blob: 6e17b916c073d6165aa4efd561dc44eb977ba0a8 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* Copyright (c) 2018 Nest Labs, Inc.
*
* 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.
*/
/**
* @file
* Provides an implementation of the BLEManager singleton object
* for Tizen platforms.
*/
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <ble/CHIPBleServiceData.h>
#include <platform/internal/BLEManager.h>
#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
#include "MainLoop.h"
#include <bluetooth.h>
using namespace ::chip;
using namespace ::chip::Ble;
namespace chip {
namespace DeviceLayer {
namespace Internal {
BLEManagerImpl BLEManagerImpl::sInstance;
struct BLEConnection
{
char * peerAddr;
uint16_t mtu;
bool subscribed;
void * gattCharC1Handle;
void * gattCharC2Handle;
bool isChipDevice;
};
/* CHIPoBLE UUID strings */
const char * chip_ble_service_uuid = "0000FFF6-0000-1000-8000-00805F9B34FB";
const char * chip_ble_char_c1_tx_uuid = "18EE2EF5-263D-4559-959F-4F9C429F9D11";
const char * chip_ble_char_c2_rx_uuid = "18EE2EF5-263D-4559-959F-4F9C429F9D12";
/* CCCD */
const char * desc_uuid_short = "2902";
const char * chip_ble_service_uuid_short = "FFF6";
const int BtpServiceDataLenMax =
7; // OpCode(1) + Discriminator(2) + VendorId(2) + ProductId(2), 5.2.3.8.6. Advertising Data, CHIP Specification
static void __AdapterStateChangedCb(int result, bt_adapter_state_e adapterState, void * userData)
{
ChipLogProgress(DeviceLayer, "Adapter State Changed: %s", adapterState == BT_ADAPTER_ENABLED ? "Enabled" : "Disabled");
}
void BLEManagerImpl::GattConnectionStateChangedCb(int result, bool connected, const char * remoteAddress, void * userData)
{
ChipLogProgress(DeviceLayer, "Gatt Connection State Changed: %s result [%d]", connected ? "Connected" : "Disconnected", result);
sInstance.HandleConnectionEvent(connected, remoteAddress);
}
gboolean BLEManagerImpl::_BleInitialize(void * userData)
{
int ret;
if (sInstance.mFlags.Has(Flags::kTizenBLELayerInitialized))
{
ChipLogProgress(DeviceLayer, "BLE Already Initialized");
return true;
}
ret = bt_initialize();
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_initialize() failed. ret: %d", ret));
ret = bt_adapter_set_state_changed_cb(__AdapterStateChangedCb, NULL);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_adapter_set_state_changed_cb() failed. ret: %d", ret));
ret = bt_gatt_server_initialize();
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_server_initialize() failed. ret: %d", ret));
ret = bt_gatt_set_connection_state_changed_cb(GattConnectionStateChangedCb, NULL);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_adapter_set_state_changed_cb() failed. ret: %d", ret));
sInstance.InitConnectionData();
sInstance.mFlags.Set(Flags::kTizenBLELayerInitialized);
ChipLogProgress(DeviceLayer, "BLE Initialized");
return true;
exit:
return false;
}
static int __GetAttInfo(bt_gatt_h gattHandle, char ** uuid, int * type)
{
int ret;
ret = bt_gatt_get_type(gattHandle, (bt_gatt_type_e *) type);
VerifyOrReturnError(ret == BT_ERROR_NONE, ret);
return bt_gatt_get_uuid(gattHandle, uuid);
}
static const char * __ConvertAttTypeToStr(int type)
{
switch (type)
{
case BT_GATT_TYPE_SERVICE:
return "Service";
case BT_GATT_TYPE_CHARACTERISTIC:
return "Characteristic";
case BT_GATT_TYPE_DESCRIPTOR:
return "Descriptor";
default:
return NULL;
}
}
static void __ReadValueRequestedCb(const char * remoteAddress, int requestId, bt_gatt_server_h server, bt_gatt_h gattHandle,
int offset, void * userData)
{
int ret, len = 0, type = 0;
char *value = NULL, *uuid = NULL;
__GetAttInfo(gattHandle, &uuid, &type);
ChipLogProgress(DeviceLayer, "Read Requested on %s(%s)", __ConvertAttTypeToStr(type), uuid);
g_free(uuid);
ret = bt_gatt_get_value(gattHandle, &value, &len);
VerifyOrReturn(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_get_value() failed. ret: %d", ret));
ChipLogProgress(DeviceLayer, "Read Value: %s(len: %d)", value, len);
ret = bt_gatt_server_send_response(requestId, BT_GATT_REQUEST_TYPE_READ, offset, 0x00, value, len);
g_free(value);
VerifyOrReturn(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_server_send_response() failed. ret: %d", ret));
}
void BLEManagerImpl::WriteValueRequestedCb(const char * remoteAddress, int requestId, bt_gatt_server_h server, bt_gatt_h gattHandle,
bool responseNeeded, int offset, const char * value, int len, void * userData)
{
int ret, type = 0;
char * uuid = NULL;
BLEConnection * conn = nullptr;
conn = (BLEConnection *) g_hash_table_lookup(sInstance.mConnectionMap, remoteAddress);
VerifyOrReturn(conn != nullptr, ChipLogError(DeviceLayer, "Failed to find connection info"));
VerifyOrReturn(__GetAttInfo(gattHandle, &uuid, &type) == BT_ERROR_NONE,
ChipLogError(DeviceLayer, "Failed to fetch GATT Attribute from GATT handle"));
ChipLogProgress(DeviceLayer, "Write Requested on %s(%s)", __ConvertAttTypeToStr(type), uuid);
ChipLogProgress(DeviceLayer, "Write Value: %s(len: %d)", value, len);
g_free(uuid);
ret = bt_gatt_set_value(gattHandle, value, len);
VerifyOrReturn(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_set_value() failed. ret: %d", ret));
ret = bt_gatt_server_send_response(requestId, BT_GATT_REQUEST_TYPE_WRITE, offset, 0x00, NULL, 0);
VerifyOrReturn(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_server_send_response() failed. ret: %d", ret));
sInstance.HandleC1CharWriteEvent(conn, (const uint8_t *) value, len);
}
void BLEManagerImpl::NotificationStateChangedCb(bool notify, bt_gatt_server_h server, bt_gatt_h gattHandle, void * userData)
{
int type = 0;
char * uuid = NULL;
BLEConnection * conn = nullptr;
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init(&iter, sInstance.mConnectionMap);
while (g_hash_table_iter_next(&iter, &key, &value))
{
/* NOTE: Currently Tizen Platform API does not return remote device address, which enables/disables
* notification/Indication. Therefore, returning first Connection */
conn = (BLEConnection *) value;
break;
}
VerifyOrReturn(conn != nullptr, ChipLogError(DeviceLayer, "Failed to find connection info"));
VerifyOrReturn(__GetAttInfo(gattHandle, &uuid, &type) == BT_ERROR_NONE,
ChipLogError(DeviceLayer, "Failed to fetch GATT Attribute from GATT handle"));
ChipLogProgress(DeviceLayer, "Notification State Changed %d on %s(%s)", notify, __ConvertAttTypeToStr(type), uuid);
g_free(uuid);
sInstance.NotifyBLESubscribed(notify ? true : false, conn);
}
void BLEManagerImpl::IndicationConfirmationCb(int result, const char * remoteAddress, bt_gatt_server_h server,
bt_gatt_h characteristic, bool completed, void * userData)
{
BLEConnection * conn = nullptr;
VerifyOrReturn(result == BT_ERROR_NONE, ChipLogError(DeviceLayer, "Failed to Get Indication Confirmation"));
conn = (BLEConnection *) g_hash_table_lookup(sInstance.mConnectionMap, remoteAddress);
VerifyOrReturn(conn != nullptr, ChipLogError(DeviceLayer, "Could not find connection for [%s]", remoteAddress));
VerifyOrReturn(sInstance.mGattCharC2Handle == characteristic,
ChipLogError(DeviceLayer, "Gatt characteristic handle did not match"));
sInstance.NotifyBLEIndicationConfirmation(conn);
}
void BLEManagerImpl::AdvertisingStateChangedCb(int result, bt_advertiser_h advertiser, bt_adapter_le_advertising_state_e advState,
void * userData)
{
ChipLogProgress(DeviceLayer, "Advertising %s", advState == BT_ADAPTER_LE_ADVERTISING_STARTED ? "Started" : "Stopped");
if (advState == BT_ADAPTER_LE_ADVERTISING_STARTED)
{
sInstance.mFlags.Set(Flags::kAdvertising);
sInstance.NotifyBLEPeripheralAdvStartComplete(true, nullptr);
}
else
{
sInstance.mFlags.Clear(Flags::kAdvertising);
sInstance.NotifyBLEPeripheralAdvStopComplete(true, nullptr);
}
if (sInstance.mFlags.Has(Flags::kAdvertisingRefreshNeeded))
{
sInstance.mFlags.Clear(Flags::kAdvertisingRefreshNeeded);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
}
sInstance.mAdvReqInProgress = false;
}
// ====== Private Functions.
void BLEManagerImpl::NotifyBLEPeripheralGATTServerRegisterComplete(bool aIsSuccess, void * apAppstate)
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kPlatformTizenBLEPeripheralGATTServerRegisterComplete;
event.Platform.BLEPeripheralGATTServerRegisterComplete.mIsSuccess = aIsSuccess;
event.Platform.BLEPeripheralGATTServerRegisterComplete.mpAppstate = apAppstate;
PlatformMgr().PostEventOrDie(&event);
}
void BLEManagerImpl::NotifyBLEPeripheralAdvConfiguredComplete(bool aIsSuccess, void * apAppstate)
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kPlatformTizenBLEPeripheralAdvConfiguredComplete;
event.Platform.BLEPeripheralAdvConfiguredComplete.mIsSuccess = aIsSuccess;
event.Platform.BLEPeripheralAdvConfiguredComplete.mpAppstate = apAppstate;
PlatformMgr().PostEventOrDie(&event);
}
void BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(bool aIsSuccess, void * apAppstate)
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kPlatformTizenBLEPeripheralAdvStartComplete;
event.Platform.BLEPeripheralAdvStartComplete.mIsSuccess = aIsSuccess;
event.Platform.BLEPeripheralAdvStartComplete.mpAppstate = apAppstate;
PlatformMgr().PostEventOrDie(&event);
}
void BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(bool aIsSuccess, void * apAppstate)
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kPlatformTizenBLEPeripheralAdvStopComplete;
event.Platform.BLEPeripheralAdvStopComplete.mIsSuccess = aIsSuccess;
event.Platform.BLEPeripheralAdvStopComplete.mpAppstate = apAppstate;
PlatformMgr().PostEventOrDie(&event);
}
void BLEManagerImpl::NotifyBLEWriteReceived(System::PacketBufferHandle & buf, BLE_CONNECTION_OBJECT conId)
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kCHIPoBLEWriteReceived;
event.CHIPoBLEWriteReceived.ConId = conId;
event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease();
PlatformMgr().PostEventOrDie(&event);
}
void BLEManagerImpl::NotifyBLESubscribed(bool indicationsEnabled, BLE_CONNECTION_OBJECT conId)
{
ChipDeviceEvent event;
event.Type = (indicationsEnabled) ? DeviceEventType::kCHIPoBLESubscribe : DeviceEventType::kCHIPoBLEUnsubscribe;
event.CHIPoBLESubscribe.ConId = conId;
PlatformMgr().PostEventOrDie(&event);
}
void BLEManagerImpl::NotifyBLEIndicationConfirmation(BLE_CONNECTION_OBJECT conId)
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm;
event.CHIPoBLEIndicateConfirm.ConId = conId;
PlatformMgr().PostEventOrDie(&event);
}
void BLEManagerImpl::NotifyBLEConnectionEstablished(BLE_CONNECTION_OBJECT conId, CHIP_ERROR error)
{
ChipDeviceEvent connectionEvent;
connectionEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished;
PlatformMgr().PostEventOrDie(&connectionEvent);
}
void BLEManagerImpl::NotifyBLEDisconnection(BLE_CONNECTION_OBJECT conId, CHIP_ERROR error)
{
ChipDeviceEvent event;
event.Type = DeviceEventType::kCHIPoBLEConnectionError;
event.CHIPoBLEConnectionError.ConId = conId;
event.CHIPoBLEConnectionError.Reason = error;
PlatformMgr().PostEventOrDie(&event);
}
int BLEManagerImpl::RegisterGATTServer()
{
int ret = BT_ERROR_NONE;
bt_gatt_server_h server = NULL;
bt_gatt_h service = NULL;
bt_gatt_h char1 = NULL, char2 = NULL;
bt_gatt_h desc = NULL;
char desc_value[2] = { 0, 0 };
ChipLogProgress(DeviceLayer, "Start GATT Service Registration");
// Create Server
ret = bt_gatt_server_create(&server);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_server_create() failed. ret: %d", ret));
// Create Service (BTP Service)
ret = bt_gatt_service_create(chip_ble_service_uuid, BT_GATT_SERVICE_TYPE_PRIMARY, &service);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_service_create() failed. ret: %d", ret));
// Create 1st Characteristic (Client TX Buffer)
ret = bt_gatt_characteristic_create(
chip_ble_char_c1_tx_uuid, BT_GATT_PERMISSION_WRITE,
BT_GATT_PROPERTY_WRITE, // Write Request is not coming if we use WITHOUT_RESPONSE property. Let's use WRITE property and
// consider to use WITHOUT_RESPONSE property in the future according to the CHIP Spec 4.16.3.2. BTP
// GATT Service
"CHIPoBLE_C1", strlen("CHIPoBLE_C1"), &char1);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_characteristic_create() failed. ret: %d", ret));
ret = bt_gatt_server_set_write_value_requested_cb(char1, WriteValueRequestedCb, NULL);
VerifyOrExit(ret == BT_ERROR_NONE,
ChipLogError(DeviceLayer, "bt_gatt_server_set_write_value_requested_cb() failed. ret: %d", ret));
ret = bt_gatt_service_add_characteristic(service, char1);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_service_add_characteristic() failed. ret: %d", ret));
// Create 2nd Characteristic (Client RX Buffer)
ret = bt_gatt_characteristic_create(chip_ble_char_c2_rx_uuid, BT_GATT_PERMISSION_READ,
BT_GATT_PROPERTY_READ | BT_GATT_PROPERTY_INDICATE, "CHIPoBLE_C2", strlen("CHIPoBLE_C2"),
&char2);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_characteristic_create() failed. ret: %d", ret));
ret = bt_gatt_server_set_read_value_requested_cb(char2, __ReadValueRequestedCb, NULL);
VerifyOrExit(ret == BT_ERROR_NONE,
ChipLogError(DeviceLayer, "bt_gatt_server_set_read_value_requested_cb() failed. ret: %d", ret));
ret = bt_gatt_server_set_characteristic_notification_state_change_cb(char2, NotificationStateChangedCb, NULL);
VerifyOrExit(
ret == BT_ERROR_NONE,
ChipLogError(DeviceLayer, "bt_gatt_server_set_characteristic_notification_state_change_cb() failed. ret: %d", ret));
// Create CCC Descriptor
ret = bt_gatt_descriptor_create(desc_uuid_short, BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE, desc_value,
sizeof(desc_value), &desc);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_descriptor_create() failed. ret: %d", ret));
ret = bt_gatt_characteristic_add_descriptor(char2, desc);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_characteristic_add_descriptor() failed. ret: %d", ret));
ret = bt_gatt_service_add_characteristic(service, char2);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_service_add_characteristic() failed. ret: %d", ret));
// Register Service to Server
ret = bt_gatt_server_register_service(server, service);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_server_register_service() failed. ret: %d", ret));
// Start Server
ret = bt_gatt_server_start();
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_server_start() failed. ret: %d", ret));
ChipLogDetail(DeviceLayer, "NotifyBLEPeripheralGATTServerRegisterComplete Success");
BLEManagerImpl::NotifyBLEPeripheralGATTServerRegisterComplete(true, nullptr);
// Save the Local Peripheral char1 & char2 handles
mGattCharC1Handle = char1;
mGattCharC2Handle = char2;
return ret;
exit:
ChipLogDetail(DeviceLayer, "NotifyBLEPeripheralGATTServerRegisterComplete Failed");
BLEManagerImpl::NotifyBLEPeripheralGATTServerRegisterComplete(false, nullptr);
return ret;
}
int BLEManagerImpl::StartAdvertising()
{
int ret = BT_ERROR_NONE;
CHIP_ERROR err = CHIP_NO_ERROR;
char service_data[BtpServiceDataLenMax] = {
0x0,
}; // need to fill advertising data. 5.2.3.8.6. Advertising Data, CHIP Specification
ChipBLEDeviceIdentificationInfo deviceIdInfo = {
0x0,
};
if (sInstance.mAdvReqInProgress)
{
ChipLogProgress(DeviceLayer, "Advertising Request In Progress");
return ret;
}
ChipLogProgress(DeviceLayer, "Start Advertising");
if (mAdvertiser == NULL)
{
ret = bt_adapter_le_create_advertiser(&mAdvertiser);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_adapter_le_create_advertiser() failed. ret: %d", ret));
}
else
{
ret = bt_adapter_le_clear_advertising_data(mAdvertiser, BT_ADAPTER_LE_PACKET_ADVERTISING);
VerifyOrExit(ret == BT_ERROR_NONE,
ChipLogError(DeviceLayer, "bt_adapter_le_clear_advertising_data() failed. ret: %d", ret));
ret = bt_adapter_le_clear_advertising_data(mAdvertiser, BT_ADAPTER_LE_PACKET_SCAN_RESPONSE);
VerifyOrExit(ret == BT_ERROR_NONE,
ChipLogError(DeviceLayer, "bt_adapter_le_clear_advertising_data() failed. ret: %d", ret));
}
if (mFlags.Has(Flags::kFastAdvertisingEnabled))
{
ret = bt_adapter_le_set_advertising_mode(mAdvertiser, BT_ADAPTER_LE_ADVERTISING_MODE_LOW_LATENCY);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_adapter_le_set_advertising_mode() failed. ret: %d", ret));
// NOTE: Check specification for recommended Advertising Interval range for Fast Advertising
// ret = bt_adapter_le_set_advertising_interval(mAdvertiser, BT_LE_ADV_INTERVAL_MIN, BT_LE_ADV_INTERVAL_MIN);
}
else
{
// NOTE: Check specification for recommended Advertising Interval range for Slow Advertising
// ret = bt_adapter_le_set_advertising_interval(mAdvertiser, BT_LE_ADV_INTERVAL_MAX, BT_LE_ADV_INTERVAL_MAX);
}
err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo);
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "GetBLEDeviceIdentificationInfo() failed. %s", ErrorStr(err)));
memcpy(service_data, &deviceIdInfo, sizeof(service_data));
ret = bt_adapter_le_add_advertising_service_data(mAdvertiser, BT_ADAPTER_LE_PACKET_ADVERTISING, chip_ble_service_uuid_short,
service_data, sizeof(service_data));
VerifyOrExit(ret == BT_ERROR_NONE,
ChipLogError(DeviceLayer, "bt_adapter_le_add_advertising_service_data() failed. ret: %d", ret));
BLEManagerImpl::NotifyBLEPeripheralAdvConfiguredComplete(true, nullptr);
ret = bt_adapter_le_start_advertising_new(mAdvertiser, AdvertisingStateChangedCb, NULL);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_adapter_le_start_advertising_new() failed. ret: %d", ret));
sInstance.mAdvReqInProgress = true;
return ret;
exit:
BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(false, nullptr);
return ret;
}
int BLEManagerImpl::StopAdvertising()
{
int ret = BT_ERROR_NONE;
ChipLogProgress(DeviceLayer, "Stop Advertising");
ret = bt_adapter_le_stop_advertising(mAdvertiser);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_adapter_le_stop_advertising() failed. ret: %d", ret));
sInstance.mAdvReqInProgress = true;
return ret;
exit:
BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(false, nullptr);
return ret;
}
void BLEManagerImpl::InitConnectionData(void)
{
/* Initialize Hashmap */
if (!mConnectionMap)
{
mConnectionMap = g_hash_table_new(g_str_hash, g_str_equal);
ChipLogProgress(DeviceLayer, "GATT Connection HashMap created");
}
}
void BLEManagerImpl::AddConnectionData(const char * remoteAddr)
{
BLEConnection * conn;
ChipLogProgress(DeviceLayer, "AddConnectionData for [%s]", remoteAddr);
if (!g_hash_table_lookup(mConnectionMap, remoteAddr))
{
ChipLogProgress(DeviceLayer, "Not Found in Map");
conn = (BLEConnection *) g_malloc0(sizeof(BLEConnection));
conn->peerAddr = g_strdup(remoteAddr);
g_hash_table_insert(mConnectionMap, (gpointer) conn->peerAddr, conn);
ChipLogProgress(DeviceLayer, "New Connection Added for [%s]", remoteAddr);
}
}
void BLEManagerImpl::RemoveConnectionData(const char * remoteAddr)
{
BLEConnection * conn = nullptr;
conn = (BLEConnection *) g_hash_table_lookup(mConnectionMap, remoteAddr);
if (!conn)
return;
g_hash_table_remove(mConnectionMap, remoteAddr);
g_free(conn->peerAddr);
g_free(conn);
ChipLogProgress(DeviceLayer, "Connection Removed for [%s]", remoteAddr);
}
void BLEManagerImpl::HandleC1CharWriteEvent(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len)
{
CHIP_ERROR err = CHIP_NO_ERROR;
System::PacketBufferHandle buf;
ChipLogProgress(DeviceLayer, "Write request received for CHIPoBLE Client TX characteristic (data len %u)", len);
// Copy the data to a packet buffer.
buf = System::PacketBufferHandle::NewWithData(value, len);
VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
NotifyBLEWriteReceived(buf, conId);
return;
exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "HandleC1CharWriteEvent() failed: %s", ErrorStr(err));
}
}
void BLEManagerImpl::HandleConnectionEvent(bool connected, const char * remoteAddress)
{
if (connected)
{
ChipLogProgress(DeviceLayer, "Device Connected [%s]", remoteAddress);
AddConnectionData(remoteAddress);
}
else
{
BLEConnection * conn = nullptr;
ChipLogProgress(DeviceLayer, "Device DisConnected [%s]", remoteAddress);
conn = (BLEConnection *) g_hash_table_lookup(mConnectionMap, remoteAddress);
/* Tizen Platform does not return GATT disconnection reason, hence fallback to default */
NotifyBLEDisconnection(conn, BLE_ERROR_REMOTE_DEVICE_DISCONNECTED);
RemoveConnectionData(remoteAddress);
}
}
void BLEManagerImpl::DriveBLEState()
{
int ret = BT_ERROR_NONE;
ChipLogProgress(DeviceLayer, "Enter DriveBLEState");
if (!mIsCentral && mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && !mFlags.Has(Flags::kAppRegistered))
{
ret = RegisterGATTServer();
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "Register GATT Server Failed. ret: %d", ret));
ChipLogProgress(DeviceLayer, "GATT Service Registered");
mFlags.Set(Flags::kAppRegistered);
ExitNow();
}
if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kAdvertisingEnabled))
{
if (!mFlags.Has(Flags::kAdvertising))
{
ret = StartAdvertising();
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "Start Advertising Failed. ret: %d", ret));
}
else if (mFlags.Has(Flags::kAdvertisingRefreshNeeded))
{
ChipLogProgress(DeviceLayer, "Advertising Refreshed Needed. Stop Advertising");
ret = StopAdvertising();
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "Stop Advertising Failed. ret: %d", ret));
}
}
else if (mFlags.Has(Flags::kAdvertising))
{
ChipLogProgress(DeviceLayer, "Stop Advertising");
ret = StopAdvertising();
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "Stop Advertising Failed. ret: %d", ret));
ret = bt_adapter_le_destroy_advertiser(mAdvertiser);
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_adapter_le_destroy_advertiser() failed. ret: %d", ret));
mAdvertiser = NULL;
}
exit:
if (ret != BT_ERROR_NONE)
{
mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
}
}
void BLEManagerImpl::DriveBLEState(intptr_t arg)
{
sInstance.DriveBLEState();
}
CHIP_ERROR BLEManagerImpl::_Init(void)
{
CHIP_ERROR err;
bool ret;
err = BleLayer::Init(this, this, this, &DeviceLayer::SystemLayer());
SuccessOrExit(err);
mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
ChipLogProgress(DeviceLayer, "Initialize BLE");
ret = MainLoop::Instance().Init(_BleInitialize);
VerifyOrExit(ret != false, err = CHIP_ERROR_INTERNAL);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
exit:
return err;
}
CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val)
{
CHIP_ERROR err = CHIP_NO_ERROR;
VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrExit(mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
if (val != mServiceMode)
{
mServiceMode = val;
PlatformMgr().ScheduleWork(DriveBLEState, 0);
}
exit:
return err;
}
CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
{
mFlags.Set(Flags::kAdvertisingEnabled, val);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
return CHIP_NO_ERROR;
}
CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode)
{
switch (mode)
{
case BLEAdvertisingMode::kFastAdvertising:
mFlags.Set(Flags::kFastAdvertisingEnabled, true);
break;
case BLEAdvertisingMode::kSlowAdvertising:
mFlags.Set(Flags::kFastAdvertisingEnabled, false);
break;
default:
return CHIP_ERROR_INVALID_ARGUMENT;
}
mFlags.Set(Flags::kAdvertisingRefreshNeeded);
PlatformMgr().ScheduleWork(DriveBLEState, 0);
return CHIP_NO_ERROR;
}
CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize)
{
CHIP_ERROR err = CHIP_NO_ERROR;
int ret;
char * deviceName = NULL;
VerifyOrExit(buf != NULL, err = CHIP_ERROR_INVALID_ARGUMENT);
ret = bt_adapter_get_name(&deviceName);
if (ret != BT_ERROR_NONE)
{
ChipLogError(DeviceLayer, "bt_adapter_get_name() failed. ret: %d", ret);
return CHIP_ERROR_INTERNAL;
}
VerifyOrExit(deviceName != NULL, err = CHIP_ERROR_INTERNAL);
VerifyOrExit(strlen(deviceName) >= bufSize, err = CHIP_ERROR_BUFFER_TOO_SMALL);
g_strlcpy(buf, deviceName, bufSize);
ChipLogProgress(DeviceLayer, "DeviceName: %s", buf);
exit:
return err;
}
CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName)
{
CHIP_ERROR err = CHIP_NO_ERROR;
int ret;
VerifyOrExit(deviceName != NULL, err = CHIP_ERROR_INVALID_ARGUMENT);
ret = bt_adapter_set_name(deviceName);
if (ret != BT_ERROR_NONE)
{
ChipLogError(DeviceLayer, "bt_adapter_set_name() failed. ret: %d", ret);
return CHIP_ERROR_INTERNAL;
}
exit:
return err;
}
uint16_t BLEManagerImpl::_NumConnections(void)
{
return 0;
}
CHIP_ERROR BLEManagerImpl::ConfigureBle(uint32_t aAdapterId, bool aIsCentral)
{
mAdapterId = aAdapterId;
mIsCentral = aIsCentral;
return CHIP_NO_ERROR;
}
void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEvent)
{
ChipLogDetail(DeviceLayer, "HandlePlatformSpecificBLEEvent %d", apEvent->Type);
// TODO: Need to implement Tizen Platform Specific events: CHIPDevicePlatformEvent
}
void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
{
ChipBleUUID service_uuid;
ChipBleUUID char_notification_uuid;
ChipBleUUID char_write_uuid;
switch (event->Type)
{
case DeviceEventType::kCHIPoBLESubscribe:
ChipLogProgress(DeviceLayer, "CHIPoBLESubscribe");
StringToUUID(chip_ble_service_uuid, service_uuid);
StringToUUID(chip_ble_char_c2_rx_uuid, char_notification_uuid);
HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &service_uuid, &char_notification_uuid);
NotifyBLEConnectionEstablished(event->CHIPoBLESubscribe.ConId, CHIP_NO_ERROR);
break;
case DeviceEventType::kCHIPoBLEUnsubscribe:
ChipLogProgress(DeviceLayer, "CHIPoBLEUnsubscribe");
StringToUUID(chip_ble_service_uuid, service_uuid);
StringToUUID(chip_ble_char_c2_rx_uuid, char_notification_uuid);
HandleUnsubscribeReceived(event->CHIPoBLESubscribe.ConId, &service_uuid, &char_notification_uuid);
break;
case DeviceEventType::kCHIPoBLEWriteReceived:
ChipLogProgress(DeviceLayer, "CHIPoBLEWriteReceived");
StringToUUID(chip_ble_service_uuid, service_uuid);
StringToUUID(chip_ble_char_c1_tx_uuid, char_write_uuid);
HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &service_uuid, &char_write_uuid,
PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data));
break;
case DeviceEventType::kCHIPoBLEIndicateConfirm:
ChipLogProgress(DeviceLayer, "CHIPoBLEIndicateConfirm");
StringToUUID(chip_ble_service_uuid, service_uuid);
StringToUUID(chip_ble_char_c2_rx_uuid, char_notification_uuid);
HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &service_uuid, &char_notification_uuid);
break;
case DeviceEventType::kCHIPoBLEConnectionError:
ChipLogProgress(DeviceLayer, "CHIPoBLEConnectionError");
HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason);
break;
case DeviceEventType::kFabricMembershipChange:
case DeviceEventType::kServiceProvisioningChange:
case DeviceEventType::kAccountPairingChange:
break;
default:
HandlePlatformSpecificBLEEvent(event);
break;
}
}
uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const
{
return false;
}
bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
return false;
}
bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
{
return false;
}
bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId)
{
return false;
}
bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
chip::System::PacketBufferHandle pBuf)
{
int ret = BT_ERROR_NONE;
BLEConnection * conn = nullptr;
ChipLogProgress(DeviceLayer, "SendIndication");
conn = (BLEConnection *) g_hash_table_lookup(sInstance.mConnectionMap, ((BLEConnection *) conId)->peerAddr);
VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "Failed to find connection info"));
ret = bt_gatt_set_value(mGattCharC2Handle, (const char *) pBuf->Start(), pBuf->DataLength());
VerifyOrExit(ret == BT_ERROR_NONE, ChipLogError(DeviceLayer, "bt_gatt_set_value() failed. ret: %d", ret));
ChipLogProgress(DeviceLayer, "Sending indication for CHIPoBLE RX characteristic (con %s, len %u)", conn->peerAddr,
pBuf->DataLength());
ret = bt_gatt_server_notify_characteristic_changed_value(mGattCharC2Handle, IndicationConfirmationCb, conn->peerAddr, NULL);
VerifyOrExit(ret == BT_ERROR_NONE,
ChipLogError(DeviceLayer, "bt_gatt_server_notify_characteristic_changed_value() failed. ret: %d", ret));
return true;
exit:
return false;
}
bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
chip::System::PacketBufferHandle pBuf)
{
return false;
}
bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
chip::System::PacketBufferHandle pBuf)
{
return false;
}
bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext,
const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId)
{
return false;
}
void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) {}
void BLEManagerImpl::NewConnection(BleLayer * bleLayer, void * appState, const uint16_t connDiscriminator) {}
CHIP_ERROR BLEManagerImpl::CancelConnection()
{
return CHIP_ERROR_NOT_IMPLEMENTED;
}
} // namespace Internal
} // namespace DeviceLayer
} // namespace chip
#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE