deepo
Posts: 250
Joined: Sun Dec 30, 2018 8:36 pm

Help with Bluetooth and BlueZ D-Bus from C++

Fri May 03, 2019 8:53 pm

I'm trying to work with the code I found on stack overflow topic Basic BLE client with D-Bus BlueZ.

The first part of the code scans for BLE advertisement messages. It works fine, and I am able to read and decode temperature and humidity measurements from an Minew S1 Bluetooth device. So I have cut that part of the code out and left in what I can't get to work:

Code: Select all

#include <iostream>

#include <glib.h>
#include <gio/gio.h>

// sudo apt-get update
// sudo apt-get install bluez libbluetooth-dev

// Compile with:
// g++ -std=c++11 $(pkg-config --cflags glib-2.0 gobject-2.0 gio-2.0) ./bluez_dbus.cpp $(pkg-config --libs glib-2.0 gobject-2.0 gio-2.0 bluez)

// Run with:
// sudo ./a.out

// https://stackoverflow.com/questions/2896600/how-to-replace-all-occurrences-of-a-character-in-string
std::string ReplaceAll(std::string str, const std::string& from, const std::string& to)
{
    size_t start_pos = 0;
    while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
        str.replace(start_pos, from.length(), to);
        start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
    }
    return str;
}

GDBusProxy *connect(const char *addr)
{
    GError *err = nullptr;

    std::string ble_addr(addr);
    ble_addr = ReplaceAll(ble_addr, ":", "_");

    std::string objPath = ReplaceAll(std::string("/org/bluez/hci0/dev_[DEV_ADDR]"), std::string("[DEV_ADDR]"), ble_addr);
    std::cout << "Connect path: " << objPath << std::endl;

    GDBusProxy *devProxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, nullptr, "org.bluez", objPath.c_str(), "org.bluez.Device1", nullptr, &err);
    if (!devProxy) {
        std::cerr << "Device " << addr << " not available: " << err->message << " (" << err->code << ")" << std::endl;
        g_clear_error(&err);
        return nullptr;
    }
    if (g_dbus_proxy_call_sync(devProxy, "Connect", nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &err)) {
        if (!g_dbus_proxy_call_sync(devProxy, "Pair", nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &err)) {
            std::cerr << "Failed to pair: " << err->message << " (" << err->code << ")" << std::endl;
            g_clear_error(&err);
            devProxy = nullptr;
        }
    }
    else {
        std::cerr << "Failed to connect: " << err->message << " (" << err->code << ")" << std::endl;
        g_clear_error(&err);
        devProxy = nullptr;
    }
    return devProxy;
}

bool disconnect(GDBusProxy *devProxy)
{
    if (devProxy != nullptr)
    {
        GError *err = nullptr;
        if (!g_dbus_proxy_call_sync(devProxy, "Disconnect", nullptr, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &err)) {
            std::cerr << "Failed to disconnect - " << err->message << "(" << err->code << ")" << std::endl;
            g_clear_error(&err);
            return false;
        }
    }
    return true;
}

GVariant *read(const char *addr)
{
	std::string ble_addr(addr);
	ble_addr = ReplaceAll(ble_addr, ":", "_");

	std::string objPath = ReplaceAll(std::string("/org/bluez/hci0/dev_[DEV_ADDR]/service0013/char0014"), std::string("[DEV_ADDR]"), ble_addr);
	std::cout << "Read path: " << objPath << std::endl;

    GVariantBuilder *b = g_variant_builder_new(G_VARIANT_TYPE("({sv})"));
    g_variant_builder_add(b, "{sv}", "offset", g_variant_new_uint16(0));
    GVariant *args = g_variant_builder_end(b);

    GError *err = nullptr;
    GDBusProxy *charProxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, nullptr, "org.bluez", objPath.c_str(), "org.bluez.GattCharacteristic1", nullptr, &err);
    GVariant *ret = g_dbus_proxy_call_sync(charProxy, "ReadValue", args, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, &err);
    if (ret == FALSE) {
        std::cerr << "Failed to read - " << err->message << "(" << err->code << ")" << std::endl;
        g_clear_error(&err);
        return nullptr;
    }

    return ret;
}

int main()
{
    GDBusProxy *proxy = connect("AC:23:3F:A0:3B:73");
    if (proxy) {
        GVariant *ret = read("AC:23:3F:A0:3B:73");
    }
    disconnect(proxy);

    return 0;
}
I have added a few comments on what's needed to install to make it compile and how to run the code.

I know my device probably doesn't have the path in the read() function, but the code doesn't seem to be able to connect at all. So it stops long before I get to the read function.

I run it on a Raspberry Pi 3b+ running Raspbian 9 Strech.

I get this output:

Code: Select all

[email protected]:~/bluez_dbus $ sudo ./a.out
Connect path: /org/bluez/hci0/dev_AC_23_3F_A0_3B_73
Failed to connect: GDBus.Error:org.freedesktop.DBus.Error.UnknownObject: Method "Connect" with signature "" on interface "org.bluez.Device1" doesn't exist
 (41)
What am I doing wrong?

Regards
Mogens

Return to “C/C++”