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

Peripheral Support Migration Effort #351

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
87e6262
SimpleDBus Proxy objects are now linked to their interfaces (#345)
kdewald Sep 30, 2024
639fc7c
Switched to using the DBus message handling mechanism
kdewald Sep 30, 2024
8f6a6d6
Extended ObjectManager and Properties classes
kdewald Oct 2, 2024
1d06112
Interfaces now own pointers to their Proxy owners
kdewald Oct 3, 2024
c0a0891
Property updates are now routed through the Properties class
kdewald Oct 3, 2024
a1ae3ef
Avoided circular include in Proxy and Interface
kdewald Oct 3, 2024
489f00f
Split Bluez class from the ProxyRoot object
kdewald Oct 4, 2024
d719888
Renamed a few classes for convenience
kdewald Oct 4, 2024
084b342
Development checkpoint in implementation of advertising features.
kdewald Oct 6, 2024
568c0a4
All scaffolding for advertising is ready. Debugging is pending.
kdewald Oct 6, 2024
c164058
Advertising demo with manufacturer data works.
kdewald Oct 6, 2024
4d3870b
Exposed all LEAdvertisement1 properties on the CustomAdvertisement cl…
kdewald Oct 6, 2024
a68fa5a
Built the necessary scaffolding for custom services, characteristics …
kdewald Oct 10, 2024
d3a1f0f
POC of service/characteristic announcement
kdewald Oct 11, 2024
f16cfed
Very crude pathfinder that an notify.
kdewald Oct 13, 2024
ff26b97
Refactor of incoming app into better architecture.
kdewald Oct 13, 2024
5f6e57d
Added detection of incoming connections.
kdewald Oct 15, 2024
fed433f
Added handling of advertising state.
kdewald Oct 15, 2024
1cc9b46
Implemented incoming characteristic functions.
kdewald Oct 16, 2024
7bcff13
Example of pairing support
kdewald Oct 20, 2024
af8ed03
Added power on/off. Added discoverable flag.
kdewald Oct 20, 2024
57f7c6d
Rebased on main for new Message class
kdewald Oct 21, 2024
e5e1511
Removed parent dependency on Proxy events.
kdewald Oct 29, 2024
6d5527a
Removed unused dependency for Proxy
kdewald Oct 29, 2024
bd04429
Added alias property getter/setter.
kdewald Oct 29, 2024
a7f1c50
Exposed advertising instance counts, added check to ensure advertisin…
kdewald Nov 7, 2024
4bc5a19
Exposed device path during pairing. Exposed bonded property.
kdewald Nov 13, 2024
1802ce2
Exposed bonded devices
kdewald Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ include simplebluez/include/simplebluez/Characteristic.h
include simplebluez/include/simplebluez/Descriptor.h
include simplebluez/include/simplebluez/Device.h
include simplebluez/include/simplebluez/Exceptions.h
include simplebluez/include/simplebluez/ProxyOrg.h
include simplebluez/include/simplebluez/ProxyOrgBluez.h
include simplebluez/include/simplebluez/BluezOrg.h
include simplebluez/include/simplebluez/BluezOrgBluez.h
include simplebluez/include/simplebluez/Service.h
include simplebluez/include/simplebluez/Types.h
include simplebluez/include/simplebluez/interfaces/Adapter1.h
Expand All @@ -119,8 +119,8 @@ include simplebluez/src/Device.cpp
include simplebluez/src/Exceptions.cpp
include simplebluez/src/Logging.cpp
include simplebluez/src/Logging.h
include simplebluez/src/ProxyOrg.cpp
include simplebluez/src/ProxyOrgBluez.cpp
include simplebluez/src/BluezOrg.cpp
include simplebluez/src/BluezOrgBluez.cpp
include simplebluez/src/Service.cpp
include simplebluez/src/interfaces/Adapter1.cpp
include simplebluez/src/interfaces/Agent1.cpp
Expand Down
9 changes: 9 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ The format is based on `Keep a Changelog`_, and this project adheres to `Semanti
[0.8.0] - XXXX-XX-XX
--------------------

This version brings a few important changes to the project, so please read the following carefully. The two main
changes are the introduction of the Android backend and an important refactor of SimpleBluez and SimpleDBus.

From an API perspective, SimpleBLE users won't notice any changes, but SimpleBluez users must now handle the
SimpleBluez::Bluez object as a std::shared_ptr, due to the upcoming work supporting Peripheral mode on Linux.
Some of these changes might have downstream effects that are hard to predict, so make sure to test after updating
and please report any issues you find.

**Added**

- (Android) Alpha preview of Android support.
Expand All @@ -17,6 +25,7 @@ The format is based on `Keep a Changelog`_, and this project adheres to `Semanti

- Implemented standalone ByteArray class derived from `kvn::bytearray`. *(Thanks tlifschitz!)*
- **API CHANGE**: Notify and Indicate callback in C bindings now receive the peripheral handle as the first argument.
- **API CHANGE**: SimpleBluez::Bluez must now be handled as a std::shared_ptr.

**Fixed**

Expand Down
2 changes: 2 additions & 0 deletions examples/simplebluez/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ else()
find_package(simplebluez CONFIG REQUIRED)
endif()

add_subdirectory(advertise)
add_subdirectory(incoming)
add_subdirectory(list_adapters)
add_subdirectory(list_paired)
add_subdirectory(scan)
Expand Down
7 changes: 7 additions & 0 deletions examples/simplebluez/advertise/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.21)

project(EXAMPLE_ADVERTISE)

message("-- [INFO] Building Example")
add_executable(example_advertise advertise.cpp)
target_link_libraries(example_advertise simplebluez::simplebluez pthread)
72 changes: 72 additions & 0 deletions examples/simplebluez/advertise/advertise.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include <simplebluez/Bluez.h>

#include <atomic>
#include <chrono>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <thread>

std::shared_ptr<SimpleBluez::Bluez> bluez = SimpleBluez::Bluez::create();

std::atomic_bool async_thread_active = true;
void async_thread_function() {
while (async_thread_active) {
bluez->run_async();
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}

void millisecond_delay(int ms) {
for (int i = 0; i < ms; i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}

int main(int argc, char* argv[]) {
int selection = -1;

std::thread* async_thread = new std::thread(async_thread_function);

auto adapters = bluez->get_adapters();
std::cout << "The following adapters were found:" << std::endl;
for (int i = 0; i < adapters.size(); i++) {
std::cout << "[" << i << "] " << adapters[i]->identifier() << " [" << adapters[i]->address() << "]"
<< std::endl;
}

// std::cout << "Please select an adapter to advertise: ";
// std::cin >> selection;
// if (selection < 0 || selection >= adapters.size()) {
// std::cout << "Invalid selection" << std::endl;
// return 1;
// }

auto adapter = adapters[0];
std::cout << "Advertising on " << adapter->identifier() << " [" << adapter->address() << "]" << std::endl;

auto advertisement_manager = bluez->get_custom_advertisement_manager();
auto advertisement = advertisement_manager->create_advertisement("potato");

std::map<uint16_t, std::vector<uint8_t>> data;
data[0x1024] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
advertisement->manufacturer_data(data);
advertisement->timeout(180);
advertisement->local_name("SimpleBluez");

adapter->register_advertisement(advertisement);

// Sleep for a bit to allow the adapter to stop discovering.
millisecond_delay(8000);

adapter->unregister_advertisement(advertisement);

async_thread_active = false;
while (!async_thread->joinable()) {
millisecond_delay(10);
}
async_thread->join();
delete async_thread;

return 0;
}
7 changes: 3 additions & 4 deletions examples/simplebluez/ble_nus/ble_nus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
#include <iostream>
#include <thread>

SimpleBluez::Bluez bluez;
std::shared_ptr<SimpleBluez::Bluez> bluez = SimpleBluez::Bluez::create();

std::atomic_bool async_thread_active = true;
void async_thread_function() {
while (async_thread_active) {
bluez.run_async();
bluez->run_async();
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
}
Expand All @@ -37,10 +37,9 @@ std::vector<std::shared_ptr<SimpleBluez::Device>> peripherals;
int main(int argc, char* argv[]) {
int selection = -1;

bluez.init();
std::thread* async_thread = new std::thread(async_thread_function);

auto adapters = bluez.get_adapters();
auto adapters = bluez->get_adapters();
std::cout << "Available adapters:" << std::endl;
for (int i = 0; i < adapters.size(); i++) {
std::cout << "[" << i << "] " << adapters[i]->identifier() << " [" << adapters[i]->address() << "]"
Expand Down
7 changes: 3 additions & 4 deletions examples/simplebluez/connect/connect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
#include <iostream>
#include <thread>

SimpleBluez::Bluez bluez;
std::shared_ptr<SimpleBluez::Bluez> bluez = SimpleBluez::Bluez::create();

std::atomic_bool async_thread_active = true;
void async_thread_function() {
while (async_thread_active) {
bluez.run_async();
bluez->run_async();
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}
Expand All @@ -29,10 +29,9 @@ std::vector<std::shared_ptr<SimpleBluez::Device>> peripherals;
int main(int argc, char* argv[]) {
int selection = -1;

bluez.init();
std::thread* async_thread = new std::thread(async_thread_function);

auto adapters = bluez.get_adapters();
auto adapters = bluez->get_adapters();
std::cout << "Available adapters:" << std::endl;
for (int i = 0; i < adapters.size(); i++) {
std::cout << "[" << i << "] " << adapters[i]->identifier() << " [" << adapters[i]->address() << "]"
Expand Down
7 changes: 7 additions & 0 deletions examples/simplebluez/incoming/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.21)

project(EXAMPLE_INCOMING)

message("-- [INFO] Building Example")
add_executable(example_incoming incoming.cpp)
target_link_libraries(example_incoming simplebluez::simplebluez pthread)
165 changes: 165 additions & 0 deletions examples/simplebluez/incoming/incoming.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#include <simplebluez/Bluez.h>

#include <atomic>
#include <chrono>
#include <csignal>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <thread>

std::shared_ptr<SimpleBluez::Bluez> bluez = SimpleBluez::Bluez::create();

std::atomic_bool async_thread_active = true;
void async_thread_function() {
while (async_thread_active) {
bluez->run_async();
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}

std::atomic_bool app_running = true;
void signal_handler(int signal) { app_running = false; }

void millisecond_delay(int ms) {
for (int i = 0; i < ms; i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}

int main(int argc, char* argv[]) {
std::signal(SIGINT, signal_handler);
std::thread* async_thread = new std::thread(async_thread_function);
auto adapter = bluez->get_adapters()[0];

if (!adapter->powered()) {
std::cout << "Powering on adapter..." << std::endl;
adapter->powered(true);
}

std::cout << "Initializing SimpleBluez Peripheral Mode Demo" << std::endl;
auto service_manager = bluez->get_custom_service_manager();
auto advertisement_manager = bluez->get_custom_advertisement_manager();

// --- AGENT SETUP ---
auto agent = bluez->get_agent();
agent->set_capabilities(SimpleBluez::Agent::Capabilities::DisplayOnly);
bluez->register_agent();

agent->set_on_cancel([agent]() {
std::cout << "Cancel called" << std::endl;
});

agent->set_on_display_passkey([agent](const std::string& device_path, uint32_t passkey, uint16_t entered) {
std::cout << "DisplayPasskey called with passkey: " << passkey << " for device: " << device_path << std::endl;
});


// --- ADAPTER SETUP ---
std::map<std::string, std::shared_ptr<SimpleBluez::Device>> peripherals;
adapter->set_on_device_updated([&peripherals](std::shared_ptr<SimpleBluez::Device> device) {
const bool device_connected = device->connected();
const bool is_new_device = peripherals.find(device->address()) == peripherals.end();

if (device_connected && is_new_device) {
peripherals[device->address()] = device;
std::cout << "New peripheral: " << device->name() << " [" << device->address() << "]" << std::endl;

// NOTE: This moment can also be used to deregister the advertisement if only one connection is needed.
} else if (!device_connected && !is_new_device) {
peripherals.erase(device->address());
std::cout << "Lost peripheral: " << device->name() << " [" << device->address() << "]" << std::endl;
}
});

adapter->alias("Potato");

// --- SERVICE DEFINITION ---
auto service0 = service_manager->create_service();
service0->uuid("12345678-1234-5678-1234-567812345678");
service0->primary(true);

auto characteristic0 = service0->create_characteristic();
characteristic0->uuid("12345678-AAAA-5678-1234-567812345678");
characteristic0->flags({"secure-read", "secure-write", "secure-notify"});
// NOTE: Setting an initial value is not required, as this value doesn't get sent
// to the central until it attempts to read or notify.

characteristic0->set_on_read_value([characteristic0]() {
std::cout << "ReadValue called" << std::endl;
});

characteristic0->set_on_write_value([characteristic0](const SimpleBluez::ByteArray& value) {
std::cout << "WriteValue called with value: " << value.toHex() << std::endl;
});

characteristic0->set_on_notify([characteristic0](bool notify) {
std::cout << "Notify called with notify: " << notify << std::endl;
});

// Register the services and characteristics.
adapter->register_application(service_manager->path());

// NOTE: This long delay is not necessary. However, once an application is registered
// you want to wait until all services have been added to the adapter. This is done by
// checking the UUIDs property of org.bluez.Adapter1.
millisecond_delay(1000);

// --- ADVERTISEMENT DEFINITION ---

auto advertisement = advertisement_manager->create_advertisement("potato");
std::map<uint16_t, std::vector<uint8_t>> data;
data[0x1024] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
advertisement->manufacturer_data(data);
advertisement->timeout(10);
advertisement->discoverable(true);
advertisement->local_name("SimpleBluez");

// --- MAIN EVENT LOOP ---
while (app_running) {
// Handle advertising state.
if (!advertisement->active()) {
adapter->register_advertisement(advertisement);
std::cout << "Advertising on " << adapter->identifier() << " [" << adapter->address() << "]" << std::endl;

auto paired_devices = adapter->device_paired_get();
for (auto& device : paired_devices) {
std::cout << "Paired device: " << device->name() << " [" << device->address() << "]" << std::endl;
}

auto bonded_devices = adapter->device_bonded_get();
for (auto& device : bonded_devices) {
std::cout << "Bonded device: " << device->name() << " [" << device->address() << "]" << std::endl;
}
}

// TODO: Handle connection events.

// TODO: Handle data updates.
static int value = 0;
characteristic0->value({(uint8_t)(value), (uint8_t)(value + 1), (uint8_t)(value + 2)});
value = (value * 1103515245 + 12345) & 0xFFFFFF;

// This should eventually become a yield.
millisecond_delay(100);
}

// --- CLEANUP ---

for (auto& peripheral : peripherals) {
std::cout << "Disconnecting from " << peripheral.second->name() << " [" << peripheral.second->address() << "]" << std::endl;
peripheral.second->disconnect();
}

adapter->unregister_advertisement(advertisement);
adapter->unregister_application(service_manager->path());

std::cout << "Powering off adapter..." << std::endl;
adapter->powered(false);

async_thread_active = false;
async_thread->join();
delete async_thread;

return 0;
}
7 changes: 3 additions & 4 deletions examples/simplebluez/list_adapters/list_adapters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
#include <iostream>
#include <thread>

SimpleBluez::Bluez bluez;
std::shared_ptr<SimpleBluez::Bluez> bluez = SimpleBluez::Bluez::create();

std::atomic_bool async_thread_active = true;
void async_thread_function() {
while (async_thread_active) {
bluez.run_async();
bluez->run_async();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
Expand All @@ -23,10 +23,9 @@ void millisecond_delay(int ms) {
}

int main(int argc, char* argv[]) {
bluez.init();
std::thread* async_thread = new std::thread(async_thread_function);

auto adapters = bluez.get_adapters();
auto adapters = bluez->get_adapters();
std::cout << "The following adapters were found:" << std::endl;
for (int i = 0; i < adapters.size(); i++) {
std::cout << "[" << i << "] " << adapters[i]->identifier() << " [" << adapters[i]->address() << "]"
Expand Down
Loading
Loading