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

[Linux] Split BLE helper into separate class files #29722

Merged
merged 1 commit into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/platform/Linux/BLEManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
#include <platform/CHIPDeviceLayer.h>
#include <platform/CommissionableDataProvider.h>

#include "bluez/Helper.h"
#include "bluez/BluezEndpoint.h"

using namespace ::nl;
using namespace ::chip::Ble;
Expand Down
3 changes: 3 additions & 0 deletions src/platform/Linux/BLEManagerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@

#pragma once

#include <string>

#include <ble/BleLayer.h>
#include <platform/internal/BLEManager.h>

#include "bluez/BluezEndpoint.h"
#include "bluez/ChipDeviceScanner.h"
#include "bluez/Types.h"

Expand Down
6 changes: 4 additions & 2 deletions src/platform/Linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,12 @@ static_library("Linux") {
"BlePlatformConfig.h",
"bluez/AdapterIterator.cpp",
"bluez/AdapterIterator.h",
"bluez/BluezConnection.cpp",
"bluez/BluezConnection.h",
"bluez/BluezEndpoint.cpp",
"bluez/BluezEndpoint.h",
"bluez/ChipDeviceScanner.cpp",
"bluez/ChipDeviceScanner.h",
"bluez/Helper.cpp",
"bluez/Helper.h",
"bluez/Types.h",
]
}
Expand Down
3 changes: 2 additions & 1 deletion src/platform/Linux/bluez/AdapterIterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

#include <gio/gio.h>

#include "lib/core/CHIPError.h"
#include <lib/core/CHIPError.h>
#include <platform/Linux/dbus/bluez/DbusBluez.h>

#include "Types.h"

Expand Down
241 changes: 241 additions & 0 deletions src/platform/Linux/bluez/BluezConnection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "BluezConnection.h"

#include <cstring>
#include <limits>
#include <memory>

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

#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
#include <platform/ConnectivityManager.h>
#include <platform/GLibTypeDeleter.h>
#include <platform/Linux/dbus/bluez/DbusBluez.h>
#include <platform/PlatformManager.h>
#include <platform/internal/BLEManager.h>
#include <system/SystemPacketBuffer.h>

#include "BluezEndpoint.h"
#include "Types.h"

namespace chip {
namespace DeviceLayer {
namespace Internal {

static CHIP_ERROR BluezC2Indicate(BluezConnection::ConnectionDataBundle * closure)
andy31415 marked this conversation as resolved.
Show resolved Hide resolved
{
BluezConnection * conn = nullptr;
GAutoPtr<GError> error;
GIOStatus status;
const char * buf;
size_t len, written;

VerifyOrExit(closure != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));

conn = closure->mpConn;
VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
VerifyOrExit(conn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", "NULL C2"));

if (bluez_gatt_characteristic1_get_notify_acquired(conn->mpC2) == TRUE)
{
buf = (char *) g_variant_get_fixed_array(closure->mpVal, &len, sizeof(uint8_t));
VerifyOrExit(len <= static_cast<size_t>(std::numeric_limits<gssize>::max()),
ChipLogError(DeviceLayer, "FAIL: buffer too large in %s", __func__));
status = g_io_channel_write_chars(conn->mC2Channel.mpChannel, buf, static_cast<gssize>(len), &written,
&MakeUniquePointerReceiver(error).Get());
g_variant_unref(closure->mpVal);
closure->mpVal = nullptr;

VerifyOrExit(status == G_IO_STATUS_NORMAL, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", error->message));
}
else
{
bluez_gatt_characteristic1_set_value(conn->mpC2, closure->mpVal);
closure->mpVal = nullptr;
}

exit:
if (closure != nullptr)
{
g_free(closure);
}

return CHIP_NO_ERROR;
}

static BluezConnection::ConnectionDataBundle * MakeConnectionDataBundle(BLE_CONNECTION_OBJECT apConn,
const chip::System::PacketBufferHandle & apBuf)
{
auto * bundle = g_new(BluezConnection::ConnectionDataBundle, 1);
bundle->mpConn = static_cast<BluezConnection *>(apConn);
bundle->mpVal =
g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, apBuf->Start(), apBuf->DataLength() * sizeof(uint8_t), sizeof(uint8_t));
return bundle;
}

CHIP_ERROR SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
{
VerifyOrReturnError(!apBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
return PlatformMgrImpl().GLibMatterContextInvokeSync(BluezC2Indicate, MakeConnectionDataBundle(apConn, apBuf));
}

static CHIP_ERROR BluezDisconnect(BluezConnection * conn)
{
GAutoPtr<GError> error;
gboolean success;

VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "conn is NULL in %s", __func__));
VerifyOrExit(conn->mpDevice != nullptr, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", "NULL Device"));

ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, bluez_device1_get_address(conn->mpDevice));

success = bluez_device1_call_disconnect_sync(conn->mpDevice, nullptr, &MakeUniquePointerReceiver(error).Get());
VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message));

exit:
return CHIP_NO_ERROR;
}

CHIP_ERROR CloseBluezConnection(BLE_CONNECTION_OBJECT apConn)
{
return PlatformMgrImpl().GLibMatterContextInvokeSync(BluezDisconnect, static_cast<BluezConnection *>(apConn));
}

// BluezSendWriteRequest callbacks

static void SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
{
BluezGattCharacteristic1 * c1 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
GAutoPtr<GError> error;
gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c1, aResult, &MakeUniquePointerReceiver(error).Get());

VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSendWriteRequest : %s", error->message));
BLEManagerImpl::HandleWriteComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection));
}

static CHIP_ERROR SendWriteRequestImpl(BluezConnection::ConnectionDataBundle * data)
{
GVariant * options = nullptr;
GVariantBuilder optionsBuilder;

VerifyOrExit(data != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
VerifyOrExit(data->mpConn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
VerifyOrExit(data->mpConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "C1 is NULL in %s", __func__));

g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE_ARRAY);
g_variant_builder_add(&optionsBuilder, "{sv}", "type", g_variant_new_string("request"));
options = g_variant_builder_end(&optionsBuilder);

bluez_gatt_characteristic1_call_write_value(data->mpConn->mpC1, data->mpVal, options, nullptr, SendWriteRequestDone,
data->mpConn);

exit:
g_free(data);
return CHIP_NO_ERROR;
}

CHIP_ERROR BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
{
VerifyOrReturnError(!apBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
return PlatformMgrImpl().GLibMatterContextInvokeSync(SendWriteRequestImpl, MakeConnectionDataBundle(apConn, apBuf));
}

// BluezSubscribeCharacteristic callbacks

static void OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChangedProperties, const gchar * const * aInvalidatedProps,
gpointer apConnection)
{
BLE_CONNECTION_OBJECT connection = static_cast<BLE_CONNECTION_OBJECT>(apConnection);
GAutoPtr<GVariant> dataValue(g_variant_lookup_value(aChangedProperties, "Value", G_VARIANT_TYPE_BYTESTRING));
VerifyOrReturn(dataValue != nullptr);

size_t bufferLen;
auto buffer = g_variant_get_fixed_array(dataValue.get(), &bufferLen, sizeof(uint8_t));
VerifyOrReturn(buffer != nullptr, ChipLogError(DeviceLayer, "Characteristic value has unexpected type"));

BLEManagerImpl::HandleTXCharChanged(connection, static_cast<const uint8_t *>(buffer), bufferLen);
}

static void SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
{
BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
GAutoPtr<GError> error;
gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &MakeUniquePointerReceiver(error).Get());

VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSubscribeCharacteristic : %s", error->message));

BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), true);
}

static CHIP_ERROR SubscribeCharacteristicImpl(BluezConnection * connection)
{
BluezGattCharacteristic1 * c2 = nullptr;
VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));
c2 = BLUEZ_GATT_CHARACTERISTIC1(connection->mpC2);

// Get notifications on the TX characteristic change (e.g. indication is received)
g_signal_connect(c2, "g-properties-changed", G_CALLBACK(OnCharacteristicChanged), connection);
bluez_gatt_characteristic1_call_start_notify(connection->mpC2, nullptr, SubscribeCharacteristicDone, connection);

exit:
return CHIP_NO_ERROR;
}

CHIP_ERROR BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
{
return PlatformMgrImpl().GLibMatterContextInvokeSync(SubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
}

// BluezUnsubscribeCharacteristic callbacks

static void UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
{
BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
GAutoPtr<GError> error;
gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &MakeUniquePointerReceiver(error).Get());

VerifyOrReturn(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezUnsubscribeCharacteristic : %s", error->message));

// Stop listening to the TX characteristic changes
g_signal_handlers_disconnect_by_data(c2, apConnection);
BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), false);
}

static CHIP_ERROR UnsubscribeCharacteristicImpl(BluezConnection * connection)
{
VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));

bluez_gatt_characteristic1_call_stop_notify(connection->mpC2, nullptr, UnsubscribeCharacteristicDone, connection);

exit:
return CHIP_NO_ERROR;
}

CHIP_ERROR BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
{
return PlatformMgrImpl().GLibMatterContextInvokeSync(UnsubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
}

} // namespace Internal
} // namespace DeviceLayer
} // namespace chip
79 changes: 79 additions & 0 deletions src/platform/Linux/bluez/BluezConnection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <stdint.h>

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

#include <lib/core/CHIPError.h>
#include <platform/GLibTypeDeleter.h>
#include <platform/Linux/dbus/bluez/DbusBluez.h>
#include <system/SystemPacketBuffer.h>

namespace chip {
namespace DeviceLayer {
namespace Internal {

struct BluezEndpoint;

struct BluezConnection
{

struct IOChannel
{
GIOChannel * mpChannel;
GSource * mWatchSource;
};

struct ConnectionDataBundle
{
BluezConnection * mpConn;
GVariant * mpVal;
};

char * mpPeerAddress;
BluezDevice1 * mpDevice;
BluezGattService1 * mpService;
BluezGattCharacteristic1 * mpC1;
BluezGattCharacteristic1 * mpC2;
// additional data characteristics
BluezGattCharacteristic1 * mpC3;

bool mIsNotify;
uint16_t mMtu;
struct IOChannel mC1Channel;
struct IOChannel mC2Channel;
BluezEndpoint * mpEndpoint;
};

CHIP_ERROR SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf);
CHIP_ERROR CloseBluezConnection(BLE_CONNECTION_OBJECT apConn);

/// Write to the CHIP RX characteristic on the remote peripheral device
CHIP_ERROR BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf);
/// Subscribe to the CHIP TX characteristic on the remote peripheral device
CHIP_ERROR BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn);
/// Unsubscribe from the CHIP TX characteristic on the remote peripheral device
CHIP_ERROR BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn);

} // namespace Internal
} // namespace DeviceLayer
} // namespace chip
Loading
Loading