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

Correcting connection issue #37

Merged
merged 4 commits into from
Jun 12, 2018

Conversation

sylvchev
Copy link
Contributor

@sylvchev sylvchev commented Apr 26, 2018

I found that my Muse headband could not connect directly after a night charging up. I should start the Muse app on my phone, connect the band and then I could use muse-lsl. This happens each time that I fully charge my headband with a phone charger. I did some tests with different chargers and in different places, this does not happen in certain configurations, but I could not get the bottom of it. Nonetheless, it systematically happens in the building where I need the headband, hence this PR.

I activated the developer mode on my android Phone to "Enable Bluetooth HCI snoop log" and I analyzed the exchanges with Wireshark between the Muse phone app and the headband (when it could not connect). I found out that the Muse app sends an ask_device_info sequence (0x03 76 31 0a) and that, in its response, the 'ap' field of the headband is set to 'bootloader' (instead of 'headset' in a functional headband). When the headband is in 'bootloader' mode, the Muse app sends a special sequence that I identified as a "reset to headset mode" order (0x03 2a 31 0a, or *1 in ASCII). The headband then reboots, cutting the Bluetooth connection. Once reconnected, the ask_device_info returns now the correct 'headset' value in the 'ap' field.

I also spotted that, after "resetting", the headband preset mode is indicated as "32" which seems to map to preset 20 from the official documentation. The Muse app then change the preset to 21, with the sequence `0x04 70 32 31 0a, which is also documented here.

I proposed the following update in this PR:

  • adding the function select_preset to set the preset to indicated value (default is 21)
  • adding a 'keep alive' function, documented here. It is not used in this PR, but it could be useful later.
  • the main change is in the connect function: I send a reset order, wait for 2 sec, reconnect, then change the preset. The 2 second delay could be shortened, it is 5 second on the Muse app. Compared to the main branch, and assuming a headband already working well with muse-lsl, this adds a small inconvenience as the muse-lsl take 2 more seconds before starting to stream. But then again, it could be cut to half a second or less without taking any risk. The fact that the Muse headband is reset at each connection does not seem to have any effect.
  • before opening this PR, I made a PEP8 check and corrected most of it. Unfortunately, this made the changes in the PR less visible. Sorry for that, won't make the same mistake next time.

Instead of making a reset at each connection, a better approach could be to use an internal callback responding to ask_device_info and to triggers the reset depending on the 'ap' field value. Unfortunately, with the concurrent programming, I did not find a correct way to do that.

@alexandrebarachant
Copy link
Owner

Thanks a lot !
This is a great PR.

@hubertjb can you review and merge if this work ?

@hubertjb
Copy link
Collaborator

Awesome work @sylvchev :)

@alexandrebarachant yes, I'll take a look asap

@@ -70,6 +71,11 @@ def connect(self, interface=None, backend='auto'):
self.address = address
self.device = self.adapter.connect(self.address)

self.ask_reset()
Copy link
Collaborator

@jdpigeon jdpigeon Jun 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of having it reset everytime, just wrap this code block in a try catch.

For example:

        try:
            self.device = self.adapter.connect(self.address)
            # subscribes to EEG stream
            if self.enable_eeg:
                self._subscribe_eeg()

            if self.enable_control:
                self._subscribe_control()

            if self.enable_telemetry:
                self._subscribe_telemetry()

            if self.enable_acc:
                self._subscribe_acc()

            if self.enable_gyro:
                self._subscribe_gyro()

        except pygatt.exceptions.BLEError as error:
            if("characteristic" in str(error)):
                self.ask_reset()
                sleep(2)
                self.device = self.adapter.connect(self.address)
                self.select_preset(preset=21)

                # subscribes to EEG stream
                if self.enable_eeg:
                    self._subscribe_eeg()

                if self.enable_control:
                    self._subscribe_control()

                if self.enable_telemetry:
                    self._subscribe_telemetry()

                if self.enable_acc:
                    self._subscribe_acc()

                if self.enable_gyro:
                    self._subscribe_gyro()

Copy link
Collaborator

@jdpigeon jdpigeon Jun 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree doing an ask_device_info callback would be the best way to handle this bootloader mode issue. However, @sylvchev's right in that it's kind of tricky to do that kind of async/await logic in Python

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, I have currently no access to a Muse band. I could not test your solution but it seems a better solution than to reset everytime.
@alexandrebarachant, @hubertjb, if you agree, I'll update my PR with the code proposed by @jdpigeon.

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

Successfully merging this pull request may close these issues.

None yet

4 participants