diff --git a/config/mbed/CMakeLists.txt b/config/mbed/CMakeLists.txt index c2b57fb892e633..d95f7f6d66fbd8 100644 --- a/config/mbed/CMakeLists.txt +++ b/config/mbed/CMakeLists.txt @@ -121,6 +121,10 @@ list(APPEND CHIP_CFLAGS_C ${CMAKE_C_FLAGS_INIT}) mbed_get_lang_compile_flags(CHIP_CFLAGS_CC mbed-core CXX) list(APPEND CHIP_CFLAGS_CC ${CMAKE_CXX_FLAGS_INIT}) +# Add support for Mbed BLE +mbed_get_target_common_compile_flags(CHIP_MBEDBLE_CFLAGS mbed-ble) +list(APPEND CHIP_CFLAGS ${CHIP_MBEDBLE_CFLAGS}) + # Add support for Mbed event mbed_get_target_common_compile_flags(CHIP_MBEDEVENTS_CFLAGS mbed-events) list(APPEND CHIP_CFLAGS ${CHIP_MBEDEVENTS_CFLAGS}) diff --git a/examples/shell/mbed/CMakeLists.txt b/examples/shell/mbed/CMakeLists.txt index cb690a48166d49..0a6168c57bfad2 100644 --- a/examples/shell/mbed/CMakeLists.txt +++ b/examples/shell/mbed/CMakeLists.txt @@ -54,7 +54,13 @@ if("wifi_ism43362" IN_LIST MBED_TARGET_LABELS) ) endif() -target_link_libraries(${APP_TARGET} mbed-os mbed-events mbed-netsocket mbed-storage mbed-storage-kv-global-api mbed-mbedtls mbed-mbedtls-cryptocell310 chip) +if("BlueNRG_MS" IN_LIST MBED_TARGET_LABELS) + target_link_libraries(${APP_TARGET} + mbed-ble-blue_nrg + ) +endif() + +target_link_libraries(${APP_TARGET} mbed-os mbed-ble mbed-events mbed-netsocket mbed-storage mbed-storage-kv-global-api mbed-mbedtls mbed-mbedtls-cryptocell310 chip) mbed_set_post_build(${APP_TARGET}) diff --git a/examples/shell/mbed/mbed_app.json b/examples/shell/mbed/mbed_app.json index b41da2a22a4f5f..5254ca5357bb51 100644 --- a/examples/shell/mbed/mbed_app.json +++ b/examples/shell/mbed/mbed_app.json @@ -1,22 +1,22 @@ { "macros" : [ - "MBEDTLS_USER_CONFIG_FILE=\"chip_mbedtls_config.h\"", - "MBED_CONF_LWIP_IPV6_ENABLED=1", - "MBED_CONF_LWIP_RAW_SOCKET_ENABLED=1", - "MBED_CONF_ISM43362_PROVIDE_DEFAULT=1" + "MBEDTLS_USER_CONFIG_FILE=\"chip_mbedtls_config.h\"" ], "target_overrides": { "*": { "lwip.ipv6-enabled": true, - "lwip.raw-socket-enabled": true + "lwip.raw-socket-enabled": true, + "platform.stdio-baud-rate": 115200 }, "DISCO_L475VG_IOT01A": { "lwip.ipv6-enabled": true, "lwip.raw-socket-enabled": true, - "target.components_add": ["wifi_ism43362"], + "target.components_add": ["wifi_ism43362", "BlueNRG_MS"], "ism43362.provide-default": true, "target.network-default-interface-type": "WIFI", - "target.macros_add" : ["MBEDTLS_SHA1_C"] + "target.macros_add" : ["MBEDTLS_SHA1_C"], + "target.features_add": ["BLE"], + "target.extra_labels_add": ["CORDIO"] } } } \ No newline at end of file diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index a032d1d185a900..965e716eee8b6a 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -534,14 +534,16 @@ if (chip_device_platform != "none" && chip_device_platform != "external") { } } else if (chip_device_platform == "mbed") { sources += [ + "mbed/BLEManagerImpl.cpp", + "mbed/BLEManagerImpl.h", "mbed/ConfigurationManagerImpl.cpp", - "mbed/SystemTimeSupport.cpp", - "mbed/PlatformManagerImpl.cpp", "mbed/ConnectivityManagerImpl.cpp", "mbed/ConnectivityManagerImpl.h", "mbed/DeviceNetworkProvisioningDelegateImpl.cpp", "mbed/DeviceNetworkProvisioningDelegateImpl.h", - "mbed/MbedConfig.cpp" + "mbed/MbedConfig.cpp", + "mbed/PlatformManagerImpl.cpp", + "mbed/SystemTimeSupport.cpp", ] } diff --git a/src/platform/mbed/BLEManagerImpl.cpp b/src/platform/mbed/BLEManagerImpl.cpp new file mode 100644 index 00000000000000..63a9c0fb942f66 --- /dev/null +++ b/src/platform/mbed/BLEManagerImpl.cpp @@ -0,0 +1,966 @@ +/* + * + * Copyright (c) 2020-2021 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. + */ + +/** + * @file + * Provides an implementation of the BLEManager singleton object + * for mbed platforms. + */ + +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +#include + +#include +#include +#include +#include + +// Show BLE status with LEDs +#define _BLEMGRIMPL_USE_LEDS 0 + +/* Undefine the BLE_ERROR_NOT_IMPLEMENTED macro provided by CHIP's + * src/ble/BleError.h to avoid a name conflict with Mbed-OS ble_error_t + * enum value. For the enum values, see: + * mbed-os/connectivity/FEATURE_BLE/include/ble/common/blecommon.h + */ +#undef BLE_ERROR_NOT_IMPLEMENTED +// mbed-os headers +#include "ble/BLE.h" +#include "ble/Gap.h" +#include "platform/Callback.h" +#include "platform/NonCopyable.h" +#include "platform/Span.h" + +#if _BLEMGRIMPL_USE_LEDS +#include "drivers/DigitalOut.h" +#endif + +using namespace ::chip; +using namespace ::chip::Ble; +using namespace ::chip::System; + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +namespace { +const UUID ShortUUID_CHIPoBLEService(0xFEAF); +// RX = BleLayer::CHIP_BLE_CHAR_1_ID +const UUID LongUUID_CHIPoBLEChar_RX("18EE2EF5-263D-4559-959F-4F9C429F9D11"); +const ChipBleUUID ChipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x11 } }; +// TX = BleLayer::CHIP_BLE_CHAR_2_ID +const UUID LongUUID_CHIPoBLEChar_TX("18EE2EF5-263D-4559-959F-4F9C429F9D12"); +const ChipBleUUID ChipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x12 } }; +} // namespace + +#if _BLEMGRIMPL_USE_LEDS +#include "drivers/DigitalOut.h" +// LED1 -- toggle on every call to ble::BLE::processEvents() +// LED2 -- on when ble::BLE::init() callback completes +// LED3 -- on when advertising +mbed::DigitalOut led1(LED1, 1); +mbed::DigitalOut led2(LED2, 1); +mbed::DigitalOut led3(LED3, 1); +#endif + +struct ConnectionInfo +{ + struct ConnStatus + { + ble::connection_handle_t connHandle; + uint16_t attMtuSize; + }; + + ConnectionInfo() + { + for (size_t i = 0; i < kMaxConnections; i++) + { + mConnStates[i].connHandle = kInvalidHandle; + mConnStates[i].attMtuSize = 0; + } + } + + CHIP_ERROR setStatus(ble::connection_handle_t conn_handle, uint16_t mtu_size) + { + size_t new_i = kMaxConnections; + for (size_t i = 0; i < kMaxConnections; i++) + { + if (mConnStates[i].connHandle == conn_handle) + { + mConnStates[i].attMtuSize = mtu_size; + return CHIP_NO_ERROR; + } + else if (mConnStates[i].connHandle == kInvalidHandle && i < new_i) + { + new_i = i; + } + } + // Handle not found, has to be added. + if (new_i == kMaxConnections) + { + return CHIP_ERROR_NO_MEMORY; + } + mConnStates[new_i].connHandle = conn_handle; + mConnStates[new_i].attMtuSize = mtu_size; + return CHIP_NO_ERROR; + } + + CHIP_ERROR clearStatus(ble::connection_handle_t conn_handle) + { + for (size_t i = 0; i < kMaxConnections; i++) + { + if (mConnStates[i].connHandle == conn_handle) + { + mConnStates[i].connHandle = kInvalidHandle; + mConnStates[i].attMtuSize = 0; + return CHIP_NO_ERROR; + } + } + return CHIP_ERROR_INVALID_ARGUMENT; + } + + ConnStatus getStatus(ble::connection_handle_t conn_handle) const + { + for (size_t i = 0; i < kMaxConnections; i++) + { + if (mConnStates[i].connHandle == conn_handle) + { + return mConnStates[i]; + } + } + return { kInvalidHandle, 0 }; + } + + uint16_t getMTU(ble::connection_handle_t conn_handle) const { return getStatus(conn_handle).attMtuSize; } + +private: + const int kMaxConnections = BLE_LAYER_NUM_BLE_ENDPOINTS; + ConnStatus mConnStates[BLE_LAYER_NUM_BLE_ENDPOINTS]; + const ble::connection_handle_t kInvalidHandle = 0xf00d; +}; + +static ConnectionInfo sConnectionInfo; + +class GapEventHandler : private mbed::NonCopyable, public ble::Gap::EventHandler +{ + void onScanRequestReceived(const ble::ScanRequestEvent & event) + { + // Requires enable action from setScanRequestNotification(true). + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + /* Called when advertising starts. + */ + void onAdvertisingStart(const ble::AdvertisingStartEvent & event) + { +#if _BLEMGRIMPL_USE_LEDS + led3 = 0; +#endif + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + + BLEManagerImpl & ble_manager = BLEMgrImpl(); + SetFlag(ble_manager.mFlags, ble_manager.kFlag_Advertising); + ClearFlag(ble_manager.mFlags, ble_manager.kFlag_AdvertisingRefreshNeeded); + + // Post a CHIPoBLEAdvertisingChange(Started) event. + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + chip_event.CHIPoBLEAdvertisingChange.Result = kActivity_Started; + PlatformMgrImpl().PostEvent(&chip_event); + + PlatformMgr().ScheduleWork(ble_manager.DriveBLEState, 0); + } + + /* Called when advertising ends. + * + * Advertising ends when the process timeout or if it is stopped by the + * application or if the local device accepts a connection request. + */ + void onAdvertisingEnd(const ble::AdvertisingEndEvent & event) + { +#if _BLEMGRIMPL_USE_LEDS + led3 = 1; +#endif + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + + BLEManagerImpl & ble_manager = BLEMgrImpl(); + ClearFlag(ble_manager.mFlags, ble_manager.kFlag_Advertising); + + // Post a CHIPoBLEAdvertisingChange(Stopped) event. + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + chip_event.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; + PlatformMgrImpl().PostEvent(&chip_event); + + if (event.isConnected()) + { + SetFlag(ble_manager.mFlags, ble_manager.kFlag_AdvertisingRefreshNeeded); + ChipLogDetail(DeviceLayer, "Restarting advertising to allow more connections."); + } + PlatformMgr().ScheduleWork(ble_manager.DriveBLEState, 0); + } + + /* Called when connection attempt ends or an advertising device has been + * connected. + */ + void onConnectionComplete(const ble::ConnectionCompleteEvent & event) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + + ble_error_t mbed_err = event.getStatus(); + BLEManagerImpl & ble_manager = BLEMgrImpl(); + + if (mbed_err == BLE_ERROR_NONE) + { + const ble::address_t & peer_addr = event.getPeerAddress(); + ChipLogProgress(DeviceLayer, "BLE connection established with %02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX", peer_addr[5], + peer_addr[4], peer_addr[3], peer_addr[2], peer_addr[1], peer_addr[0]); + ble_manager.mGAPConns++; + CHIP_ERROR err = sConnectionInfo.setStatus(event.getConnectionHandle(), BLE_GATT_MTU_SIZE_DEFAULT); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Unable to store connection status, error: %s ", ErrorStr(err)); + } + } + else + { + ChipLogError(DeviceLayer, "BLE connection failed, mbed-os error: %d", mbed_err); + } + ChipLogProgress(DeviceLayer, "Current number of connections: %" PRIu16 "/%d", ble_manager.NumConnections(), + ble_manager.kMaxConnections); + + // The connection established event is propagated when the client has subscribed to + // the TX characteristic. + } + + void onUpdateConnectionParametersRequest(const ble::UpdateConnectionParametersRequestEvent & event) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + void onConnectionParametersUpdateComplete(const ble::ConnectionParametersUpdateCompleteEvent & event) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + void onReadPhy(ble_error_t status, ble::connection_handle_t connectionHandle, ble::phy_t txPhy, ble::phy_t rxPhy) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + void onPhyUpdateComplete(ble_error_t status, ble::connection_handle_t connectionHandle, ble::phy_t txPhy, ble::phy_t rxPhy) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + /* Called when a connection has been disconnected. + */ + void onDisconnectionComplete(const ble::DisconnectionCompleteEvent & event) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + + const ble::disconnection_reason_t & reason = event.getReason(); + BLEManagerImpl & ble_manager = BLEMgrImpl(); + + if (ble_manager.NumConnections()) + { + ble_manager.mGAPConns--; + } + CHIP_ERROR err = sConnectionInfo.clearStatus(event.getConnectionHandle()); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Unable to clear connection status, error: %s ", ErrorStr(err)); + } + + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEConnectionError; + chip_event.CHIPoBLEConnectionError.ConId = event.getConnectionHandle(); + switch (reason.value()) + { + case ble::disconnection_reason_t::REMOTE_USER_TERMINATED_CONNECTION: + chip_event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; + break; + case ble::disconnection_reason_t::LOCAL_HOST_TERMINATED_CONNECTION: + chip_event.CHIPoBLEConnectionError.Reason = BLE_ERROR_APP_CLOSED_CONNECTION; + break; + default: + chip_event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; + break; + } + PlatformMgrImpl().PostEvent(&chip_event); + + ChipLogProgress(DeviceLayer, "BLE connection terminated, mbed-os reason: %d", reason.value()); + ChipLogProgress(DeviceLayer, "Current number of connections: %" PRIu16 "/%d", ble_manager.NumConnections(), + ble_manager.kMaxConnections); + + // Force a reconfiguration of advertising in case we switched to non-connectable mode when + // the BLE connection was established. + SetFlag(ble_manager.mFlags, ble_manager.kFlag_AdvertisingRefreshNeeded); + PlatformMgr().ScheduleWork(ble_manager.DriveBLEState, 0); + } + + void onDataLengthChange(ble::connection_handle_t connectionHandle, uint16_t txSize, uint16_t rxSize) + { + ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); + } + + void onPrivacyEnabled() { ChipLogDetail(DeviceLayer, "GAP %s", __FUNCTION__); } +}; + +struct CHIPService : public ble::GattServer::EventHandler +{ + CHIPService() {} + CHIPService(const CHIPService &) = delete; + CHIPService & operator=(const CHIPService &) = delete; + + CHIP_ERROR init(ble::BLE & ble_interface) + { + ChipLogDetail(DeviceLayer, "GATT %s", __FUNCTION__); + + if (mCHIPoBLEChar_RX != nullptr || mCHIPoBLEChar_TX != nullptr) + { + return CHIP_NO_ERROR; + } + + mCHIPoBLEChar_RX = new GattCharacteristic(LongUUID_CHIPoBLEChar_RX, nullptr, 0, BLE_GATT_MTU_SIZE_DEFAULT, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE); + + mCHIPoBLEChar_TX = new GattCharacteristic(LongUUID_CHIPoBLEChar_TX, nullptr, 0, BLE_GATT_MTU_SIZE_DEFAULT, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); + + // Setup callback + mCHIPoBLEChar_RX->setWriteAuthorizationCallback(this, &CHIPService::onWriteAuth); + + GattCharacteristic * chipoble_gatt_characteristics[] = { mCHIPoBLEChar_RX, mCHIPoBLEChar_TX }; + auto num_characteristics = sizeof chipoble_gatt_characteristics / sizeof chipoble_gatt_characteristics[0]; + GattService chipoble_gatt_service(ShortUUID_CHIPoBLEService, chipoble_gatt_characteristics, num_characteristics); + + auto mbed_err = ble_interface.gattServer().addService(chipoble_gatt_service); + if (mbed_err != BLE_ERROR_NONE) + { + ChipLogError(DeviceLayer, "Unable to add GATT service, mbed-os err: %d", mbed_err); + return CHIP_ERROR_INTERNAL; + } + + // Store the attribute handles in the class so they are reused in + // callbacks to discriminate events. + mRxHandle = mCHIPoBLEChar_RX->getValueHandle(); + mTxHandle = mCHIPoBLEChar_TX->getValueHandle(); + // There is a single descriptor in the characteristic, CCCD is at index 0 + mTxCCCDHandle = mCHIPoBLEChar_TX->getDescriptor(0)->getHandle(); + ChipLogDetail(DeviceLayer, "char handles: rx=%d, tx=%d, cccd=%d", mRxHandle, mTxHandle, mTxCCCDHandle); + + ble_interface.gattServer().setEventHandler(this); + return CHIP_NO_ERROR; + } + + // Write authorization callback + void onWriteAuth(GattWriteAuthCallbackParams * params) + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params->connHandle, params->handle); + if (params->handle == mRxHandle) + { + ChipLogDetail(DeviceLayer, "Received BLE packet on RX"); + + // Allocate a buffer, copy the data. They will be passed into the event + auto buf = System::PacketBufferHandle::NewWithData(params->data, params->len); + if (buf.IsNull()) + { + params->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_REQUEST_REJECTED; + ChipLogError(DeviceLayer, "Dropping packet, not enough memory"); + return; + } + + params->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS; + + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEWriteReceived; + chip_event.CHIPoBLEWriteReceived.ConId = params->connHandle; + chip_event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease(); + PlatformMgrImpl().PostEvent(&chip_event); + } + else + { + params->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_HANDLE; + } + } + + // overrides of GattServerEvent Handler + void onAttMtuChange(ble::connection_handle_t connectionHandle, uint16_t attMtuSize) override + { + ChipLogDetail(DeviceLayer, "GATT %s", __FUNCTION__); + CHIP_ERROR err = sConnectionInfo.setStatus(connectionHandle, attMtuSize); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Unable to store connection status, error: %s ", ErrorStr(err)); + } + } + + void onDataSent(const GattDataSentCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle); + } + + void onDataWritten(const GattWriteCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.handle); + } + + void onDataRead(const GattReadCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.handle); + } + + void onShutdown(const ble::GattServer & server) override { ChipLogDetail(DeviceLayer, "GATT %s", __FUNCTION__); } + + void onUpdatesEnabled(const GattUpdatesEnabledCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle); + if (params.attHandle == mTxCCCDHandle) + { + ChipLogDetail(DeviceLayer, "Updates enabled on TX CCCD"); + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLESubscribe; + chip_event.CHIPoBLESubscribe.ConId = params.connHandle; + PlatformMgrImpl().PostEvent(&chip_event); + } + } + + void onUpdatesDisabled(const GattUpdatesDisabledCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle); + if (params.attHandle == mTxCCCDHandle) + { + ChipLogDetail(DeviceLayer, "Updates disabled on TX CCCD"); + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEUnsubscribe; + chip_event.CHIPoBLEUnsubscribe.ConId = params.connHandle; + PlatformMgrImpl().PostEvent(&chip_event); + } + } + + void onConfirmationReceived(const GattConfirmationReceivedCallbackParams & params) override + { + ChipLogDetail(DeviceLayer, "GATT %s, connHandle=%d, attHandle=%d", __FUNCTION__, params.connHandle, params.attHandle); + if (params.attHandle == mTxHandle) + { + ChipLogDetail(DeviceLayer, "Confirmation received for TX transfer"); + ChipDeviceEvent chip_event; + chip_event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm; + chip_event.CHIPoBLEIndicateConfirm.ConId = params.connHandle; + PlatformMgrImpl().PostEvent(&chip_event); + } + } + + const ble::attribute_handle_t getTxHandle() const { return mTxHandle; } + const ble::attribute_handle_t getTxCCCDHandle() const { return mTxCCCDHandle; } + const ble::attribute_handle_t getRxHandle() const { return mRxHandle; } + + GattCharacteristic * mCHIPoBLEChar_RX = nullptr; + GattCharacteristic * mCHIPoBLEChar_TX = nullptr; + ble::attribute_handle_t mRxHandle = 0; + ble::attribute_handle_t mTxCCCDHandle = 0; + ble::attribute_handle_t mTxHandle = 0; +}; + +BLEManagerImpl BLEManagerImpl::sInstance; +static GapEventHandler sMbedGapEventHandler; +static CHIPService sCHIPService; + +/* Initialize the mbed-os BLE subsystem. Register the BLE event processing + * callback to the system event queue. Register the BLE initialization complete + * callback that handles the rest of the setup commands. Register the BLE GAP + * event handler. + */ +CHIP_ERROR BLEManagerImpl::_Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ble_error_t mbed_err = BLE_ERROR_NONE; + + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + mFlags = CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART ? kFlag_AdvertisingEnabled : 0; + mGAPConns = 0; + + ble::BLE & ble_interface = ble::BLE::Instance(); + + ble_interface.gap().setEventHandler(&sMbedGapEventHandler); + err = sCHIPService.init(ble_interface); + SuccessOrExit(err); + + ble_interface.onEventsToProcess(FunctionPointerWithContext{ + [](ble::BLE::OnEventsToProcessCallbackContext * context) { PlatformMgr().ScheduleWork(DoBLEProcessing, 0); } }); + + mbed_err = ble_interface.init([](ble::BLE::InitializationCompleteCallbackContext * context) { + BLEMgrImpl().HandleInitComplete(context->error == BLE_ERROR_NONE); + }); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + +exit: + return err; +} + +/* Process all the events from the mbed-os BLE subsystem. + */ +void BLEManagerImpl::DoBLEProcessing(intptr_t arg) +{ +#if _BLEMGRIMPL_USE_LEDS + led1 = !led1; +#endif + ble::BLE::Instance().processEvents(); +} + +/* This is the mbed-os BLE subsystem init complete callback. Initialize the + * BLELayer and update the state based on the flags. + */ +void BLEManagerImpl::HandleInitComplete(bool no_error) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(no_error, err = CHIP_ERROR_INTERNAL); + + err = BleLayer::Init(this, this, &SystemLayer); + SuccessOrExit(err); + PlatformMgr().ScheduleWork(DriveBLEState, 0); +#if _BLEMGRIMPL_USE_LEDS + led2 = 0; +#endif + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "BLEManager init error: %s ", ErrorStr(err)); + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service."); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } +} + +void BLEManagerImpl::DriveBLEState(intptr_t arg) +{ + BLEMgrImpl().DriveBLEState(); +} + +/* Update the advertising state based on the flags. + */ +void BLEManagerImpl::DriveBLEState() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Perform any initialization actions that must occur after the CHIP task is running. + if (!GetFlag(mFlags, kFlag_AsyncInitCompleted)) + { + SetFlag(mFlags, kFlag_AsyncInitCompleted); + + // If CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, + // disable CHIPoBLE advertising if the device is fully provisioned. +#if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED + if (ConfigurationMgr().IsFullyProvisioned()) + { + ClearFlag(mFlags, kFlag_AdvertisingEnabled); + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned"); + } +#endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED + } + + // If the application has enabled CHIPoBLE and BLE advertising... + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && + GetFlag(mFlags, kFlag_AdvertisingEnabled) +#if CHIP_DEVICE_CONFIG_CHIPOBLE_SINGLE_CONNECTION + // and no connections are active... + && (_NumConnections() == 0) +#endif + ) + { + // Start/re-start advertising if not already advertising, or if the + // advertising state needs to be refreshed. + if (!GetFlag(mFlags, kFlag_Advertising) || GetFlag(mFlags, kFlag_AdvertisingRefreshNeeded)) + { + err = StartAdvertising(); + SuccessOrExit(err); + } + } + // Otherwise, stop advertising if currently active. + else + { + err = StopAdvertising(); + SuccessOrExit(err); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + } +} +/* Build the advertising data and start advertising. + */ +CHIP_ERROR BLEManagerImpl::StartAdvertising(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ble_error_t mbed_err = BLE_ERROR_NONE; + + ble::Gap & gap = ble::BLE::Instance().gap(); + ble::AdvertisingDataBuilder adv_data_builder(mAdvertisingDataBuffer); + + ChipBLEDeviceIdentificationInfo dev_id_info; + + // Advertise CONNECTABLE if we haven't reached the maximum number of connections. + uint16_t num_conns = _NumConnections(); + bool connectable = (num_conns < kMaxConnections); + ble::advertising_type_t adv_type = + connectable ? ble::advertising_type_t::CONNECTABLE_UNDIRECTED : ble::advertising_type_t::SCANNABLE_UNDIRECTED; + + // Advertise in fast mode if not fully provisioned and there are no CHIPoBLE connections, or + // if the application has expressly requested fast advertising. + ble::adv_interval_t adv_interval = (num_conns == 0 && !ConfigurationMgr().IsFullyProvisioned()) + ? ble::adv_interval_t(CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL) + : ble::adv_interval_t(CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL); + // minInterval and maxInterval are equal for CHIP. + ble::AdvertisingParameters adv_params(adv_type, adv_interval, adv_interval); + + // Change own address type from RANDOM to PUBLIC. + adv_params.setOwnAddressType(ble::own_address_type_t::PUBLIC); + + // Restart advertising if already active. + if (gap.isAdvertisingActive(ble::LEGACY_ADVERTISING_HANDLE)) + { + mbed_err = gap.stopAdvertising(ble::LEGACY_ADVERTISING_HANDLE); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + ChipLogDetail(DeviceLayer, "Advertising already active. Restarting."); + } + + mbed_err = gap.setAdvertisingParameters(ble::LEGACY_ADVERTISING_HANDLE, adv_params); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + mbed_err = + adv_data_builder.setFlags(ble::adv_data_flags_t::BREDR_NOT_SUPPORTED | ble::adv_data_flags_t::LE_GENERAL_DISCOVERABLE); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + if (!GetFlag(mFlags, kFlag_UseCustomDeviceName)) + { + // FIXME + // uint16_t discriminator; + // SuccessOrExit(err = ConfigurationMgr().GetSetupDiscriminator(discriminator)); + uint16_t discriminator = 0xff; + memset(mDeviceName, 0, kMaxDeviceNameLength); + snprintf(mDeviceName, kMaxDeviceNameLength, "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator); + } + mbed_err = adv_data_builder.setName(mDeviceName); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + dev_id_info.Init(); + // FIXME + // SuccessOrExit(ConfigurationMgr().GetBLEDeviceIdentificationInfo(dev_id_info)); + mbed_err = adv_data_builder.setServiceData( + ShortUUID_CHIPoBLEService, mbed::make_Span(reinterpret_cast(&dev_id_info), sizeof dev_id_info)); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + mbed_err = gap.setAdvertisingPayload(ble::LEGACY_ADVERTISING_HANDLE, adv_data_builder.getAdvertisingData()); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + adv_data_builder.clear(); + adv_data_builder.setLocalServiceList(mbed::make_Span(&ShortUUID_CHIPoBLEService, 1)); + mbed_err = gap.setAdvertisingScanResponse(ble::LEGACY_ADVERTISING_HANDLE, adv_data_builder.getAdvertisingData()); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + mbed_err = gap.startAdvertising(ble::LEGACY_ADVERTISING_HANDLE); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + + ChipLogDetail(DeviceLayer, "Advertising started, type: 0x%x (%sconnectable), interval: [%d:%d] ms, device name: %s)", + adv_params.getType(), connectable ? "" : "non-", adv_params.getMinPrimaryInterval().valueInMs(), + adv_params.getMaxPrimaryInterval().valueInMs(), mDeviceName); + +exit: + if (mbed_err != BLE_ERROR_NONE) + { + ChipLogError(DeviceLayer, "StartAdvertising mbed-os error: %d", mbed_err); + } + return err; +} + +CHIP_ERROR BLEManagerImpl::StopAdvertising(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ble_error_t mbed_err = BLE_ERROR_NONE; + + ble::Gap & gap = ble::BLE::Instance().gap(); + + if (!gap.isAdvertisingActive(ble::LEGACY_ADVERTISING_HANDLE)) + { + ChipLogDetail(DeviceLayer, "No need to stop. Advertising inactive."); + return err; + } + mbed_err = gap.stopAdvertising(ble::LEGACY_ADVERTISING_HANDLE); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + +exit: + if (mbed_err != BLE_ERROR_NONE) + { + ChipLogError(DeviceLayer, "StopAdvertising mbed-os error: %d", mbed_err); + } + 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) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (GetFlag(mFlags, kFlag_AdvertisingEnabled) != val) + { + ChipLogDetail(DeviceLayer, "SetAdvertisingEnabled(%s)", val ? "true" : "false"); + + SetFlag(mFlags, kFlag_AdvertisingEnabled, val); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::_SetFastAdvertisingEnabled(bool val) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (GetFlag(mFlags, kFlag_FastAdvertisingEnabled) != val) + { + ChipLogDetail(DeviceLayer, "SetFastAdvertisingEnabled(%s)", val ? "true" : "false"); + + SetFlag(mFlags, kFlag_FastAdvertisingEnabled, val); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(strlen(mDeviceName) < bufSize, err = CHIP_ERROR_BUFFER_TOO_SMALL); + strcpy(buf, mDeviceName); + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (deviceName != nullptr && deviceName[0] != '\0') + { + VerifyOrExit(strlen(deviceName) < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT); + strcpy(mDeviceName, deviceName); + SetFlag(mFlags, kFlag_UseCustomDeviceName); + ChipLogDetail(DeviceLayer, "Device name set to: %s", deviceName); + } + else + { + mDeviceName[0] = '\0'; + ClearFlag(mFlags, kFlag_UseCustomDeviceName); + } + +exit: + return err; +} + +uint16_t BLEManagerImpl::_NumConnections(void) +{ + return mGAPConns; +} + +void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) +{ + switch (event->Type) + { + case DeviceEventType::kCHIPoBLESubscribe: { + ChipDeviceEvent connEstEvent; + + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLESubscribe"); + HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX); + connEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; + PlatformMgrImpl().PostEvent(&connEstEvent); + } + break; + + case DeviceEventType::kCHIPoBLEUnsubscribe: { + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEUnsubscribe"); + HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX); + } + break; + + case DeviceEventType::kCHIPoBLEWriteReceived: { + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEWriteReceived"); + HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX, + PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); + } + break; + + case DeviceEventType::kCHIPoBLEConnectionError: { + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEConnectionError"); + HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); + } + break; + + case DeviceEventType::kCHIPoBLEIndicateConfirm: { + ChipLogProgress(DeviceLayer, "_OnPlatformEvent kCHIPoBLEIndicateConfirm"); + HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX); + } + break; + + default: + ChipLogProgress(DeviceLayer, "_OnPlatformEvent default: event->Type = 0x%x", event->Type); + break; + } +} + +void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) +{ + // no-op +} + +bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) +{ + ChipLogProgress(DeviceLayer, "Closing BLE GATT connection, connHandle=%d", conId); + + ble::Gap & gap = ble::BLE::Instance().gap(); + + ble_error_t mbed_err = gap.disconnect(conId, ble::local_disconnection_reason_t::USER_TERMINATION); + return mbed_err == BLE_ERROR_NONE; +} + +uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const +{ + return sConnectionInfo.getMTU(conId); +} + +bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogDetail(DeviceLayer, "BlePlatformDelegate %s", __FUNCTION__); + + CHIP_ERROR err = CHIP_NO_ERROR; + ble_error_t mbed_err = BLE_ERROR_NONE; + + ble::GattServer & gatt_server = ble::BLE::Instance().gattServer(); + ble::attribute_handle_t att_handle; + + // No need to do anything fancy here. Only 3 handles are used in this impl. + if (UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_TX)) + { + att_handle = sCHIPService.getTxHandle(); + // att_handle = sCHIPService.getTxCCCDHandle(); + } + else if (UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_RX)) + { + // TODO does this make sense? + att_handle = sCHIPService.getRxHandle(); + } + else + { + // TODO handle error with chipConnection::SendMessage as described + // in the BlePlatformDelegate.h. + ChipLogError(DeviceLayer, "Send indication failed, invalid charID."); + return false; + } + + ChipLogDetail(DeviceLayer, + "Sending indication for CHIPoBLE characteristic " + "(connHandle=%d, attHandle=%d, data_len=%" PRIu16 ")", + conId, att_handle, pBuf->DataLength()); + + mbed_err = gatt_server.write(att_handle, pBuf->Start(), pBuf->DataLength(), false); + VerifyOrExit(mbed_err == BLE_ERROR_NONE, err = CHIP_ERROR_INTERNAL); + +exit: + if (mbed_err != BLE_ERROR_NONE) + { + ChipLogError(DeviceLayer, "Send indication failed, mbed-os error: %d", mbed_err); + } + return err == CHIP_NO_ERROR; +} + +bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, + const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogError(DeviceLayer, "%s: NOT IMPLEMENTED", __PRETTY_FUNCTION__); + return true; +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/mbed/BLEManagerImpl.h b/src/platform/mbed/BLEManagerImpl.h new file mode 100644 index 00000000000000..668fdeb3761735 --- /dev/null +++ b/src/platform/mbed/BLEManagerImpl.h @@ -0,0 +1,175 @@ +/* + * + * Copyright (c) 2020-2021 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. + */ + +/** + * @file + * Provides an implementation of the BLEManager singleton object + * for the Mbed platform. + */ + +#pragma once + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +class GapEventHandler; +class CHIPService; + +using namespace chip::Ble; + +/** + * Concrete implementation of the BLEManager singleton object for the Mbed platform. + */ +class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePlatformDelegate, private BleApplicationDelegate +{ + // Allow the BLEManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend BLEManager; + + // ===== Members that implement the BLEManager internal interface. + + CHIP_ERROR _Init(void); + CHIPoBLEServiceMode _GetCHIPoBLEServiceMode(void); + CHIP_ERROR _SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val); + bool _IsAdvertisingEnabled(void); + CHIP_ERROR _SetAdvertisingEnabled(bool val); + bool _IsFastAdvertisingEnabled(void); + CHIP_ERROR _SetFastAdvertisingEnabled(bool val); + bool _IsAdvertising(void); + CHIP_ERROR _GetDeviceName(char * buf, size_t bufSize); + CHIP_ERROR _SetDeviceName(const char * deviceName); + uint16_t _NumConnections(void); + void _OnPlatformEvent(const ChipDeviceEvent * event); + BleLayer * _GetBleLayer(void); + + // ===== Members that implement virtual methods on BlePlatformDelegate. + + bool SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId); + bool UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId); + bool CloseConnection(BLE_CONNECTION_OBJECT conId); + uint16_t GetMTU(BLE_CONNECTION_OBJECT conId) const; + bool SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf); + bool SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf); + bool SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf); + bool SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, const ChipBleUUID * svcId, + const ChipBleUUID * charId); + + // ===== Members that implement virtual methods on BleApplicationDelegate. + + void NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId); + + // ===== Members for internal use by the following friends. + + friend BLEManager & BLEMgr(void); + friend BLEManagerImpl & BLEMgrImpl(void); + friend class GapEventHandler; + friend class CHIPService; + + static BLEManagerImpl sInstance; + + // ===== Private members reserved for use by this class only. + + enum + { + kFlag_AsyncInitCompleted = 0x0001, /**< One-time asynchronous initialization actions have been performed. */ + kFlag_AdvertisingEnabled = 0x0002, /**< The application has enabled CHIPoBLE advertising. */ + kFlag_FastAdvertisingEnabled = 0x0004, /**< The application has enabled fast advertising. */ + kFlag_Advertising = 0x0008, /**< The system is currently CHIPoBLE advertising. */ + kFlag_AdvertisingRefreshNeeded = 0x0010, /**< The advertising configuration/state in BLE layer needs to be updated. */ + kFlag_DeviceNameSet = 0x0020, + kFlag_UseCustomDeviceName = 0x0040, /**< The application has configured a custom BLE device name. */ + }; + + enum + { + kMaxConnections = BLE_LAYER_NUM_BLE_ENDPOINTS, + kMaxDeviceNameLength = 16, + kAdvertisingDataSize = 0x1F, // mbed-os ble::LEGACY_ADVERTISING_MAX_SIZE + }; + + CHIPoBLEServiceMode mServiceMode; + uint16_t mFlags; + uint16_t mGAPConns; + char mDeviceName[kMaxDeviceNameLength + 1]; + uint8_t mAdvertisingDataBuffer[kAdvertisingDataSize]; + + static void DoBLEProcessing(intptr_t arg); + void HandleInitComplete(bool no_error); + static void DriveBLEState(intptr_t arg); + void DriveBLEState(void); + CHIP_ERROR StartAdvertising(void); + CHIP_ERROR StopAdvertising(void); +}; + +/** + * Returns a reference to the public interface of the BLEManager singleton object. + * + * Internal components should use this to access features of the BLEManager object + * that are common to all platforms. + */ +inline BLEManager & BLEMgr(void) +{ + return BLEManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the BLEManager singleton object. + * + * Internal components can use this to gain access to features of the BLEManager + * that are specific to the Mbed platform. + */ +inline BLEManagerImpl & BLEMgrImpl(void) +{ + return BLEManagerImpl::sInstance; +} + +inline BleLayer * BLEManagerImpl::_GetBleLayer() +{ + return this; +} + +inline BLEManager::CHIPoBLEServiceMode BLEManagerImpl::_GetCHIPoBLEServiceMode(void) +{ + return mServiceMode; +} + +inline bool BLEManagerImpl::_IsAdvertisingEnabled(void) +{ + return GetFlag(mFlags, kFlag_AdvertisingEnabled); +} + +inline bool BLEManagerImpl::_IsFastAdvertisingEnabled(void) +{ + return GetFlag(mFlags, kFlag_FastAdvertisingEnabled); +} + +inline bool BLEManagerImpl::_IsAdvertising(void) +{ + return GetFlag(mFlags, kFlag_Advertising); +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/mbed/CHIPDevicePlatformConfig.h b/src/platform/mbed/CHIPDevicePlatformConfig.h index cf436a96f1a665..76bec1d89c8162 100644 --- a/src/platform/mbed/CHIPDevicePlatformConfig.h +++ b/src/platform/mbed/CHIPDevicePlatformConfig.h @@ -28,7 +28,7 @@ #define CHIP_DEVICE_CONFIG_ENABLE_THREAD 0 #define CHIP_DEVICE_CONFIG_THREAD_FTD 0 -#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 0 +#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 1 #define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 0 diff --git a/src/platform/mbed/ConnectivityManagerImpl.cpp b/src/platform/mbed/ConnectivityManagerImpl.cpp index 237a4bb3b4b7e6..72a986505ea93d 100644 --- a/src/platform/mbed/ConnectivityManagerImpl.cpp +++ b/src/platform/mbed/ConnectivityManagerImpl.cpp @@ -133,13 +133,16 @@ CHIP_ERROR ConnectivityManagerImpl::_Init() // TODO Initialize the Chip Addressing and Routing Module. _interface = WiFiInterface::get_default_instance(); _security = NSAPI_SECURITY_WPA_WPA2; - _interface->attach([this](nsapi_event_t event, intptr_t data) { - PlatformMgrImpl().mQueue.call([this, event, data] { - PlatformMgr().LockChipStack(); - OnInterfaceEvent(event, data); - PlatformMgr().UnlockChipStack(); + if (_interface) + { + _interface->attach([this](nsapi_event_t event, intptr_t data) { + PlatformMgrImpl().mQueue.call([this, event, data] { + PlatformMgr().LockChipStack(); + OnInterfaceEvent(event, data); + PlatformMgr().UnlockChipStack(); + }); }); - }); + } return err; } diff --git a/src/platform/mbed/PlatformManagerImpl.cpp b/src/platform/mbed/PlatformManagerImpl.cpp index b67502a61b6cd1..4bb2d5b4c10245 100644 --- a/src/platform/mbed/PlatformManagerImpl.cpp +++ b/src/platform/mbed/PlatformManagerImpl.cpp @@ -5,6 +5,10 @@ #include #include +#if CHIP_SYSTEM_CONFIG_USE_LWIP +#include +#endif + namespace chip { namespace DeviceLayer { @@ -38,6 +42,11 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) return CHIP_ERROR_INCORRECT_STATE; } +#if CHIP_SYSTEM_CONFIG_USE_LWIP + // Initialize LwIP. + tcpip_init(NULL, NULL); +#endif + // Call up to the base class _InitChipStack() to perform the bulk of the initialization. auto err = GenericPlatformManagerImpl::_InitChipStack(); SuccessOrExit(err); diff --git a/src/platform/mbed/PlatformManagerImpl.h b/src/platform/mbed/PlatformManagerImpl.h index 74e3629d2ca9e3..5e21628120046b 100644 --- a/src/platform/mbed/PlatformManagerImpl.h +++ b/src/platform/mbed/PlatformManagerImpl.h @@ -70,7 +70,10 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener friend PlatformManagerImpl & PlatformMgrImpl(void); friend class Internal::BLEManagerImpl; friend class ConnectivityManagerImpl; + friend class Internal::GapEventHandler; + friend class Internal::CHIPService; + using PlatformManager::PostEvent; static PlatformManagerImpl sInstance; // ===== Members for internal use. @@ -95,9 +98,17 @@ inline PlatformManager & PlatformMgr(void) { return PlatformManagerImpl::sInstance; } -inline PlatformManagerImpl & PlatformMgrImpl(void) + +/** + * Returns the platform-specific implementation of the PlatformManager singleton object. + * + * chip applications can use this to gain access to features of the PlatformManager + * that are specific to the Mbed platform. + */ +inline PlatformManagerImpl & PlatformMgrImpl() { return PlatformManagerImpl::sInstance; } + } // namespace DeviceLayer } // namespace chip