-
Notifications
You must be signed in to change notification settings - Fork 98
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
It's impossible using Bluejay with some other libraries #119
Comments
I like the idea of providing flexibility. A total black box isn't always ideal. But I am not sure how best to expose the CBPeripheral and CBCentralManager references so that we don't encourage less experienced developers to use them, nor easily allow them to stumble upon those. Thoughts @nbrooke or @larryonoff? |
I'm not sure if it's possible to support two libraries actually sharing the same CBCentralManager even in theory. Since there is only a single delegate on CBCentralManager and you need to install the delegate to do anything useful, letting one library do anything will necessarily damage the state of the other one. You'd need to essentially shut down one while using the other. Just doing that yourself in the app (Having two CBCentralManagers) would be one option, but I imagine it would be useful to be able to do some work with he more convenient API of Bluejay (connect to the peripheral, check firmware version before you start the update) and then pass off the connected peripheral to the other library when you are ready to get started. What we COULD potentially do to allow that without too much complexity or danger is to provide a way to start a Bluejay instance with an existing CBCentralManager (and connected CBPeripheral) and a way to do a purposeful "non-clean" shutdown that resets all internal state, but does not disconnect and returns rather then deallocating the active CBCentralManager and CBPeripheral . So usage would look something like this (lots of spread between different functions and async behaviour elided for clarity):
I don't think that either of the new "stopAndExtractState" (should probably have a better name) or the alternative form of "start" are particularly hard to implement, and I think would enable what you are trying to do without exposing internal state in a way that could be misused via attempting to actually use the CB objects at the same time Bluejay is. |
I like the idea. I think that API may look in the following way
|
There's one more idea. Considering Bluejay as a framework that connects to CoreBluetooth, like
|
I'm not wild about either of those alternate approaches. Like I said at the outset, i don't think it's possible to share the manager object between libraries that have any internal state at all safely. If you ever change the delegate while there are in flight operations, then callbacks will not get delivered to the library that is expecting them, or callbacks that the library is not expecting will get delivered, and once that has happened the internal state is damaged. This is particularly bad for Bluejay because it's whole metaphor is trying to impose reliability by being VERY specific about the queuing of operations so we (try to) never end up in a state we don't understand, allowing swapping of it's CBCentralManger delegate without cleaning all internal state is very likely to fail in cases where there is any operation in progress either when you start or stop. I think both these proposed tweaks with the Thinking about it more, I would actually argue that if we REALLY wanted to be safe:
|
I'm probably going to have the same issue, the nordic library, to start a firmware update, requests the |
Having those exposed would definitely be enough to implement this sort of thing, and yes, Bluejay does not have much significant state if there are no objects in the queue (thought there is some, the fact that the peripheral is connected is a bit of implicit state that could be invalidated in a scenario like this) So when there aren't any object in the queue, you definitely could just swap the delegate pointers and then put them back later. The reason I'd prefer the more heavyweight style of interface with explicit stop and start calls as discussed above is that just exposing those pointers in general could open up lots of API surface for potential mistakes (swapping the delegates when the queue is NOT empty, making other calls on those objects that would cause callbacks when Bluejay isn't expecting them, etc.) I think a stop call that returns the current objects and a start call that takes the objects provides an interface that let's people use the library in this way, without introducing any potential dangers. We (Steamclock) will definitely make this change when we have some time to work on some non-essential features, but because it's not something we need for any of our projects, I don't want to promise any particular timeline. A pull request that implemented this along the lines of the stop and restart model would definitely be appreciated, if anyone else is willing to give it a shot. |
thank you @nbrooke , I've forked the project and I already made some changes. Now I'm modifying the sample project, to test if it working correctly. When it will be done I will tell you and maybe I can make a pull request. |
We created a fork of Bluejay after some testing I can tell you that is working pretty fine along with nordic DFU, you can connect to a device and if an update is needed you can pass the peripheral and the manager to nordic library. After the update is completed you can give back those to BlueJay. |
That change looks good to me. I don't know if we would want to take the change to the sample code (that's a lot of complexity added to the sample code for something that is a more advanced feature, might make more sense to have a separate test project for demoing this or something), but the change to Bluejay itself looks great. @jeremychiang Let's get this merged in next time you are doing Bluejay updates. |
awesome. I'm really grateful that you integrated this feature |
* Add the stop and extract API, #119 * Bump version to 0.6.0
Implemented. |
I apologize if this is the wrong location to ask my question, but I wanted to quote @DrAma999 's efforts. Please guide me to the correct location if this is incorrect. I am attempting to do the same Nordic DFU flow. I have got it all working except for cleanly handing control back from CB to Bluejay. Bluejay reports that it has started when I give it the CBCentralManager reference only, but once I attempt my first operation back with Bluejay I get "Queue is paused because CBCentralManager is not ready yet". Is there any checking or flushing that needs to be done to CB before handing it back to Bluejay? Would @DrAma999 be willing to share a snippet of their sample code displaying the success of restarting Bluejay after the DFU operation? Thank you |
@MetalManipulator I might have an idea of what the problem is. @DrAma999's use case might be Bluejay first, then Nordic, then back to Bluejay. Yours might be Nordic first, then back to Bluejay. The bug might be that if you don't start with a Bluejay instance first, then the Bluejay queue won't get started. The queue is usually started by listening to The fix might look like:
|
@jeremychiang I apologize if it wasn't clear before. I actually am starting with Bluejay, moving to Nordic, and then back to Bluejay. The Nordic framework finishes by disconnecting from the device, so I am trying to restart Bluejay with just the previous CBCentralManager reference I got when I stopped Bluejay before and not providing a CBPeripheral since I'm not connected. I will look further into your suggestion above though to see if I can get the queue going. Thank you. |
There is bug, I couldn't discover it because for our business requirements I needed to reinstate another instance of bluejay after updating the firmware.
I don't know if they also changed something in the Nordic library that could cause some other issues. |
@DrAma999 Thank you for your insight. I will proceed accordingly. |
Bluejay does the right thing and incapsulates CoreBluetooth classes. But in my case I have to use DFU library, https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library that requires direct access to CBCentralManager and CBPeripheral. As result I had to get rid of all Bluejay super-features and implement manually a part of work that Bluejay does perfectly.
Maybe it would be reasonable to expose some CoreBluetooth classes at developers risk? So it would be some-kind of Force Unwrap in Swift?
The text was updated successfully, but these errors were encountered: