Skip to content
New issue

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

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

Already on GitHub? # to your account

[settings] "Make Connectable" appears to not setup blerepl #3771

Closed
bobrippling opened this issue Mar 11, 2025 · 10 comments
Closed

[settings] "Make Connectable" appears to not setup blerepl #3771

bobrippling opened this issue Mar 11, 2025 · 10 comments

Comments

@bobrippling
Copy link
Collaborator

Affected hardware version

Bangle 2

Your firmware version

2v25

The bug

If I have bluetooth off and want to use the Bluetooth menu's "Make Connectable" to enable it, this turns on bluetooth but I can't connect with the IDE or the App Loader - I'm presented with the following: No response from device. Is 'Programmable' set to 'Off'?

To resolve this, I must restart the watch (as in, load()) at which point the IDE/App Loader can connect.

It appears that the effects of setting blerepl are applied by "Make Connectable" so I'm puzzled as to why the reset is required.

To make things more interesting, attempting to reproduce this after the fact doesn't raise the bug - turning off bluetooth, resetting, then using "Make Connectable" works fine.

Installed apps

No response

@bobrippling
Copy link
Collaborator Author

@gfwilliams does this sound like anything you've seen before?

@gfwilliams
Copy link
Member

That's very strange indeed... Make Connectable should really undo everything else (and as you note it appears to).

I must restart the watch (as in, load())

How do you do that? Just hold the button for a few seconds? Because I guess you can't connect to call load()?

Would it have been just an app reload, or a full hardware reboot?

To make things more interesting, attempting to reproduce this after the fact doesn't raise the bug

So this happened once, and you haven't been able to reproduce it since? I guess there is also the possibility it was a glitch in the Bluetooth driver of the device you were connecting with?

@bobrippling
Copy link
Collaborator Author

I must restart the watch (as in, load())

How do you do that? Just hold the button for a few seconds? Because I guess you can't connect to call load()?

Would it have been just an app reload, or a full hardware reboot?

Yes exactly - the equivalent to load() I should have clarified, so an app reload

To make things more interesting, attempting to reproduce this after the fact doesn't raise the bug

So this happened once, and you haven't been able to reproduce it since? I guess there is also the possibility it was a glitch in the Bluetooth driver of the device you were connecting with?

It happens if I haven't connected in a while, but otherwise I'm unable to say why - I've tried just now and it connected as expected. Will narrow it down next it happens

@gfwilliams
Copy link
Member

Thanks - it may be a hard one to track down - but one reason you might not get a response on the BLE UART is that the Bangle is busy doing something (like compacting?) that means it can't respond... So maybe that could be it?

@bobrippling
Copy link
Collaborator Author

Bug repro

So I believe the cause might be gadgetbridge messages. The bug happened again and I got this in the web console:

Console output when bug occurs
puck.js:409 <BLE> Device Name:       Bangle.js ABCD
puck.js:409 <BLE> Device ID:         <redacted>
puck.js:409 <BLE> Connected
puck.js:409 <BLE> Got service
puck.js:409 <BLE> RX characteristic:{}
puck.js:409 <BLE> TX characteristic:{}
puck.js:409 <BLE> Sending "\u0003"
puck.js:409 <BLE> Sent
comms.js:233 <COMMS> Ctrl-C gave ""
puck.js:409 <BLE> Sending "\u0010Bluetooth.print(\"[\""
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending ");require(\"Storage\")"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending ".list(/\\.info$/).for"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "Each(f=>{var j=requi"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "re(\"Storage\").readJS"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "ON(f,1)||{};Bluetoot"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "h.print(JSON.stringi"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "fy({id:f.slice(0,-5)"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending ",version:j.version,f"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "iles:j.files,data:j."
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "data,type:j.type})+\""
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending ",\")});Bluetooth.prin"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "tln(JSON.stringify(r"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "equire(\"Storage\").ge"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "tStats?require(\"Stor"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "age\").getStats():{})"
puck.js:409 <BLE> Received packet of length 69, increasing chunk size
puck.js:409 <BLE> Received "\r\n{\"t\":\"status\",\"bat\":62,\"chg\":0}\r\n\r\n{\"t\":\"ver\",\"fw\":\"2v25\",\"hw\":2}\r\n"
puck.js:409 <BLE> Received "\r\n{\"t\":\"force_calendar_sync\",\"ids\":[]}\r\n"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "+\",\"+E.toJS([process.env.BOARD,process.env.VERSION,process.env.EXPTR,"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "process.env.MODULES,0|getTime(),E.CRC32(getSerial()+(global.NRF?NRF.g"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Sending "etAddress():0))]).substr(1))\n"
puck.js:409 <BLE> Sent
puck.js:409 <BLE> Received "["
comms.js:260 No JSON, just got: "\r"
ui.js:86 <TOAST>[error] Device connection failed, No response from device. Is 'Programmable' set to 'Off'?
puck.js:409 <BLE> Disconnected (gattserverdisconnected)

The crucial part being:

puck.js:409 <BLE> Received "["
comms.js:260 No JSON, just got: "\r"
ui.js:86 <TOAST>[error] Device connection failed, No response from device. Is 'Programmable' set to 'Off'?

However, if I attach the IDE, then attach the App Loader (to see at least the bangle's output in parallel), the IDE connection succeeds and I see this in the IDE:

>
{"t":"status","bat":61,"chg":0}

{"t":"ver","fw":"2v25","hw":2}

{"t":"force_calendar_sync","ids":[]}

Then when the App Loader connects, it (presumably) multiplexes/shares the existing connection created by the IDE, so the GB messages aren't resent, so the App Loader isn't tripped up and works.

I confirmed this by disconnecting entirely, then only connecting the App Loader, and the bug appears again.


So I suspect the GB messages are tripping up the app loader.

Attempted Remedies

I further attempted to remedy this by:

  1. Connect IDE
  2. Run load()
  3. Disconnect IDE
  4. ⚠ Connect App Loader - this fails with the same error as above

The only method that I know to work:

  1. Change the settings to BLE: enabled, Programmable: enabled
  2. Exit the settings app
  3. Let the watch do a boot-update
  4. ✅ Connect the App Loader - this succeeds. But I don't know why. Perhaps a boot-update frees up enough RAM to give the Bangle time to do a speedier connect?

@gfwilliams
Copy link
Member

Hi - thanks! So looking at the code the app loader sends, you can see it says to output [ and then list all info files and start outputting them with require("Storage").list(/\.info$/) - so I assume what happens is for some reason the scan of files takes so long that it times out waiting for a response!

Please can you try: t=getTime();require("Storage").list(/\.info$/);print(getTime()-t) and see what the result is?

I'd be interested to see how long that takes - I guess if you did a compact it would probably solve the problem but we shouldn't have to rely on that.

Right now the app loader is dependent on the Puck.js library and its default timeout. I can look at adding a change so that we can increase it, but right now the timeout appears to be 10 seconds which is quite a lot! require("Storage").list shouldn't take that long.

Actually what firmware version do you have? If it's a cutting edge one from a week or so ago please can you try upgrading? I made some changes to how characters coming over Bluetooth are handled and I know that for a few days I did have a firmware build that occasionally dropped characters - but that should be fixed now.

@bobrippling
Copy link
Collaborator Author

Sure:

>t=getTime();require("Storage").list(/\.info$/);print(getTime()-t)
0.12075805664

I don't think it's a timeout issue though - when I connect the App Loader it works fine if there's already a connection established to the watch (via another tab). If it were a timeout, we'd see the problem regardless, when the App Loader lists the files, right?

Issue example (GB messages)

I believe it's the GB messages (the initial ones) that are confusing the App Loader and can confirm this via:

  1. Connect the App Loader (unsuccessfully), observe the issue (Device connection failed, No response from device. Is 'Programmable' set to 'Off'?)

  2. Connect to the IDE, disable initial GB messages:

Found BANGLEJS2, 2v25
Connected to Web Bluetooth, Bangle.js 65f0
{"t":"status","bat":89,"chg":0}
{"t":"ver","fw":"2v25","hw":2}
{"t":"force_calendar_sync","ids":[]}
>a=require("android")
={
  gbSend: function (message) { ... },
  gbHandler: function (event) { ... },
  httpHandler: function (url,options) { ... },
  overwriteGPS: function () { ... },
  actInterval: undefined }
>a._gbSend = a.gbSend
=function (message) { ... }
>a.gbSend=()=>{}
=function () {}
Disconnected from Web Bluetooth, Bangle.js 65f0
  1. Connect the App Loader (successfully) - observe the apps are listed etc

  2. Disconnect the App Loader

  3. Connect to the IDE, enable initial GB messages:

Found BANGLEJS2, 2v25
Connected to Web Bluetooth, Bangle.js 65f0
>a.gbSend = a._gbSend
=function (message) { ... }
Disconnected from Web Bluetooth, Bangle.js 65f0
  1. Connect the App Loader (unsuccessfully), observe the issue has reappeared (Device connection failed, No response from device. Is 'Programmable' set to 'Off'?)

@gfwilliams
Copy link
Member

Thanks for tracking it down! So my guess would be that the Puck.js library Puck.write command is waiting for a newline and sends the data it receives back at that point. So it:

  • Clears its input buffer
  • Starts sending the command to get the data it wants
  • Receives Gadgetbridge messages
  • Finishes sending the command
  • Adds a handler for received data
  • receives data, and checks the buffer (which contains a newline) and returns it

So it's a tricky one. I'm not sure I can just clear the input buffer right after we've sent the last bit of the command as if the command contains newlines then it might have created output while it was being sent over.

We could use some delimiting characters like <<< and >>> around the command but then we'd have to make our own handler for getting the data back.

What I might try is to only check for a newline when one is received (so even if the input buffer contained a newline from previously received data we ignore it). Hopefully that won't break anything that's using the Puck.js lib but we'll see

@gfwilliams
Copy link
Member

I'm hoping I've fixed this now - definitely seems more reliable. In the end I added a bit of a hack to search all received data for the line that stars with [

@bobrippling
Copy link
Collaborator Author

Awesome - just tried the new app loader and it worked first time, thanks for the fix!

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

No branches or pull requests

2 participants