-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Python based device scanning interfacing with native C++ code on linux. #4960
Python based device scanning interfacing with native C++ code on linux. #4960
Conversation
Moved Bluez mainloop into a separate class Moved blezl iterators into separate files Added ble generic initialization and handle management Switched bluez to use the newly developed scanner main loop.
This comment has been minimized.
This comment has been minimized.
Factor common code in the two function.connectedhomeip/src/platform/Linux/bluez/Helper.cpp Lines 904 to 914 in 67b1525
This comment was generated by todo based on a
|
g_free(mBluezMainLoop); | ||
mBluezMainLoop = nullptr; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cleanup logic looks suspicious. err will always equal CHIP_NO_ERROR, so this block can never execute. But if it was to execute, shouldn't the pthread also be cleaned up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed - I did not notice no error was ever set; thank you for catching.
|
||
private: | ||
ChipDeviceScanner::Ptr mScanner; | ||
PyObject * mContext; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PyObject * const mContext ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated. Made me not be able to set it to nullptr in destructor (I was trying too set everything to null to catch any odd reference errors while debugging what turned out to be python void* cast issues).
|
||
~ScannerDelegateImpl() | ||
{ | ||
mContext = nullptr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose of assigning in the dtor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debugging invalid memory references. Turned out to be python c_void_p behavind oddly (it casts to 32-bit if it can, but when passing back it stays 32-bit int and does a sign extension or invalid high order bits when sent as a function argument ... very frustrating)
{ | ||
if (manager == nullptr) | ||
{ | ||
ChipLogError(DeviceLayer, "Manager is NULL in %s", __func__); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be an assert (manager != nullptr) ?
In general, I don't think "internal pointer is null" is ever an appropriate log message (except perhaps when debugging locally).
We should instead log something that describes the cause of the pointer being null, or not get into here in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just moved this code (copied and pasted as is). Agree it would require some more passes, but I am afraid of going to deep if trying to update everything. The PR is already huge.
namespace Internal { | ||
namespace { | ||
|
||
struct GObjectUnref |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use this in other cases where we're manually calling g_object_unref?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually I assume yes. I think it should be pulled out more globally as we change this code more.
I wonder though how much we will still touch it: I wanted to have scanning and this PR has it. The only additonal thing we may want is BLE connection by address instead of discriminator.
BluezObjectsCleanup(endpoint); | ||
if (!MainLoop::Instance().SetCleanupFunction(BluezObjectsCleanup, endpoint)) | ||
{ | ||
ChipLogError(DeviceLayer, "Failed to schedule cleanup function"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't this an assert?
Printing a message when things go badly off the rails isn't going to catch issues quickly and reliably (e.g., cause our tests to fail).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may require additional passes: as it stands, we do not seem to ever stop the main loop, so I kept the cleanup function because cleanup existed in previous code, however this really does not get called in the current code structure.
…to be very useful
… library handle pointers to not use c_void_p directly. This looks stable on my linux machine (ran >100 scans)
} | ||
|
||
private: | ||
std::unique_ptr<ChipDeviceScanner> mScanner; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: const
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cannot do this because scanner is moved post object creation and I have a SetScanner method.
This is a side-effect of creation order: delegate needs to access the scanner, but scanner needs a delegate.
Problem
Native C++ device scanning is not implemented nor accessible from python, which does not allow us to verify/script the parsing of discovered devices.
Current discovery is done natively by Android and iOS platforms and a pure python version. However connectivity itself is done by C++ native code which would only be exercised on connect and never on discovery.
Summary of Changes
This is a merge of several branches developed while the bluez code split was under review. It contains:
Example usage: