diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 72243ab5a..fe6ea0152 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -337,6 +337,13 @@ build_esp_matter_examples: - cp sdkconfig.defaults sdkconfig.defaults.backup - cp sdkconfig.defaults.ext_plat_ci sdkconfig.defaults + # steps for external platform build for light_wifi_prov app + - cd ${ESP_MATTER_PATH}/examples/light_wifi_prov + - cp sdkconfig.defaults.esp32s3 sdkconfig.defaults.esp32s3.backup + - cp sdkconfig.defaults.esp32s3.ext_plat_ci sdkconfig.defaults.esp32s3 + - cp sdkconfig.defaults.esp32c3 sdkconfig.defaults.esp32c3.backup + - cp sdkconfig.defaults.esp32c3.ext_plat_ci sdkconfig.defaults.esp32c3 + - cd ${ESP_MATTER_PATH} - pip install -r tools/ci/requirements-build.txt - python tools/ci/build_apps.py ./examples --no_pytest diff --git a/examples/.build-rules.yml b/examples/.build-rules.yml index 2a17d4c5a..12ccdb6ce 100644 --- a/examples/.build-rules.yml +++ b/examples/.build-rules.yml @@ -110,3 +110,9 @@ examples/ota_provider: - if: IDF_TARGET in ["esp32s3"] temporary: true reason: the other targets are not tested yet + +examples/light_wifi_prov: + enable: + - if: IDF_TARGET in ["esp32s3", "esp32c3"] + temporary: true + reason: the other targets are not tested yet diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/BLEManagerImpl.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/BLEManagerImpl.h new file mode 100644 index 000000000..e5480505c --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/BLEManagerImpl.h @@ -0,0 +1,493 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * 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 ESP32 platform. + */ + +#pragma once +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +#include "sdkconfig.h" + +#include + +#ifdef CONFIG_BT_BLUEDROID_ENABLED + +#include "esp_bt.h" +#include "esp_gap_ble_api.h" +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +#include "esp_gattc_api.h" +#endif +#include "esp_gatts_api.h" +#include + +#elif defined(CONFIG_BT_NIMBLE_ENABLED) + +/* min max macros in NimBLE can cause build issues with generic min max + * functions defined in CHIP.*/ +#define min +#define max +#include "host/ble_hs.h" +#undef min +#undef max + +/* GATT context */ +struct ble_gatt_char_context +{ + uint16_t conn_handle; + uint16_t attr_handle; + struct ble_gatt_access_ctxt * ctxt; + void * arg; +}; + +#define MAX_ADV_DATA_LEN 31 +#define MAX_DEVICE_NAME_LEN 29 + +#endif // CONFIG_BT_BLUEDROID_ENABLED + +#include +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +#include +#ifdef CONFIG_BT_NIMBLE_ENABLED +#include "nimble/blecent.h" +#endif // CONFIG_BT_NIMBLE_ENABLED +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + +#define MAX_SCAN_RSP_DATA_LEN 31 + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +enum class BleScanState : uint8_t +{ + kNotScanning, + kScanForDiscriminator, + kScanForAddress, + kConnecting, +}; + +struct BLEAdvConfig +{ + char * mpBleName; + uint32_t mAdapterId; + uint8_t mMajor; + uint8_t mMinor; + uint16_t mVendorId; + uint16_t mProductId; + uint64_t mDeviceId; + uint8_t mPairingStatus; + uint8_t mType; + uint16_t mDuration; + const char * mpAdvertisingUUID; +}; + +struct BLEScanConfig +{ + // If an active scan for connection is being performed + BleScanState mBleScanState = BleScanState::kNotScanning; + + // If scanning by discriminator, what are we scanning for + SetupDiscriminator mDiscriminator; + + // If scanning by address, what address are we searching for + std::string mAddress; + + // Optional argument to be passed to callback functions provided by the BLE scan/connect requestor + void * mAppState = nullptr; +}; + +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER +/** + * Concrete implementation of the BLEManager singleton object for the ESP32 platform. + */ +class BLEManagerImpl final : public BLEManager, + private Ble::BleLayer, + private Ble::BlePlatformDelegate, +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + private Ble::BleApplicationDelegate, + private Ble::BleConnectionDelegate, + private ChipDeviceScannerDelegate +#else + private Ble::BleApplicationDelegate +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER +{ +public: + uint8_t scanResponseBuffer[MAX_SCAN_RSP_DATA_LEN]; + BLEManagerImpl() {} +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + CHIP_ERROR ConfigureBle(uint32_t aAdapterId, bool aIsCentral); +#ifdef CONFIG_BT_BLUEDROID_ENABLED + static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t * param); +#endif // CONFIG_BT_BLUEDROID_ENABLED +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + + CHIP_ERROR ConfigureScanResponseData(ByteSpan data); + void ClearScanResponseData(void); + + CHIP_ERROR SetSecondaryGATTService(struct ble_gatt_svc_def *gatt_svc, size_t gattSvcIndex) + { + if (!gatt_svc || gattSvcIndex > 1) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + mSecondGATTServiceIndex = gattSvcIndex; + memcpy(&mGATTServices[gattSvcIndex], gatt_svc, sizeof(struct ble_gatt_svc_def)); + return CHIP_NO_ERROR; + } + + using BleGapEventHandler = int(*)(struct ble_gap_event * event, void * arg); + + void SetSecondaryAdvGapEventHandler(BleGapEventHandler handler) { mSecondaryBleGapEventHandler = handler; } + + CHIP_ERROR SetSecondaryAdvDeviceName(const char *deviceName) + { + strncpy(mSecondaryAdvDeviceName, deviceName, MAX_DEVICE_NAME_LEN); + mSecondaryAdvDeviceName[MAX_DEVICE_NAME_LEN] = 0; + return CHIP_NO_ERROR; + } + + CHIP_ERROR SetSecondaryAdvUuid(const ByteSpan &uuid) + { + if (uuid.size() != 16) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + mSecondaryAdvUuid.u.type = BLE_UUID_TYPE_128; + memcpy(mSecondaryAdvUuid.value, uuid.data(), uuid.size()); + return CHIP_NO_ERROR; + } + + void SetSecondaryBleSmConfig(bool bleBonding, bool bleSmSc) + { + mSecondaryBleBonding = bleBonding; + mSecondaryBleSmSc = bleSmSc; + } + +private: + chip::Optional mScanResponse; + + // 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); + void _Shutdown(); + bool _IsAdvertisingEnabled(void); + CHIP_ERROR _SetAdvertisingEnabled(bool val); + bool _IsAdvertising(void); + CHIP_ERROR _SetAdvertisingMode(BLEAdvertisingMode mode); + CHIP_ERROR _GetDeviceName(char * buf, size_t bufSize); + CHIP_ERROR _SetDeviceName(const char * deviceName); + uint16_t _NumConnections(void); + void _OnPlatformEvent(const ChipDeviceEvent * event); +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + void HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * event); + CHIP_ERROR _SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val); +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + ::chip::Ble::BleLayer * _GetBleLayer(void); + + // ===== Members that implement virtual methods on BlePlatformDelegate. + + CHIP_ERROR SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, + const Ble::ChipBleUUID * charId) override; + CHIP_ERROR UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, + const Ble::ChipBleUUID * charId) override; + CHIP_ERROR CloseConnection(BLE_CONNECTION_OBJECT conId) override; + uint16_t GetMTU(BLE_CONNECTION_OBJECT conId) const override; + CHIP_ERROR SendIndication(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId, + System::PacketBufferHandle pBuf) override; + CHIP_ERROR SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId, + System::PacketBufferHandle pBuf) override; + + // ===== Members that implement virtual methods on BleApplicationDelegate. + + void NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) override; + // ===== Members that implement virtual methods on BleConnectionDelegate. +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + + void NewConnection(chip::Ble::BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator) override; + void NewConnection(chip::Ble::BleLayer * bleLayer, void * appState, BLE_CONNECTION_OBJECT connObj) override{}; + CHIP_ERROR CancelConnection() override; + + // ===== Members that implement virtual methods on ChipDeviceScannerDelegate +#ifdef CONFIG_BT_NIMBLE_ENABLED + virtual void OnDeviceScanned(const struct ble_hs_adv_fields & fields, const ble_addr_t & addr, + const chip::Ble::ChipBLEDeviceIdentificationInfo & info) override; +#elif defined(CONFIG_BT_BLUEDROID_ENABLED) + virtual void OnDeviceScanned(esp_ble_addr_type_t & addr_type, esp_bd_addr_t & addr, + const chip::Ble::ChipBLEDeviceIdentificationInfo & info) override; +#endif // CONFIG_BT_NIMBLE_ENABLED + + void OnScanComplete() override; +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + // ===== Members for internal use by the following friends. + + friend BLEManager & BLEMgr(void); + friend BLEManagerImpl & BLEMgrImpl(void); + + static BLEManagerImpl sInstance; + + // ===== Private members reserved for use by this class only. + + enum class Flags : uint16_t + { + kAsyncInitCompleted = 0x0001, /**< One-time asynchronous initialization actions have been performed. */ + kESPBLELayerInitialized = 0x0002, /**< The ESP BLE layer has been initialized. */ + kAppRegistered = 0x0004, /**< The CHIPoBLE application has been registered with the ESP BLE layer. */ + kAttrsRegistered = 0x0008, /**< The CHIPoBLE GATT attributes have been registered with the ESP BLE layer. */ + kGATTServiceStarted = 0x0010, /**< The CHIPoBLE GATT service has been started. */ + kAdvertisingConfigured = 0x0020, /**< CHIPoBLE advertising has been configured in the ESP BLE layer. */ + kAdvertising = 0x0040, /**< The system is currently CHIPoBLE advertising. */ + kControlOpInProgress = 0x0080, /**< An async control operation has been issued to the ESP BLE layer. */ + kAdvertisingEnabled = 0x0100, /**< The application has enabled CHIPoBLE advertising. */ + kFastAdvertisingEnabled = 0x0200, /**< The application has enabled fast advertising. */ + kUseCustomDeviceName = 0x0400, /**< The application has configured a custom BLE device name. */ + kAdvertisingRefreshNeeded = 0x0800, /**< The advertising configuration/state in ESP BLE layer needs to be updated. */ + kExtAdvertisingEnabled = 0x1000, /**< The application has enabled Extended BLE announcement. */ + }; + + enum + { + kMaxConnections = BLE_LAYER_NUM_BLE_ENDPOINTS, + kMaxDeviceNameLength = 16 + }; + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + BLEAdvConfig mBLEAdvConfig; +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER +#ifdef CONFIG_BT_NIMBLE_ENABLED + uint16_t mSubscribedConIds[kMaxConnections]; +#endif // CONFIG_BT_NIMBLE_ENABLED + + struct CHIPoBLEConState + { + System::PacketBufferHandle PendingIndBuf; + uint16_t ConId; + uint16_t MTU : 10; + uint16_t Allocated : 1; + uint16_t Subscribed : 1; + uint16_t Unused : 4; + + void Set(uint16_t conId) + { + PendingIndBuf = nullptr; + ConId = conId; + MTU = 0; + Allocated = 1; + Subscribed = 0; + Unused = 0; + } + void Reset() + { + PendingIndBuf = nullptr; + ConId = BLE_CONNECTION_UNINITIALIZED; + MTU = 0; + Allocated = 0; + Subscribed = 0; + Unused = 0; + } + }; + + CHIPoBLEConState mCons[kMaxConnections]; + CHIPoBLEServiceMode mServiceMode; +#ifdef CONFIG_BT_BLUEDROID_ENABLED + esp_gatt_if_t mAppIf; +#elif defined(CONFIG_BT_NIMBLE_ENABLED) + uint16_t mNumGAPCons; +#endif // CONFIG_BT_BLUEDROID_ENABLED + uint16_t mServiceAttrHandle; + uint16_t mRXCharAttrHandle; + uint16_t mTXCharAttrHandle; +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + uint16_t mC3CharAttrHandle; +#endif + uint16_t mTXCharCCCDAttrHandle; + BitFlags mFlags; + char mDeviceName[kMaxDeviceNameLength + 1]; + CHIP_ERROR MapBLEError(int bleErr); + + void DriveBLEState(void); + CHIP_ERROR InitESPBleLayer(void); + void DeinitESPBleLayer(void); + CHIP_ERROR ConfigureAdvertisingData(void); + CHIP_ERROR StartAdvertising(void); + void StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs); + void CancelBleAdvTimeoutTimer(void); + static void BleAdvTimeoutHandler(System::Layer *, void *); + +#ifdef CONFIG_BT_BLUEDROID_ENABLED + void HandleGATTControlEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t * param); + void HandleGATTCommEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t * param); + void HandleRXCharWrite(esp_ble_gatts_cb_param_t * param); + void HandleTXCharRead(esp_ble_gatts_cb_param_t * param); + void HandleTXCharCCCDRead(esp_ble_gatts_cb_param_t * param); + void HandleTXCharCCCDWrite(esp_ble_gatts_cb_param_t * param); + void HandleTXCharConfirm(CHIPoBLEConState * conState, esp_ble_gatts_cb_param_t * param); + void HandleDisconnect(esp_ble_gatts_cb_param_t * param); + CHIPoBLEConState * GetConnectionState(uint16_t conId, bool allocate = false); + bool ReleaseConnectionState(uint16_t conId); +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + CHIP_ERROR HandleGAPConnect(esp_ble_gattc_cb_param_t p_data); + CHIP_ERROR HandleGAPCentralConnect(esp_ble_gattc_cb_param_t p_data); + + static void HandleConnectFailed(CHIP_ERROR error); + static void ConnectDevice(esp_bd_addr_t & addr, esp_ble_addr_type_t addr_type, uint16_t timeout); + void HandleGAPConnectionFailed(); + CHIP_ERROR HandleRXNotify(esp_ble_gattc_cb_param_t p_data); +#endif + static void HandleGATTEvent(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t * param); + static void HandleGAPEvent(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t * param); + +#elif defined(CONFIG_BT_NIMBLE_ENABLED) + CHIP_ERROR DeinitBLE(); + static void ClaimBLEMemory(System::Layer *, void *); + + void HandleRXCharRead(struct ble_gatt_char_context * param); + void HandleRXCharWrite(struct ble_gatt_char_context * param); + void HandleTXCharWrite(struct ble_gatt_char_context * param); + void HandleTXCharRead(struct ble_gatt_char_context * param); + void HandleTXCharCCCDRead(void * param); + void HandleTXCharCCCDWrite(struct ble_gap_event * gapEvent); + CHIP_ERROR HandleTXComplete(struct ble_gap_event * gapEvent); + CHIP_ERROR HandleGAPConnect(struct ble_gap_event * gapEvent); + CHIP_ERROR HandleGAPPeripheralConnect(struct ble_gap_event * gapEvent); + CHIP_ERROR HandleGAPDisconnect(struct ble_gap_event * gapEvent); + CHIP_ERROR SetSubscribed(uint16_t conId); + bool UnsetSubscribed(uint16_t conId); + bool IsSubscribed(uint16_t conId); + static void ConnectDevice(const ble_addr_t & addr, uint16_t timeout); + CHIP_ERROR HandleGAPCentralConnect(struct ble_gap_event * gapEvent); + void HandleGAPConnectionFailed(struct ble_gap_event * gapEvent, CHIP_ERROR error); + + static CHIP_ERROR bleprph_set_random_addr(void); + static void bleprph_host_task(void * param); + static void bleprph_on_sync(void); + static void bleprph_on_reset(int); + static const struct ble_gatt_svc_def CHIPoBLEGATTService; + static int ble_svr_gap_event(struct ble_gap_event * event, void * arg); + + static int gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt * ctxt, void * arg); +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + static int gatt_svr_chr_access_additional_data(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt * ctxt, + void * arg); + void HandleC3CharRead(struct ble_gatt_char_context * param); +#endif /* CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING */ + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + static int btshell_on_mtu(uint16_t conn_handle, const struct ble_gatt_error * error, uint16_t mtu, void * arg); + + bool SubOrUnsubChar(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId, + bool subscribe); + + static void OnGattDiscComplete(const struct peer * peer, int status, void * arg); + static void HandleConnectFailed(CHIP_ERROR error); + CHIP_ERROR HandleRXNotify(struct ble_gap_event * event); +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER +#endif // CONFIG_BT_NIMBLE_ENABLED +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + static void CancelConnect(void); + static void HandleConnectTimeout(chip::System::Layer *, void * context); + void InitiateScan(BleScanState scanType); + static void InitiateScan(intptr_t arg); + void HandleAdvertisementTimer(System::Layer * systemLayer, void * context); + void HandleAdvertisementTimer(); + void CleanScanConfig(); + BLEScanConfig mBLEScanConfig; + bool mIsCentral; +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + + static void DriveBLEState(intptr_t arg); + + uint8_t mAdvData[MAX_ADV_DATA_LEN]; + uint16_t mAdvDataLen; + static constexpr uint8_t kChipAdvInstance = 0; + // Three GATT service + // mGATTServices[0] is for Matter-over-BLE + // mGATTServices[1] is for wifi_provisioning over BLE + // mGATTServices[2] is NULL + struct ble_gatt_svc_def mGATTServices[3]; + + // Secondary Advertisement + static int secondary_ble_svr_gap_event(struct ble_gap_event * event, void * arg); + CHIP_ERROR ConfigureSecondaryAdvertisingData(void); + CHIP_ERROR StartSecondaryAdvertising(void); + char mSecondaryAdvDeviceName[MAX_DEVICE_NAME_LEN + 1]; + size_t mSecondGATTServiceIndex = 1; + ble_uuid128_t mSecondaryAdvUuid; + bool mSecondaryBleBonding; + bool mSecondaryBleSmSc; + ble_hs_adv_fields mSecondaryAdvFields; + ble_hs_adv_fields mSecondaryRespFields; + uint8_t *mSecondaryMfgData; + size_t mSecondaryMfgDataLen; + BleGapEventHandler mSecondaryBleGapEventHandler = nullptr; + static constexpr uint8_t kSecondaryAdvInstance = 1; +}; + +/** + * 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 ESP32 platform. + */ +inline BLEManagerImpl & BLEMgrImpl(void) +{ + return BLEManagerImpl::sInstance; +} + +inline ::chip::Ble::BleLayer * BLEManagerImpl::_GetBleLayer() +{ + return this; +} + +inline bool BLEManagerImpl::_IsAdvertisingEnabled(void) +{ + return mFlags.Has(Flags::kAdvertisingEnabled); +} + +inline bool BLEManagerImpl::_IsAdvertising(void) +{ + return mFlags.Has(Flags::kAdvertising); +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/BUILD.gn b/examples/common/secondary_ble_adv/platform/ESP32_custom/BUILD.gn new file mode 100644 index 000000000..2e224e5f7 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/BUILD.gn @@ -0,0 +1,242 @@ +# Copyright (c) 2023 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. + +import("//build_overrides/chip.gni") + +import("${chip_root}/build/chip/buildconfig_header.gni") +import("${chip_root}/src/platform/device.gni") + +declare_args() { + # By default use default/example implementation of CommissionableDataProvider, + # DeviceAttestationCredentialsProvider and DeviceInstanceInfoProvider + chip_use_transitional_commissionable_data_provider = true + chip_use_transitional_device_instance_info_provider = true + chip_use_factory_data_provider = false + chip_use_device_info_provider = false + chip_config_software_version_number = 0 + chip_enable_chipoble = true + chip_bt_nimble_enabled = true + chip_bt_bluedroid_enabled = false + chip_enable_ble_controller = false + chip_use_secure_cert_dac_provider = false + chip_use_esp32_ecdsa_peripheral = false + chip_enable_ethernet = false + chip_max_discovered_ip_addresses = 5 + chip_enable_route_hook = false +} + +buildconfig_header("custom_buildconfig") { + header = "CHIPDeviceBuildConfig.h" + header_dir = "platform" + + defines = [ + "CHIP_DEVICE_CONFIG_ENABLE_WPA=false", + "CHIP_ENABLE_OPENTHREAD=${chip_enable_openthread}", + "CHIP_DEVICE_CONFIG_THREAD_FTD=${chip_openthread_ftd}", + "OPENTHREAD_CONFIG_ENABLE_TOBLE=false", + "CHIP_BYPASS_RENDEZVOUS=false", + "CHIP_STACK_LOCK_TRACKING_ENABLED=true", + "CHIP_STACK_LOCK_TRACKING_ERROR_FATAL=false", + "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING=false", + "CHIP_DEVICE_CONFIG_RUN_AS_ROOT=false", + "CHIP_DEVICE_LAYER_TARGET_ESP32=1", + "CHIP_DEVICE_LAYER_TARGET=ESP32_custom", + "CHIP_USE_TRANSITIONAL_COMMISSIONABLE_DATA_PROVIDER=${chip_use_transitional_commissionable_data_provider}", + "CHIP_USE_TRANSITIONAL_DEVICE_INSTANCE_INFO_PROVIDER=${chip_use_transitional_device_instance_info_provider}", + "BLE_PLATFORM_CONFIG_INCLUDE=", + "CHIP_DEVICE_PLATFORM_CONFIG_INCLUDE=", + "CHIP_PLATFORM_CONFIG_INCLUDE=", + "INET_CONFIG_INCLUDE=", + "SYSTEM_PLATFORM_CONFIG_INCLUDE=", + "EXTERNAL_CONFIGURATIONMANAGERIMPL_HEADER=", + "EXTERNAL_CHIPDEVICEPLATFORMEVENT_HEADER=", + "EXTERNAL_CONNECTIVITYMANAGERIMPL_HEADER=", + "EXTERNAL_BLEMANAGERIMPL_HEADER=", + "EXTERNAL_KEYVALUESTOREMANAGERIMPL_HEADER=", + "EXTERNAL_PLATFORMMANAGERIMPL_HEADER=", + "CHIP_CONFIG_SOFTWARE_VERSION_NUMBER=${chip_config_software_version_number}", + "CHIP_DEVICE_CONFIG_MAX_DISCOVERED_IP_ADDRESSES=${chip_max_discovered_ip_addresses}", + ] + + if (chip_enable_ota_requestor) { + defines += [ "CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR=1" ] + } +} + +group("platform_buildconfig") { + public_deps = [ ":custom_buildconfig" ] +} + +static_library("ESP32_custom") { + sources = [ + "${chip_root}/src/platform/SingletonConfigurationManager.cpp", + "CHIPDevicePlatformConfig.h", + "CHIPDevicePlatformEvent.h", + "ConfigurationManagerImpl.cpp", + "ConfigurationManagerImpl.h", + "ConnectivityManagerImpl.cpp", + "ConnectivityManagerImpl.h", + "DiagnosticDataProviderImpl.cpp", + "DiagnosticDataProviderImpl.h", + "ESP32Config.cpp", + "ESP32Config.h", + "ESP32Utils.cpp", + "ESP32Utils.h", + "KeyValueStoreManagerImpl.cpp", + "KeyValueStoreManagerImpl.h", + "Logging.cpp", + "LwIPCoreLock.cpp", + "PlatformManagerImpl.cpp", + "PlatformManagerImpl.h", + "SystemTimeSupport.cpp", + "SystemTimeSupport.h", + ] + + deps = [ + "${chip_root}/src/lib/dnssd:platform_header", + "${chip_root}/src/platform/logging:headers", + "${chip_root}/src/setup_payload", + ] + + public = [ + "${chip_root}/src/credentials/CHIPCert.h", + "${chip_root}/src/credentials/DeviceAttestationCredsProvider.h", + ] + + public_deps = [ + ":platform_buildconfig", + "${chip_root}/src/crypto", + "${chip_root}/src/platform:platform_base", + ] + + if (chip_enable_ota_requestor) { + sources += [ + "OTAImageProcessorImpl.cpp", + "OTAImageProcessorImpl.h", + ] + } + + if (chip_enable_chipoble) { + sources += [ + "BLEManagerImpl.h", + "ChipDeviceScanner.h", + ] + } + + if (chip_enable_ble_controller) { + sources += [ "ChipDeviceScanner.h" ] + } + + if (chip_bt_nimble_enabled) { + sources += [ "nimble/BLEManagerImpl.cpp" ] + if (chip_enable_ble_controller) { + sources += [ + "nimble/ChipDeviceScanner.cpp", + "nimble/blecent.h", + "nimble/misc.c", + "nimble/peer.c", + ] + } + } + + if (chip_bt_bluedroid_enabled) { + sources += [ "bluedroid/BLEManagerImpl.cpp" ] + if (chip_enable_ble_controller) { + sources += [ "bluedroid/ChipDeviceScanner.cpp" ] + } + } + + if (chip_enable_wifi) { + sources += [ + "ConnectivityManagerImpl_WiFi.cpp", + "NetworkCommissioningDriver.cpp", + "NetworkCommissioningDriver.h", + ] + } + + if (chip_mdns == "platform") { + sources += [ "DnssdImpl.cpp" ] + } + + if (chip_enable_ethernet) { + sources += [ + "ConnectivityManagerImpl_Ethernet.cpp", + "NetworkCommissioningDriver_Ethernet.cpp", + ] + } + + if (chip_enable_ethernet || chip_enable_wifi) { + if (chip_mdns == "platform") { + sources += [ + "ESP32DnssdImpl.cpp", + "ESP32DnssdImpl.h", + ] + } + if (chip_mdns == "minimal") { + sources += [ "ESP32EndpointQueueFilter.h" ] + } + if (chip_enable_route_hook) { + sources += [ + "route_hook/ESP32RouteHook.c", + "route_hook/ESP32RouteHook.h", + "route_hook/ESP32RouteTable.c", + "route_hook/ESP32RouteTable.h", + ] + } + } + + if (chip_enable_openthread) { + sources += [ + "../OpenThread/GenericNetworkCommissioningThreadDriver.cpp", + "../OpenThread/GenericNetworkCommissioningThreadDriver.h", + "../OpenThread/OpenThreadUtils.cpp", + "OpenthreadLauncher.cpp", + "OpenthreadLauncher.h", + "ThreadStackManagerImpl.cpp", + "ThreadStackManagerImpl.h", + ] + if (chip_mdns == "platform") { + sources += [ + "../OpenThread/OpenThreadDnssdImpl.cpp", + "../OpenThread/OpenThreadDnssdImpl.h", + ] + } + configs -= [ "${chip_root}/build/config/compiler:warnings_default" ] + } + + if (chip_use_factory_data_provider) { + sources += [ + "ESP32FactoryDataProvider.cpp", + "ESP32FactoryDataProvider.h", + "StaticESP32DeviceInfoProvider.cpp", + "StaticESP32DeviceInfoProvider.h", + ] + } + + if (chip_use_secure_cert_dac_provider) { + sources += [ + "ESP32SecureCertDACProvider.cpp", + "ESP32SecureCertDACProvider.h", + ] + } + + if (chip_use_device_info_provider) { + sources += [ + "ESP32DeviceInfoProvider.cpp", + "ESP32DeviceInfoProvider.h", + ] + } + + cflags = [ "-Wconversion" ] +} diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/BlePlatformConfig.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/BlePlatformConfig.h new file mode 120000 index 000000000..7f1b6eb48 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/BlePlatformConfig.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/BlePlatformConfig.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/CHIPDevicePlatformConfig.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/CHIPDevicePlatformConfig.h new file mode 120000 index 000000000..40c374398 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/CHIPDevicePlatformConfig.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/CHIPDevicePlatformConfig.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/CHIPDevicePlatformEvent.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/CHIPDevicePlatformEvent.h new file mode 120000 index 000000000..a4f270c54 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/CHIPDevicePlatformEvent.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/CHIPDevicePlatformEvent.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/CHIPPlatformConfig.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/CHIPPlatformConfig.h new file mode 120000 index 000000000..745831359 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/CHIPPlatformConfig.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/CHIPPlatformConfig.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ChipDeviceScanner.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ChipDeviceScanner.h new file mode 120000 index 000000000..4b623a990 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ChipDeviceScanner.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ChipDeviceScanner.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ConfigurationManagerImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConfigurationManagerImpl.cpp new file mode 120000 index 000000000..13cd8589a --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConfigurationManagerImpl.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ConfigurationManagerImpl.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ConfigurationManagerImpl.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConfigurationManagerImpl.h new file mode 120000 index 000000000..b8823431f --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConfigurationManagerImpl.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ConfigurationManagerImpl.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl.cpp new file mode 120000 index 000000000..a9f51630b --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ConnectivityManagerImpl.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl.h new file mode 120000 index 000000000..29f46b4ea --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ConnectivityManagerImpl.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl_Ethernet.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl_Ethernet.cpp new file mode 120000 index 000000000..87e131daf --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl_Ethernet.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ConnectivityManagerImpl_Ethernet.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl_WiFi.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl_WiFi.cpp new file mode 120000 index 000000000..cc3046e62 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ConnectivityManagerImpl_WiFi.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/DiagnosticDataProviderImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/DiagnosticDataProviderImpl.cpp new file mode 120000 index 000000000..592dceacc --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/DiagnosticDataProviderImpl.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/DiagnosticDataProviderImpl.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/DiagnosticDataProviderImpl.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/DiagnosticDataProviderImpl.h new file mode 120000 index 000000000..de7bf7c07 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/DiagnosticDataProviderImpl.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/DiagnosticDataProviderImpl.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/DnssdImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/DnssdImpl.cpp new file mode 120000 index 000000000..71690e7c4 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/DnssdImpl.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/DnssdImpl.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32CHIPCryptoPAL.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32CHIPCryptoPAL.cpp new file mode 120000 index 000000000..34b3cf26b --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32CHIPCryptoPAL.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32CHIPCryptoPAL.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32CHIPCryptoPAL.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32CHIPCryptoPAL.h new file mode 120000 index 000000000..bea24fd20 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32CHIPCryptoPAL.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32CHIPCryptoPAL.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Config.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Config.cpp new file mode 120000 index 000000000..8d27b30f7 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Config.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32Config.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Config.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Config.h new file mode 120000 index 000000000..7f2fe3f5d --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Config.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32Config.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DeviceInfoProvider.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DeviceInfoProvider.cpp new file mode 120000 index 000000000..4dffdba7e --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DeviceInfoProvider.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32DeviceInfoProvider.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DeviceInfoProvider.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DeviceInfoProvider.h new file mode 120000 index 000000000..dec2f5ec8 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DeviceInfoProvider.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32DeviceInfoProvider.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DnssdImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DnssdImpl.cpp new file mode 120000 index 000000000..ec6f699a9 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DnssdImpl.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32DnssdImpl.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DnssdImpl.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DnssdImpl.h new file mode 120000 index 000000000..463b03b21 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32DnssdImpl.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32DnssdImpl.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32EndpointQueueFilter.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32EndpointQueueFilter.h new file mode 120000 index 000000000..fc4f86178 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32EndpointQueueFilter.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32EndpointQueueFilter.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32FactoryDataProvider.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32FactoryDataProvider.cpp new file mode 120000 index 000000000..a1aaf653e --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32FactoryDataProvider.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32FactoryDataProvider.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32FactoryDataProvider.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32FactoryDataProvider.h new file mode 120000 index 000000000..180c6f62a --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32FactoryDataProvider.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32FactoryDataProvider.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32SecureCertDACProvider.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32SecureCertDACProvider.cpp new file mode 120000 index 000000000..bf7578970 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32SecureCertDACProvider.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32SecureCertDACProvider.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32SecureCertDACProvider.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32SecureCertDACProvider.h new file mode 120000 index 000000000..d74425545 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32SecureCertDACProvider.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32SecureCertDACProvider.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Utils.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Utils.cpp new file mode 100644 index 000000000..7a7fcad29 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Utils.cpp @@ -0,0 +1,395 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * 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 + * General utility methods for the ESP32 platform. + */ +/* this file behaves like a config.h, comes first */ +#include + +#include +#include +#include +#include + +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_netif_net_stack.h" +#include "esp_wifi.h" +#include "nvs.h" + +using namespace ::chip::DeviceLayer::Internal; +using chip::DeviceLayer::Internal::DeviceNetworkInfo; +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI +CHIP_ERROR ESP32Utils::IsAPEnabled(bool & apEnabled) +{ +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP + wifi_mode_t curWiFiMode; + + esp_err_t err = esp_wifi_get_mode(&curWiFiMode); + if (err != ESP_OK) + { + ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", esp_err_to_name(err)); + return ESP32Utils::MapError(err); + } + + apEnabled = (curWiFiMode == WIFI_MODE_AP || curWiFiMode == WIFI_MODE_APSTA); + + return CHIP_NO_ERROR; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP +} + +CHIP_ERROR ESP32Utils::IsStationEnabled(bool & staEnabled) +{ + wifi_mode_t curWiFiMode; + esp_err_t err = esp_wifi_get_mode(&curWiFiMode); + if (err != ESP_OK) + { + ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", esp_err_to_name(err)); + return ESP32Utils::MapError(err); + } + + staEnabled = (curWiFiMode == WIFI_MODE_STA || curWiFiMode == WIFI_MODE_APSTA); + + return CHIP_NO_ERROR; +} + +bool ESP32Utils::IsStationProvisioned(void) +{ + wifi_config_t stationConfig; + return (esp_wifi_get_config(WIFI_IF_STA, &stationConfig) == ERR_OK && stationConfig.sta.ssid[0] != 0); +} + +CHIP_ERROR ESP32Utils::IsStationConnected(bool & connected) +{ + wifi_ap_record_t apInfo; + connected = (esp_wifi_sta_get_ap_info(&apInfo) == ESP_OK && apInfo.ssid[0] != 0); + return CHIP_NO_ERROR; +} + +CHIP_ERROR ESP32Utils::StartWiFiLayer(void) +{ + int8_t ignored; + bool wifiStarted; + + // There appears to be no direct way to ask the ESP WiFi layer if esp_wifi_start() + // has been called. So use the ESP_ERR_WIFI_NOT_STARTED error returned by + // esp_wifi_get_max_tx_power() to detect this. + esp_err_t err = esp_wifi_get_max_tx_power(&ignored); + switch (err) + { + case ESP_OK: + wifiStarted = true; + break; + case ESP_ERR_WIFI_NOT_STARTED: + wifiStarted = false; + break; + default: + return ESP32Utils::MapError(err); + } + + if (!wifiStarted) + { + ChipLogProgress(DeviceLayer, "Starting ESP WiFi layer"); + + err = esp_wifi_start(); + if (err != ESP_OK) + { + ChipLogError(DeviceLayer, "esp_wifi_start() failed: %s", esp_err_to_name(err)); + return ESP32Utils::MapError(err); + } + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ESP32Utils::EnableStationMode(void) +{ + wifi_mode_t curWiFiMode; + + // Get the current ESP WiFI mode. + esp_err_t err = esp_wifi_get_mode(&curWiFiMode); + if (err != ESP_OK) + { + ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", esp_err_to_name(err)); + return ESP32Utils::MapError(err); + } + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP + // If station mode is not already enabled (implying the current mode is WIFI_MODE_AP), change + // the mode to WIFI_MODE_APSTA. + if (curWiFiMode == WIFI_MODE_AP) + { + ChipLogProgress(DeviceLayer, "Changing ESP WiFi mode: %s -> %s", WiFiModeToStr(WIFI_MODE_AP), + WiFiModeToStr(WIFI_MODE_APSTA)); + + err = esp_wifi_set_mode(WIFI_MODE_APSTA); + if (err != ESP_OK) + { + ChipLogError(DeviceLayer, "esp_wifi_set_mode() failed: %s", esp_err_to_name(err)); + return ESP32Utils::MapError(err); + } + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ESP32Utils::SetAPMode(bool enabled) +{ + wifi_mode_t curWiFiMode; + wifi_mode_t targetWiFiMode = WIFI_MODE_STA; + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP + targetWiFiMode = (enabled) ? WIFI_MODE_APSTA : WIFI_MODE_STA; +#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP + + // Get the current ESP WiFI mode. + esp_err_t err = esp_wifi_get_mode(&curWiFiMode); + if (err != ESP_OK) + { + ChipLogError(DeviceLayer, "esp_wifi_get_mode() failed: %s", esp_err_to_name(err)); + return ESP32Utils::MapError(err); + } + + // If station mode is not already enabled (implying the current mode is WIFI_MODE_AP), change + // the mode to WIFI_MODE_APSTA. + if (curWiFiMode != targetWiFiMode) + { + ChipLogProgress(DeviceLayer, "Changing ESP WiFi mode: %s -> %s", WiFiModeToStr(curWiFiMode), WiFiModeToStr(targetWiFiMode)); + + err = esp_wifi_set_mode(targetWiFiMode); + if (err != ESP_OK) + { + ChipLogError(DeviceLayer, "esp_wifi_set_mode() failed: %s", esp_err_to_name(err)); + return ESP32Utils::MapError(err); + } + } + + return CHIP_NO_ERROR; +} + +int ESP32Utils::OrderScanResultsByRSSI(const void * _res1, const void * _res2) +{ + const wifi_ap_record_t * res1 = (const wifi_ap_record_t *) _res1; + const wifi_ap_record_t * res2 = (const wifi_ap_record_t *) _res2; + + if (res1->rssi > res2->rssi) + { + return -1; + } + if (res1->rssi < res2->rssi) + { + return 1; + } + return 0; +} + +const char * ESP32Utils::WiFiModeToStr(wifi_mode_t wifiMode) +{ + switch (wifiMode) + { + case WIFI_MODE_NULL: + return "NULL"; + case WIFI_MODE_STA: + return "STA"; + case WIFI_MODE_AP: + return "AP"; + case WIFI_MODE_APSTA: + return "STA+AP"; + default: + return "(unknown)"; + } +} + +struct netif * ESP32Utils::GetStationNetif(void) +{ + return GetNetif(kDefaultWiFiStationNetifKey); +} + +CHIP_ERROR ESP32Utils::GetWiFiStationProvision(Internal::DeviceNetworkInfo & netInfo, bool includeCredentials) +{ + wifi_config_t stationConfig; + + esp_err_t err = esp_wifi_get_config(WIFI_IF_STA, &stationConfig); + if (err != ESP_OK) + { + return ESP32Utils::MapError(err); + } + + VerifyOrReturnError(stationConfig.sta.ssid[0] != 0, CHIP_ERROR_INCORRECT_STATE); + + netInfo.NetworkId = kWiFiStationNetworkId; + netInfo.FieldPresent.NetworkId = true; + memcpy(netInfo.WiFiSSID, stationConfig.sta.ssid, + min(strlen(reinterpret_cast(stationConfig.sta.ssid)) + 1, sizeof(netInfo.WiFiSSID))); + + // Enforce that netInfo wifiSSID is null terminated + netInfo.WiFiSSID[kMaxWiFiSSIDLength] = '\0'; + + if (includeCredentials) + { + static_assert(sizeof(netInfo.WiFiKey) < 255, "Our min might not fit in netInfo.WiFiKeyLen"); + netInfo.WiFiKeyLen = static_cast(min(strlen((char *) stationConfig.sta.password), sizeof(netInfo.WiFiKey))); + memcpy(netInfo.WiFiKey, stationConfig.sta.password, netInfo.WiFiKeyLen); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ESP32Utils::SetWiFiStationProvision(const Internal::DeviceNetworkInfo & netInfo) +{ + wifi_config_t wifiConfig; + + char wifiSSID[kMaxWiFiSSIDLength + 1]; + size_t netInfoSSIDLen = strlen(netInfo.WiFiSSID); + + // Ensure that ESP station mode is enabled. This is required before esp_wifi_set_config(ESP_IF_WIFI_STA,...) + // can be called. + ReturnErrorOnFailure(ESP32Utils::EnableStationMode()); + + // Enforce that wifiSSID is null terminated before copying it + memcpy(wifiSSID, netInfo.WiFiSSID, min(netInfoSSIDLen + 1, sizeof(wifiSSID))); + if (netInfoSSIDLen + 1 < sizeof(wifiSSID)) + { + wifiSSID[netInfoSSIDLen] = '\0'; + } + else + { + wifiSSID[kMaxWiFiSSIDLength] = '\0'; + } + + // Initialize an ESP wifi_config_t structure based on the new provision information. + memset(&wifiConfig, 0, sizeof(wifiConfig)); + memcpy(wifiConfig.sta.ssid, wifiSSID, min(strlen(wifiSSID) + 1, sizeof(wifiConfig.sta.ssid))); + memcpy(wifiConfig.sta.password, netInfo.WiFiKey, min((size_t) netInfo.WiFiKeyLen, sizeof(wifiConfig.sta.password))); + wifiConfig.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; + wifiConfig.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL; + + // Configure the ESP WiFi interface. + esp_err_t err = esp_wifi_set_config(WIFI_IF_STA, &wifiConfig); + if (err != ESP_OK) + { + ChipLogError(DeviceLayer, "esp_wifi_set_config() failed: %s", esp_err_to_name(err)); + return ESP32Utils::MapError(err); + } + + ChipLogProgress(DeviceLayer, "WiFi station provision set (SSID: %s)", netInfo.WiFiSSID); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ESP32Utils::ClearWiFiStationProvision(void) +{ + wifi_config_t stationConfig; + + // Clear the ESP WiFi station configuration. + memset(&stationConfig, 0, sizeof(stationConfig)); + esp_wifi_set_config(WIFI_IF_STA, &stationConfig); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ESP32Utils::InitWiFiStack(void) +{ + // Intentionally make this function empty so that we can setup wifi stack in the example + return CHIP_NO_ERROR; +} +#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI + +struct netif * ESP32Utils::GetNetif(const char * ifKey) +{ + struct netif * netif = NULL; + esp_netif_t * netif_handle = NULL; + netif_handle = esp_netif_get_handle_from_ifkey(ifKey); + netif = (struct netif *) esp_netif_get_netif_impl(netif_handle); + return netif; +} + +bool ESP32Utils::IsInterfaceUp(const char * ifKey) +{ + struct netif * netif = GetNetif(ifKey); + return netif != NULL && netif_is_up(netif); +} + +bool ESP32Utils::HasIPv6LinkLocalAddress(const char * ifKey) +{ + struct esp_ip6_addr if_ip6_unused; + return esp_netif_get_ip6_linklocal(esp_netif_get_handle_from_ifkey(ifKey), &if_ip6_unused) == ESP_OK; +} + +CHIP_ERROR ESP32Utils::MapError(esp_err_t error) +{ + if (error == ESP_OK) + { + return CHIP_NO_ERROR; + } + if (error == ESP_ERR_NVS_NOT_FOUND) + { + return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; + } + if (error == ESP_ERR_NVS_INVALID_LENGTH) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + return CHIP_ERROR(ChipError::Range::kPlatform, error); +} + +/** + * Given a CHIP error value that represents an ESP32 error, returns a + * human-readable NULL-terminated C string describing the error. + * + * @param[in] buf Buffer into which the error string will be placed. + * @param[in] bufSize Size of the supplied buffer in bytes. + * @param[in] err The error to be described. + * + * @return true If a description string was written into the supplied buffer. + * @return false If the supplied error was not an ESP32 error. + * + */ +bool ESP32Utils::FormatError(char * buf, uint16_t bufSize, CHIP_ERROR err) +{ + if (!err.IsRange(ChipError::Range::kPlatform)) + { + return false; + } + +#if CHIP_CONFIG_SHORT_ERROR_STR + const char * desc = NULL; +#else // CHIP_CONFIG_SHORT_ERROR_STR + const char * desc = esp_err_to_name((esp_err_t) err.GetValue()); +#endif // CHIP_CONFIG_SHORT_ERROR_STR + + chip::FormatError(buf, bufSize, "ESP32", err, desc); + + return true; +} + +/** + * Register a text error formatter for ESP32 errors. + */ +void ESP32Utils::RegisterESP32ErrorFormatter() +{ + static ErrorFormatter sErrorFormatter = { ESP32Utils::FormatError, NULL }; + + RegisterErrorFormatter(&sErrorFormatter); +} diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Utils.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Utils.h new file mode 120000 index 000000000..ba781b44a --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ESP32Utils.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32Utils.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/InetPlatformConfig.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/InetPlatformConfig.h new file mode 120000 index 000000000..10228dc8e --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/InetPlatformConfig.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/InetPlatformConfig.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/KeyValueStoreManagerImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/KeyValueStoreManagerImpl.cpp new file mode 120000 index 000000000..9cfbec315 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/KeyValueStoreManagerImpl.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/KeyValueStoreManagerImpl.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/KeyValueStoreManagerImpl.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/KeyValueStoreManagerImpl.h new file mode 120000 index 000000000..094b1f2db --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/KeyValueStoreManagerImpl.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/KeyValueStoreManagerImpl.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/Logging.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/Logging.cpp new file mode 120000 index 000000000..718dd2271 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/Logging.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/Logging.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/LwIPCoreLock.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/LwIPCoreLock.cpp new file mode 120000 index 000000000..bedaac190 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/LwIPCoreLock.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/LwIPCoreLock.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/NetworkCommissioningDriver.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/NetworkCommissioningDriver.cpp new file mode 120000 index 000000000..d9f53e41f --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/NetworkCommissioningDriver.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/NetworkCommissioningDriver.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/NetworkCommissioningDriver.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/NetworkCommissioningDriver.h new file mode 120000 index 000000000..c4bffcee7 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/NetworkCommissioningDriver.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/NetworkCommissioningDriver.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/NetworkCommissioningDriver_Ethernet.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/NetworkCommissioningDriver_Ethernet.cpp new file mode 120000 index 000000000..1b21b9c42 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/NetworkCommissioningDriver_Ethernet.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/NetworkCommissioningDriver_Ethernet.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/OTAImageProcessorImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/OTAImageProcessorImpl.cpp new file mode 120000 index 000000000..890a0f9b8 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/OTAImageProcessorImpl.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/OTAImageProcessorImpl.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/OTAImageProcessorImpl.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/OTAImageProcessorImpl.h new file mode 120000 index 000000000..f06ef5544 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/OTAImageProcessorImpl.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/OTAImageProcessorImpl.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/OpenthreadLauncher.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/OpenthreadLauncher.cpp new file mode 120000 index 000000000..9f2f03b3d --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/OpenthreadLauncher.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/OpenthreadLauncher.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/OpenthreadLauncher.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/OpenthreadLauncher.h new file mode 120000 index 000000000..d36244505 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/OpenthreadLauncher.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/OpenthreadLauncher.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/PlatformManagerImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/PlatformManagerImpl.cpp new file mode 100644 index 000000000..35ff83c2d --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/PlatformManagerImpl.cpp @@ -0,0 +1,215 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * 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 PlatformManager object + * for the ESP32 platform. + */ +/* this file behaves like a config.h, comes first */ +#include + +#include +#include +#include +#include +#include +#include + +#include "esp_event.h" +#include "esp_heap_caps_init.h" +#include "esp_log.h" +#include "esp_netif.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "spi_flash_mmap.h" +#else +#include "esp_spi_flash.h" +#endif +#include "esp_system.h" +#include "esp_wifi.h" + +namespace chip { +namespace DeviceLayer { + +namespace Internal { +extern CHIP_ERROR InitLwIPCoreLock(); +} + +PlatformManagerImpl PlatformManagerImpl::sInstance; + +static int app_entropy_source(void * data, unsigned char * output, size_t len, size_t * olen) +{ + esp_fill_random(output, len); + *olen = len; + return 0; +} + +CHIP_ERROR PlatformManagerImpl::DisableESPEventDispatch() +{ + esp_err_t err = esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent); + if (err != ESP_OK) + { + return Internal::ESP32Utils::MapError(err); + } + err = esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent); + return Internal::ESP32Utils::MapError(err); +} + +CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) +{ + // Arrange for CHIP-encapsulated ESP32 errors to be translated to text + Internal::ESP32Utils::RegisterESP32ErrorFormatter(); + // Make sure the LwIP core lock has been initialized + ReturnErrorOnFailure(Internal::InitLwIPCoreLock()); + + // Initialize TCP/IP network interface, which internally initializes LwIP stack. We have to + // call this before the usage of PacketBufferHandle::New() because in case of LwIP-based pool + // allocator, the LwIP pool allocator uses the LwIP stack. + esp_err_t err = esp_netif_init(); + VerifyOrReturnError(err == ESP_OK, Internal::ESP32Utils::MapError(err)); + +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI + err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent, nullptr); + VerifyOrReturnError(err == ESP_OK, Internal::ESP32Utils::MapError(err)); +#endif + // Arrange for the ESP event loop to deliver events into the CHIP Device layer. + err = esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent, nullptr); + VerifyOrReturnError(err == ESP_OK, Internal::ESP32Utils::MapError(err)); + + mStartTime = System::SystemClock().GetMonotonicTimestamp(); + ReturnErrorOnFailure(chip::Crypto::add_entropy_source(app_entropy_source, nullptr, 16)); + + // Call _InitChipStack() on the generic implementation base class + // to finish the initialization process. + ReturnErrorOnFailure(Internal::GenericPlatformManagerImpl_FreeRTOS::_InitChipStack()); + + ReturnErrorOnFailure(System::Clock::InitClock_RealTime()); + return CHIP_NO_ERROR; +} + +void PlatformManagerImpl::_Shutdown() +{ + uint64_t upTime = 0; + + if (GetDiagnosticDataProvider().GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalOperationalHours = 0; + + if (ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours) == CHIP_NO_ERROR) + { + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + static_cast(upTime / 3600)); + } + else + { + ChipLogError(DeviceLayer, "Failed to get total operational hours of the Node"); + } + } + else + { + ChipLogError(DeviceLayer, "Failed to get current uptime since the Node’s last reboot"); + } + + Internal::GenericPlatformManagerImpl_FreeRTOS::_Shutdown(); + + esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent); + esp_netif_deinit(); +} + +void PlatformManagerImpl::HandleESPSystemEvent(void * arg, esp_event_base_t eventBase, int32_t eventId, void * eventData) +{ + ChipDeviceEvent event; + memset(&event, 0, sizeof(event)); + event.Type = DeviceEventType::kESPSystemEvent; + event.Platform.ESPSystemEvent.Base = eventBase; + event.Platform.ESPSystemEvent.Id = eventId; + if (eventBase == IP_EVENT) + { + ChipLogProgress(DeviceLayer, "Posting ESPSystemEvent: IP Event with eventId : %ld", eventId); + switch (eventId) + { + case IP_EVENT_STA_GOT_IP: + memcpy(&event.Platform.ESPSystemEvent.Data.IpGotIp, eventData, sizeof(event.Platform.ESPSystemEvent.Data.IpGotIp)); + break; + case IP_EVENT_GOT_IP6: + memcpy(&event.Platform.ESPSystemEvent.Data.IpGotIp6, eventData, sizeof(event.Platform.ESPSystemEvent.Data.IpGotIp6)); + break; + case IP_EVENT_AP_STAIPASSIGNED: + memcpy(&event.Platform.ESPSystemEvent.Data.IpApStaIpAssigned, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.IpApStaIpAssigned)); + break; + default: + break; + } + } +#if CHIP_DEVICE_CONFIG_ENABLE_WIFI + else if (eventBase == WIFI_EVENT) + { + ChipLogProgress(DeviceLayer, "Posting ESPSystemEvent: Wifi Event with eventId : %ld", eventId); + switch (eventId) + { + case WIFI_EVENT_SCAN_DONE: + memcpy(&event.Platform.ESPSystemEvent.Data.WiFiStaScanDone, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.WiFiStaScanDone)); + break; + case WIFI_EVENT_STA_CONNECTED: + memcpy(&event.Platform.ESPSystemEvent.Data.WiFiStaConnected, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.WiFiStaConnected)); + break; + case WIFI_EVENT_STA_DISCONNECTED: + memcpy(&event.Platform.ESPSystemEvent.Data.WiFiStaDisconnected, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.WiFiStaDisconnected)); + break; + case WIFI_EVENT_STA_AUTHMODE_CHANGE: + memcpy(&event.Platform.ESPSystemEvent.Data.WiFiStaAuthModeChange, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.WiFiStaAuthModeChange)); + break; + case WIFI_EVENT_STA_WPS_ER_PIN: + memcpy(&event.Platform.ESPSystemEvent.Data.WiFiStaWpsErPin, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.WiFiStaWpsErPin)); + break; + case WIFI_EVENT_STA_WPS_ER_FAILED: + memcpy(&event.Platform.ESPSystemEvent.Data.WiFiStaWpsErFailed, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.WiFiStaWpsErFailed)); + break; + case WIFI_EVENT_AP_STACONNECTED: + memcpy(&event.Platform.ESPSystemEvent.Data.WiFiApStaConnected, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.WiFiApStaConnected)); + break; + case WIFI_EVENT_AP_STADISCONNECTED: + memcpy(&event.Platform.ESPSystemEvent.Data.WiFiApStaDisconnected, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.WiFiApStaDisconnected)); + break; + case WIFI_EVENT_AP_PROBEREQRECVED: + memcpy(&event.Platform.ESPSystemEvent.Data.WiFiApProbeReqRecved, eventData, + sizeof(event.Platform.ESPSystemEvent.Data.WiFiApProbeReqRecved)); + break; + default: + break; + } + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI + else + { + ChipLogProgress(DeviceLayer, "Posting ESPSystemEvent with eventId : %ld", eventId); + } + sInstance.PostEventOrDie(&event); +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/PlatformManagerImpl.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/PlatformManagerImpl.h new file mode 100644 index 000000000..0d99857ef --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/PlatformManagerImpl.h @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2018 Nest Labs, Inc. + * All rights reserved. + * + * 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 PlatformManager object + * for the ESP32 platform. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace DeviceLayer { + +/** + * Concrete implementation of the PlatformManager singleton object for the ESP32 platform. + */ +class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_FreeRTOS +{ + // Allow the PlatformManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend PlatformManager; + + // Allow the generic implementation base class to call helper methods on + // this class. +#ifndef DOXYGEN_SHOULD_SKIP_THIS + friend Internal::GenericPlatformManagerImpl_FreeRTOS; +#endif + +public: + // ===== Platform-specific members that may be accessed directly by the application. + + CHIP_ERROR InitLwIPCoreLock(void); + static void HandleESPSystemEvent(void * arg, esp_event_base_t eventBase, int32_t eventId, void * eventData); + System::Clock::Timestamp GetStartTime() { return mStartTime; } + static CHIP_ERROR DisableESPEventDispatch(); + +private: + // ===== Methods that implement the PlatformManager abstract interface. + + CHIP_ERROR _InitChipStack(void); + void _Shutdown(); + + // ===== Members for internal use by the following friends. + + friend PlatformManager & PlatformMgr(void); + friend PlatformManagerImpl & PlatformMgrImpl(void); + + System::Clock::Timestamp mStartTime = System::Clock::kZero; + + static PlatformManagerImpl sInstance; +}; + +/** + * Returns the public interface of the PlatformManager singleton object. + * + * Chip applications should use this to access features of the PlatformManager object + * that are common to all platforms. + */ +inline PlatformManager & PlatformMgr(void) +{ + return PlatformManagerImpl::sInstance; +} + +/** + * 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 ESP32 platform. + */ +inline PlatformManagerImpl & PlatformMgrImpl(void) +{ + return PlatformManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ScopedNvsHandle.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ScopedNvsHandle.h new file mode 120000 index 000000000..c4767c55e --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ScopedNvsHandle.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ScopedNvsHandle.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/StaticESP32DeviceInfoProvider.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/StaticESP32DeviceInfoProvider.cpp new file mode 120000 index 000000000..1070b4c76 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/StaticESP32DeviceInfoProvider.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/StaticESP32DeviceInfoProvider.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/StaticESP32DeviceInfoProvider.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/StaticESP32DeviceInfoProvider.h new file mode 120000 index 000000000..3d7c948ca --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/StaticESP32DeviceInfoProvider.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/StaticESP32DeviceInfoProvider.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/SystemPlatformConfig.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/SystemPlatformConfig.h new file mode 120000 index 000000000..ada1b59ef --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/SystemPlatformConfig.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/SystemPlatformConfig.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/SystemTimeSupport.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/SystemTimeSupport.cpp new file mode 120000 index 000000000..d9bddb7e3 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/SystemTimeSupport.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/SystemTimeSupport.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/SystemTimeSupport.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/SystemTimeSupport.h new file mode 120000 index 000000000..b5bd16627 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/SystemTimeSupport.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/SystemTimeSupport.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ThreadStackManagerImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/ThreadStackManagerImpl.cpp new file mode 120000 index 000000000..0aea9faf6 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ThreadStackManagerImpl.cpp @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ThreadStackManagerImpl.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/ThreadStackManagerImpl.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/ThreadStackManagerImpl.h new file mode 120000 index 000000000..f0238eeee --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/ThreadStackManagerImpl.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ThreadStackManagerImpl.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/WarmPlatformConfig.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/WarmPlatformConfig.h new file mode 120000 index 000000000..3c6e822ed --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/WarmPlatformConfig.h @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/WarmPlatformConfig.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/bluedroid b/examples/common/secondary_ble_adv/platform/ESP32_custom/bluedroid new file mode 120000 index 000000000..30a45b32d --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/bluedroid @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/bluedroid \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/BLEManagerImpl.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/BLEManagerImpl.cpp new file mode 100644 index 000000000..75328ddb3 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/BLEManagerImpl.cpp @@ -0,0 +1,2046 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * All rights reserved. + * + * 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 ESP32 (NimBLE) platform. + */ +/* this file behaves like a config.h, comes first */ +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +#include "sdkconfig.h" + +#ifdef CONFIG_BT_NIMBLE_ENABLED + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +#include +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + +#include +#include +#include +#include +#include + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +#include +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + +#include +#include +#include + +#include "esp_bt.h" +#include "esp_log.h" + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) +#include "esp_nimble_hci.h" +#endif + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +#include "blecent.h" +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + +#include "host/ble_hs.h" +#include "host/ble_hs_pvcy.h" +#include "host/ble_uuid.h" +#include "host/util/util.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" + +#define MAX_ADV_DATA_LEN 31 +#define CHIP_ADV_DATA_TYPE_FLAGS 0x01 +#define CHIP_ADV_DATA_FLAGS 0x06 +#define CHIP_ADV_DATA_TYPE_SERVICE_DATA 0x16 + +using namespace ::chip; +using namespace ::chip::Ble; + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +namespace { + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +static constexpr uint16_t kNewConnectionScanTimeout = 60; +static constexpr uint16_t kConnectTimeout = 20; +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + +struct ESP32ChipServiceData +{ + uint8_t ServiceUUID[2]; + ChipBLEDeviceIdentificationInfo DeviceIdInfo; +}; + +const ble_uuid16_t ShortUUID_CHIPoBLEService = { BLE_UUID_TYPE_16, 0xFFF6 }; + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +const ble_uuid16_t ShortUUID_CHIPoBLE_CharTx_Desc = { BLE_UUID_TYPE_16, 0x2902 }; +#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + +const ble_uuid128_t UUID128_CHIPoBLEChar_RX = { + BLE_UUID_TYPE_128, { 0x11, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 } +}; + +const ble_uuid128_t UUID_CHIPoBLEChar_TX = { + { BLE_UUID_TYPE_128 }, { 0x12, 0x9D, 0x9F, 0x42, 0x9C, 0x4F, 0x9F, 0x95, 0x59, 0x45, 0x3D, 0x26, 0xF5, 0x2E, 0xEE, 0x18 } +}; + +#ifdef CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING +const ble_uuid128_t UUID_CHIPoBLEChar_C3 = { + { BLE_UUID_TYPE_128 }, { 0x04, 0x8F, 0x21, 0x83, 0x8A, 0x74, 0x7D, 0xB8, 0xF2, 0x45, 0x72, 0x87, 0x38, 0x02, 0x63, 0x64 } +}; +#endif // CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + +SemaphoreHandle_t semaphoreHandle = NULL; + +// LE Random Device Address +// (see Bluetooth® Core Specification 4.2 Vol 6, Part B, Section 1.3.2.1 "Static device address") +uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM; + +} // unnamed namespace + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +ChipDeviceScanner & mDeviceScanner = Internal::ChipDeviceScanner::GetInstance(); +#endif +BLEManagerImpl BLEManagerImpl::sInstance; +const struct ble_gatt_svc_def BLEManagerImpl::CHIPoBLEGATTService = { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = (ble_uuid_t *) (&ShortUUID_CHIPoBLEService), + .characteristics = (struct ble_gatt_chr_def[]){ + { + .uuid = (ble_uuid_t *) (&UUID128_CHIPoBLEChar_RX), + .access_cb = gatt_svr_chr_access, + .flags = BLE_GATT_CHR_F_WRITE, + .val_handle = &sInstance.mRXCharAttrHandle, + }, + { + .uuid = (ble_uuid_t *) (&UUID_CHIPoBLEChar_TX), + .access_cb = gatt_svr_chr_access, + .flags = + BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_INDICATE, + .val_handle = &sInstance.mTXCharCCCDAttrHandle, + }, +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + { + .uuid = (ble_uuid_t *) (&UUID_CHIPoBLEChar_C3), + .access_cb = gatt_svr_chr_access_additional_data, + .flags = BLE_GATT_CHR_F_READ, + .val_handle = &sInstance.mC3CharAttrHandle, + }, +#endif + { + 0, /* No more characteristics in this service */ + }, + } +}; + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +void BLEManagerImpl::HandleConnectFailed(CHIP_ERROR error) +{ + if (sInstance.mIsCentral) + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kPlatformESP32BLECentralConnectFailed; + event.Platform.BLECentralConnectFailed.mError = error; + PlatformMgr().PostEventOrDie(&event); + } +} + +void BLEManagerImpl::CancelConnect(void) +{ + int rc = ble_gap_conn_cancel(); + VerifyOrReturn(rc == 0, ChipLogError(Ble, "Failed to cancel connection rc=%d", rc)); +} + +void BLEManagerImpl::HandleConnectTimeout(chip::System::Layer *, void * context) +{ + CancelConnect(); + BLEManagerImpl::HandleConnectFailed(CHIP_ERROR_TIMEOUT); +} + +void BLEManagerImpl::ConnectDevice(const ble_addr_t & addr, uint16_t timeout) +{ + int rc; + uint8_t ownAddrType; + + rc = ble_hs_id_infer_auto(0, &ownAddrType); + if (rc != 0) + { + ChipLogError(Ble, "Failed to infer own address type rc=%d", rc); + return; + } + + rc = ble_gap_connect(ownAddrType, &addr, (timeout * 1000), NULL, ble_svr_gap_event, NULL); + if (rc != 0) + { + ChipLogError(Ble, "Failed to connect to rc=%d", rc); + } +} +#endif + +CHIP_ERROR BLEManagerImpl::_Init() +{ + CHIP_ERROR err; + + // Initialize the Chip BleLayer. +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + err = BleLayer::Init(this, this, this, &DeviceLayer::SystemLayer()); +#else + err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer()); +#endif + SuccessOrExit(err); + + mRXCharAttrHandle = 0; +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + mC3CharAttrHandle = 0; +#endif + mTXCharCCCDAttrHandle = 0; +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART && !mIsCentral); + mFlags.Set(Flags::kFastAdvertisingEnabled, !mIsCentral); +#else + mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART); + mFlags.Set(Flags::kFastAdvertisingEnabled, true); +#endif + + mNumGAPCons = 0; + memset(reinterpret_cast(mCons), 0, sizeof(mCons)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + memset(mDeviceName, 0, sizeof(mDeviceName)); + + PlatformMgr().ScheduleWork(DriveBLEState, 0); + +exit: + return err; +} + +void BLEManagerImpl::_Shutdown() +{ + CancelBleAdvTimeoutTimer(); + + BleLayer::Shutdown(); + + // selectively setting kGATTServiceStarted flag, in order to notify the state machine to stop the CHIPoBLE GATT service + mFlags.ClearAll().Set(Flags::kGATTServiceStarted); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + + PlatformMgr().ScheduleWork(DriveBLEState, 0); +} + +CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (val) + { + StartBleAdvTimeoutTimer(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME); + } + + mFlags.Set(Flags::kFastAdvertisingEnabled, val); + mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); + mFlags.Set(Flags::kAdvertisingEnabled, val); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + +exit: + return err; +} + +void BLEManagerImpl::BleAdvTimeoutHandler(System::Layer *, void *) +{ + if (BLEMgrImpl().mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + ChipLogProgress(DeviceLayer, "bleAdv Timeout : Start slow advertisement"); + BLEMgrImpl().mFlags.Set(Flags::kFastAdvertisingEnabled, 0); + BLEMgrImpl().mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); + +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + BLEMgrImpl().mFlags.Clear(Flags::kExtAdvertisingEnabled); + BLEMgrImpl().StartBleAdvTimeoutTimer(CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS); +#endif + } +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + else + { + ChipLogProgress(DeviceLayer, "bleAdv Timeout : Start extended advertisement"); + BLEMgrImpl().mFlags.Set(Flags::kAdvertising); + BLEMgrImpl().mFlags.Set(Flags::kExtAdvertisingEnabled); + BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising); + BLEMgrImpl().mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); + } +#endif + PlatformMgr().ScheduleWork(DriveBLEState, 0); +} + +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) +{ + if (strlen(mDeviceName) >= bufSize) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + strcpy(buf, mDeviceName); + return CHIP_NO_ERROR; +} + +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 != NULL && deviceName[0] != 0) + { + if (strlen(deviceName) >= kMaxDeviceNameLength) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + strcpy(mDeviceName, deviceName); + mFlags.Set(Flags::kUseCustomDeviceName); + } + else + { + mDeviceName[0] = 0; + mFlags.Clear(Flags::kUseCustomDeviceName); + } + +exit: + return err; +} + +void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) +{ + switch (event->Type) + { + case DeviceEventType::kCHIPoBLESubscribe: + HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); + { + ChipDeviceEvent connectionEvent; + connectionEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; + PlatformMgr().PostEventOrDie(&connectionEvent); + } + break; + + case DeviceEventType::kCHIPoBLEUnsubscribe: + HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); + break; + + case DeviceEventType::kCHIPoBLEWriteReceived: + HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_1_UUID, + PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); + break; + + case DeviceEventType::kCHIPoBLEIndicateConfirm: + HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); + break; + + case DeviceEventType::kCHIPoBLEConnectionError: + HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); + break; + + case DeviceEventType::kServiceProvisioningChange: + case DeviceEventType::kWiFiConnectivityChange: + // Force the advertising configuration to be refreshed to reflect new provisioning state. + ChipLogProgress(DeviceLayer, "Updating advertising data"); + mFlags.Clear(Flags::kAdvertisingConfigured); + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + + DriveBLEState(); + break; + + default: +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + HandlePlatformSpecificBLEEvent(event); +#endif + break; + } +} + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEvent) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ChipLogProgress(DeviceLayer, "HandlePlatformSpecificBLEEvent %d", apEvent->Type); + + switch (apEvent->Type) + { + case DeviceEventType::kPlatformESP32BLECentralConnected: + if (BLEManagerImpl::mBLEScanConfig.mBleScanState == BleScanState::kConnecting) + { + BleConnectionDelegate::OnConnectionComplete(mBLEScanConfig.mAppState, + apEvent->Platform.BLECentralConnected.mConnection); + CleanScanConfig(); + } + break; + + case DeviceEventType::kPlatformESP32BLECentralConnectFailed: + if (BLEManagerImpl::mBLEScanConfig.mBleScanState == BleScanState::kConnecting) + { + BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, apEvent->Platform.BLECentralConnectFailed.mError); + CleanScanConfig(); + } + break; + + case DeviceEventType::kPlatformESP32BLEWriteComplete: + HandleWriteConfirmation(apEvent->Platform.BLEWriteComplete.mConnection, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_1_UUID); + break; + + case DeviceEventType::kPlatformESP32BLESubscribeOpComplete: + if (apEvent->Platform.BLESubscribeOpComplete.mIsSubscribed) + HandleSubscribeComplete(apEvent->Platform.BLESubscribeOpComplete.mConnection, &CHIP_BLE_SVC_ID, + &Ble::CHIP_BLE_CHAR_2_UUID); + else + HandleUnsubscribeComplete(apEvent->Platform.BLESubscribeOpComplete.mConnection, &CHIP_BLE_SVC_ID, + &Ble::CHIP_BLE_CHAR_2_UUID); + break; + + case DeviceEventType::kPlatformESP32BLEIndicationReceived: + HandleIndicationReceived(apEvent->Platform.BLEIndicationReceived.mConnection, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID, + PacketBufferHandle::Adopt(apEvent->Platform.BLEIndicationReceived.mData)); + break; + + default: + break; + } + + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + } +} + +static int OnUnsubscribeCharComplete(uint16_t conn_handle, const struct ble_gatt_error * error, struct ble_gatt_attr * attr, + void * arg) +{ + ChipLogProgress(DeviceLayer, "Subscribe complete: conn_handle=%d, error=%d, attr_handle=%d", conn_handle, error->status, + attr->handle); + + ChipDeviceEvent event; + event.Type = DeviceEventType::kPlatformESP32BLESubscribeOpComplete; + event.Platform.BLESubscribeOpComplete.mConnection = conn_handle; + event.Platform.BLESubscribeOpComplete.mIsSubscribed = false; + PlatformMgr().PostEventOrDie(&event); + + return 0; +} + +static int OnSubscribeCharComplete(uint16_t conn_handle, const struct ble_gatt_error * error, struct ble_gatt_attr * attr, + void * arg) +{ + ChipLogProgress(DeviceLayer, "Subscribe complete: conn_handle=%d, error=%d, attr_handle=%d", conn_handle, error->status, + attr->handle); + + ChipDeviceEvent event; + event.Type = DeviceEventType::kPlatformESP32BLESubscribeOpComplete; + event.Platform.BLESubscribeOpComplete.mConnection = conn_handle; + event.Platform.BLESubscribeOpComplete.mIsSubscribed = true; + PlatformMgr().PostEventOrDie(&event); + + return 0; +} +#endif + +CHIP_ERROR BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, + const ChipBleUUID * charId) +{ +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + const struct peer_dsc * dsc; + uint8_t value[2]; + int rc; + struct peer * peer = peer_find(conId); + if (peer == nullptr) + { + return BLE_ERROR_GATT_SUBSCRIBE_FAILED; + } + + dsc = peer_dsc_find_uuid(peer, (ble_uuid_t *) (&ShortUUID_CHIPoBLEService), (ble_uuid_t *) (&UUID_CHIPoBLEChar_TX), + (ble_uuid_t *) (&ShortUUID_CHIPoBLE_CharTx_Desc)); + + if (dsc == nullptr) + { + ChipLogError(Ble, "Peer does not have CCCD"); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return BLE_ERROR_GATT_SUBSCRIBE_FAILED; + } + + value[0] = 0x02; + value[1] = 0x00; + + rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle, value, sizeof(value), OnSubscribeCharComplete, NULL); + if (rc != 0) + { + ChipLogError(Ble, "ble_gattc_write_flat failed: %d", rc); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return BLE_ERROR_GATT_SUBSCRIBE_FAILED; + } + return CHIP_NO_ERROR; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif +} + +CHIP_ERROR BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, + const ChipBleUUID * charId) +{ +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + const struct peer_dsc * dsc; + uint8_t value[2]; + int rc; + struct peer * peer = peer_find(conId); + if (peer == nullptr) + { + return BLE_ERROR_GATT_UNSUBSCRIBE_FAILED; + } + + dsc = peer_dsc_find_uuid(peer, (ble_uuid_t *) (&ShortUUID_CHIPoBLEService), (ble_uuid_t *) (&UUID_CHIPoBLEChar_TX), + (ble_uuid_t *) (&ShortUUID_CHIPoBLE_CharTx_Desc)); + + if (dsc == nullptr) + { + ChipLogError(Ble, "Peer does not have CCCD"); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return BLE_ERROR_GATT_UNSUBSCRIBE_FAILED; + } + + value[0] = 0x00; + value[1] = 0x00; + + rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle, value, sizeof(value), OnUnsubscribeCharComplete, NULL); + if (rc != 0) + { + ChipLogError(Ble, "ble_gattc_write_flat failed: %d", rc); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return BLE_ERROR_GATT_UNSUBSCRIBE_FAILED; + } + return CHIP_NO_ERROR; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif +} + +CHIP_ERROR BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId) +{ + CHIP_ERROR err; + + ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId); + + // Signal the ESP BLE layer to close the conneecction. + err = MapBLEError(ble_gap_terminate(conId, BLE_ERR_REM_USER_CONN_TERM)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_terminate() failed: %s", ErrorStr(err)); + } + +#ifndef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + // Force a refresh of the advertising state. + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + mFlags.Clear(Flags::kAdvertisingConfigured); + PlatformMgr().ScheduleWork(DriveBLEState, 0); +#endif + + return err; +} + +uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const +{ + return ble_att_mtu(conId); +} + +CHIP_ERROR BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + chip::System::PacketBufferHandle data) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + struct os_mbuf * om; + + VerifyOrExit(IsSubscribed(conId), err = CHIP_ERROR_INVALID_ARGUMENT); + + ESP_LOGD(TAG, "Sending indication for CHIPoBLE TX characteristic (con %u, len %u)", conId, data->DataLength()); + + // For BLE, the buffer is capped at UINT16_MAX. Nevertheless, have a verify + // check before the cast to uint16_t. + VerifyOrExit(CanCastTo(data->DataLength()), err = CHIP_ERROR_MESSAGE_TOO_LONG); + + om = ble_hs_mbuf_from_flat(data->Start(), static_cast(data->DataLength())); + if (om == NULL) + { + ChipLogError(DeviceLayer, "ble_hs_mbuf_from_flat failed:"); + err = CHIP_ERROR_NO_MEMORY; + ExitNow(); + } + + err = MapBLEError(ble_gattc_indicate_custom(conId, mTXCharCCCDAttrHandle, om)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gattc_indicate_custom() failed: %s", ErrorStr(err)); + ExitNow(); + } + +exit: + return err; +} + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +static int OnWriteComplete(uint16_t conn_handle, const struct ble_gatt_error * error, struct ble_gatt_attr * attr, void * arg) +{ + ChipLogDetail(Ble, "Write complete; status:%d conn_handle:%d attr_handle:%d", error->status, conn_handle, attr->handle); + ChipDeviceEvent event; + event.Type = DeviceEventType::kPlatformESP32BLEWriteComplete; + event.Platform.BLEWriteComplete.mConnection = conn_handle; + CHIP_ERROR err = PlatformMgr().PostEvent(&event); + if (err != CHIP_NO_ERROR) + { + return 1; + } + + return 0; +} +#endif + +CHIP_ERROR BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + chip::System::PacketBufferHandle pBuf) +{ +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + const struct peer_chr * chr; + int rc; + const struct peer * peer = peer_find(conId); + + chr = peer_chr_find_uuid(peer, (ble_uuid_t *) (&ShortUUID_CHIPoBLEService), (ble_uuid_t *) (&UUID128_CHIPoBLEChar_RX)); + if (chr == nullptr) + { + ChipLogError(Ble, "Peer does not have RX characteristic"); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return BLE_ERROR_GATT_WRITE_FAILED; + } + + if (pBuf->DataLength() > UINT16_MAX) + { + ChipLogError(Ble, "Buffer data Length is too long"); + return CHIP_ERROR_INVALID_ARGUMENT; + } + rc = ble_gattc_write_flat(conId, chr->chr.val_handle, pBuf->Start(), static_cast(pBuf->DataLength()), OnWriteComplete, + this); + if (rc != 0) + { + ChipLogError(Ble, "ble_gattc_write_flat failed: %d", rc); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return BLE_ERROR_GATT_WRITE_FAILED; + } + return CHIP_NO_ERROR; +#else + return CHIP_ERROR_NOT_IMPLEMENTED; +#endif +} + +void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) +{ + ChipLogDetail(Ble, "Received notification of closed CHIPoBLE connection (con %u)", conId); + CloseConnection(conId); +} + +CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr) +{ + switch (bleErr) + { + case ESP_OK: + return CHIP_NO_ERROR; + case BLE_HS_EMSGSIZE: + return CHIP_ERROR_BUFFER_TOO_SMALL; + case BLE_HS_ENOMEM: + case ESP_ERR_NO_MEM: + return CHIP_ERROR_NO_MEMORY; + case BLE_HS_ENOTCONN: + return CHIP_ERROR_NOT_CONNECTED; + case BLE_HS_ENOTSUP: + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + case BLE_HS_EAPP: + return CHIP_ERROR_INCORRECT_STATE; + case BLE_HS_EBADDATA: + return CHIP_ERROR_DATA_NOT_ALIGNED; + case BLE_HS_ETIMEOUT: + return CHIP_ERROR_TIMEOUT; + case BLE_HS_ENOADDR: + return CHIP_ERROR_INVALID_ADDRESS; + case ESP_ERR_INVALID_ARG: + return CHIP_ERROR_INVALID_ARGUMENT; + default: + return CHIP_ERROR(ChipError::Range::kPlatform, CHIP_DEVICE_CONFIG_ESP32_BLE_ERROR_MIN + bleErr); + } +} +void BLEManagerImpl::CancelBleAdvTimeoutTimer(void) +{ + if (SystemLayer().IsTimerActive(BleAdvTimeoutHandler, nullptr)) + { + SystemLayer().CancelTimer(BleAdvTimeoutHandler, nullptr); + } +} +void BLEManagerImpl::StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs) +{ + CancelBleAdvTimeoutTimer(); + + CHIP_ERROR err = SystemLayer().StartTimer(System::Clock::Milliseconds32(aTimeoutInMs), BleAdvTimeoutHandler, nullptr); + if ((err != CHIP_NO_ERROR)) + { + ChipLogError(DeviceLayer, "Failed to start BledAdv timeout timer"); + } +} +void BLEManagerImpl::DriveBLEState(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Perform any initialization actions that must occur after the Chip task is running. + if (!mFlags.Has(Flags::kAsyncInitCompleted)) + { + mFlags.Set(Flags::kAsyncInitCompleted); + } + + // Initializes the ESP BLE layer if needed. + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && !mFlags.Has(Flags::kESPBLELayerInitialized)) + { + err = InitESPBleLayer(); + SuccessOrExit(err); + + // Add delay of 500msec while NimBLE host task gets up and running + { + vTaskDelay(500 / portTICK_PERIOD_MS); + } + } + + // If the application has enabled CHIPoBLE and BLE advertising... + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && + mFlags.Has(Flags::kAdvertisingEnabled) +#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 of the + // ESP BLE layer needs to be refreshed. + if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kAdvertisingRefreshNeeded)) + { + // Configure advertising data if it hasn't been done yet. This is an asynchronous step which + // must complete before advertising can be started. When that happens, this method will + // be called again, and execution will proceed to the code below. + if (!mFlags.Has(Flags::kAdvertisingConfigured)) + { + err = ConfigureAdvertisingData(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Configure Adv Data failed: %s", ErrorStr(err)); + ExitNow(); + } + err = ConfigureSecondaryAdvertisingData(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Configure secondary Adv Data failed: %s", ErrorStr(err)); + ExitNow(); + } + } + + // Start advertising. This is also an asynchronous step. + ESP_LOGD(TAG, "NimBLE start advertising..."); + err = StartAdvertising(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Start advertising failed: %s", ErrorStr(err)); + ExitNow(); + } + err = StartSecondaryAdvertising(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Start secondary advertising failed: %s", ErrorStr(err)); + ExitNow(); + } + + mFlags.Clear(Flags::kAdvertisingRefreshNeeded); + // Transition to the Advertising state... + if (!mFlags.Has(Flags::kAdvertising)) + { + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising started"); + + mFlags.Set(Flags::kAdvertising); + + // Post a CHIPoBLEAdvertisingChange(Started) event. + { + ChipDeviceEvent advChange; + advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started; + err = PlatformMgr().PostEvent(&advChange); + } + } + } + } + + // Otherwise stop advertising if needed... + else + { + if (mFlags.Has(Flags::kAdvertising)) + { + if (ble_gap_ext_adv_active(kChipAdvInstance)) + { + err = MapBLEError(ble_gap_ext_adv_stop(kChipAdvInstance)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_stop() failed: %s", ErrorStr(err)); + ExitNow(); + } + } + + // Transition to the not Advertising state... + mFlags.Clear(Flags::kAdvertising); + mFlags.Set(Flags::kFastAdvertisingEnabled, true); + + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); + + CancelBleAdvTimeoutTimer(); + + // Post a CHIPoBLEAdvertisingChange(Stopped) event. + { + ChipDeviceEvent advChange; + advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; + err = PlatformMgr().PostEvent(&advChange); + } + + ExitNow(); + } + } + + // Stop the CHIPoBLE GATT service if needed. + if (mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kGATTServiceStarted)) + { + DeinitESPBleLayer(); + mFlags.ClearAll(); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + } +} + +void BLEManagerImpl::bleprph_on_reset(int reason) +{ + ESP_LOGE(TAG, "Resetting state; reason=%d\n", reason); +} + +CHIP_ERROR BLEManagerImpl::bleprph_set_random_addr(void) +{ + ble_addr_t addr; + + // Generates a new static random address + int rc = ble_hs_id_gen_rnd(0, &addr); + if (rc != 0) + { + ESP_LOGE(TAG, "Failed to generate random address err: %d", rc); + return CHIP_ERROR_INTERNAL; + } + // Set generated address + rc = ble_hs_id_set_rnd(addr.val); + if (rc != 0) + { + ESP_LOGE(TAG, "Failed to set random address err: %d", rc); + return CHIP_ERROR_INTERNAL; + } + // Try to configure the device with random static address + rc = ble_hs_util_ensure_addr(1); + if (rc != 0) + { + ESP_LOGE(TAG, "Failed to configure random address err: %d", rc); + return CHIP_ERROR_INTERNAL; + } + return CHIP_NO_ERROR; +} + +void BLEManagerImpl::bleprph_on_sync(void) +{ + ESP_LOGI(TAG, "BLE host-controller synced"); + xSemaphoreGive(semaphoreHandle); +} + +void BLEManagerImpl::bleprph_host_task(void * param) +{ + ESP_LOGD(TAG, "BLE Host Task Started"); + /* This function will return only when nimble_port_stop() is executed */ + nimble_port_run(); + nimble_port_freertos_deinit(); +} + +CHIP_ERROR BLEManagerImpl::InitESPBleLayer(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(!mFlags.Has(Flags::kESPBLELayerInitialized), /* */); + + semaphoreHandle = xSemaphoreCreateBinary(); + if (semaphoreHandle == NULL) + { + err = CHIP_ERROR_NO_MEMORY; + ESP_LOGE(TAG, "Failed to create semaphore"); + ExitNow(); + } + + for (int i = 0; i < kMaxConnections; i++) + { + mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; + } +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + err = MapBLEError(esp_nimble_hci_and_controller_init()); + SuccessOrExit(err); +#endif + + nimble_port_init(); + + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = bleprph_on_reset; + ble_hs_cfg.sync_cb = bleprph_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + ble_hs_cfg.sm_bonding = 1; + ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID; + ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID; + + // Register the CHIPoBLE GATT attributes with the ESP BLE layer if needed. + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled) + { + ble_svc_gap_init(); + ble_svc_gatt_init(); + + mGATTServices[1 - mSecondGATTServiceIndex] = CHIPoBLEGATTService; + err = MapBLEError(ble_gatts_count_cfg(mGATTServices)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gatts_count_cfg failed: %s", ErrorStr(err)); + ExitNow(); + } + + err = MapBLEError(ble_gatts_add_svcs(mGATTServices)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gatts_add_svcs failed: %s", ErrorStr(err)); + ExitNow(); + } + } + + nimble_port_freertos_init(bleprph_host_task); + + xSemaphoreTake(semaphoreHandle, portMAX_DELAY); + vSemaphoreDelete(semaphoreHandle); + semaphoreHandle = NULL; + + sInstance.mFlags.Set(Flags::kESPBLELayerInitialized); + sInstance.mFlags.Set(Flags::kGATTServiceStarted); + + err = bleprph_set_random_addr(); +exit: + return err; +} + +void BLEManagerImpl::DeinitESPBleLayer() +{ + VerifyOrReturn(DeinitBLE() == CHIP_NO_ERROR); + BLEManagerImpl::ClaimBLEMemory(nullptr, nullptr); +} + +void BLEManagerImpl::ClaimBLEMemory(System::Layer *, void *) +{ + TaskHandle_t handle = xTaskGetHandle("nimble_host"); + if (handle) + { + ChipLogDetail(DeviceLayer, "Schedule ble memory reclaiming since nimble host is still running"); + + // Rescheduling it for later, 2 seconds is an arbitrary value, keeping it a bit more so that + // we dont have to reschedule it again + SystemLayer().StartTimer(System::Clock::Seconds32(2), ClaimBLEMemory, nullptr); + } + else + { + // Free up all the space occupied by ble and add it to heap + esp_err_t err = ESP_OK; + +#ifdef CONFIG_IDF_TARGET_ESP32 + err = esp_bt_mem_release(ESP_BT_MODE_BTDM); +#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) || \ + defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) + err = esp_bt_mem_release(ESP_BT_MODE_BLE); +#endif + + VerifyOrReturn(err == ESP_OK, ChipLogError(DeviceLayer, "BLE deinit failed")); + ChipLogProgress(DeviceLayer, "BLE deinit successful and memory reclaimed"); + + ChipDeviceEvent event; + event.Type = DeviceEventType::kBLEDeinitialized; + VerifyOrDo(CHIP_NO_ERROR == PlatformMgr().PostEvent(&event), ChipLogError(DeviceLayer, "Failed to post BLE deinit event")); + } +} + +CHIP_ERROR BLEManagerImpl::DeinitBLE() +{ + esp_err_t err = ESP_OK; + VerifyOrReturnError(ble_hs_is_enabled(), CHIP_ERROR_INCORRECT_STATE, ChipLogProgress(DeviceLayer, "BLE already deinited")); + VerifyOrReturnError(0 == nimble_port_stop(), MapBLEError(ESP_FAIL), ChipLogError(DeviceLayer, "nimble_port_stop() failed")); + + nimble_port_deinit(); + +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) + err = esp_nimble_hci_and_controller_deinit(); +#endif + + return MapBLEError(err); +} + +CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) +{ + CHIP_ERROR err; + uint8_t index = 0; + + constexpr uint8_t kServiceDataTypeSize = 1; + + chip::Ble::ChipBLEDeviceIdentificationInfo deviceIdInfo; + + // If a custom device name has not been specified, generate a CHIP-standard name based on the + // bottom digits of the Chip device id. + uint16_t discriminator; + SuccessOrExit(err = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator)); + + if (!mFlags.Has(Flags::kUseCustomDeviceName)) + { + snprintf(mDeviceName, sizeof(mDeviceName), "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator); + mDeviceName[kMaxDeviceNameLength] = 0; + } + + // Configure the BLE device name. + err = MapBLEError(ble_svc_gap_device_name_set(mDeviceName)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_svc_gap_device_name_set() failed: %s", ErrorStr(err)); + ExitNow(); + } + + memset(mAdvData, 0, sizeof(mAdvData)); + mAdvData[index++] = 0x02; // length + mAdvData[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags + mAdvData[index++] = CHIP_ADV_DATA_FLAGS; // AD value + mAdvData[index++] = kServiceDataTypeSize + sizeof(ESP32ChipServiceData); // length + mAdvData[index++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type: (Service Data - 16-bit UUID) + mAdvData[index++] = static_cast(ShortUUID_CHIPoBLEService.value & 0xFF); // AD value + mAdvData[index++] = static_cast((ShortUUID_CHIPoBLEService.value >> 8) & 0xFF); // AD value + + err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "GetBLEDeviceIdentificationInfo(): %s", ErrorStr(err)); + ExitNow(); + } + +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + // Check for extended advertisement interval and redact VID/PID if past the initial period. + if (mFlags.Has(Flags::kExtAdvertisingEnabled)) + { + deviceIdInfo.SetVendorId(0); + deviceIdInfo.SetProductId(0); + deviceIdInfo.SetExtendedAnnouncementFlag(true); + } +#endif + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + if (!mFlags.Has(Flags::kExtAdvertisingEnabled)) + { + deviceIdInfo.SetAdditionalDataFlag(true); + } + else + { + deviceIdInfo.SetAdditionalDataFlag(false); + } +#endif + + VerifyOrExit(index + sizeof(deviceIdInfo) <= sizeof(mAdvData), err = CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG); + memcpy(&mAdvData[index], &deviceIdInfo, sizeof(deviceIdInfo)); + index = static_cast(index + sizeof(deviceIdInfo)); + + mAdvDataLen = index; +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::ConfigureScanResponseData(ByteSpan data) +{ + if (data.empty() || data.size() > MAX_SCAN_RSP_DATA_LEN) + { + ChipLogError(DeviceLayer, "scan response data is invalid"); + return CHIP_ERROR_INVALID_ARGUMENT; + } + memcpy(scanResponseBuffer, data.data(), data.size()); + ByteSpan scanResponseSpan(scanResponseBuffer); + mScanResponse = chip::Optional(scanResponseSpan); + return CHIP_NO_ERROR; +} + +void BLEManagerImpl::ClearScanResponseData(void) +{ + mScanResponse.ClearValue(); + ChipLogDetail(DeviceLayer, "scan response data is cleared"); +} + +void BLEManagerImpl::HandleRXCharWrite(struct ble_gatt_char_context * param) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + uint16_t data_len = 0; + + ESP_LOGI(TAG, "Write request received for CHIPoBLE RX characteristic con %u %u", param->conn_handle, param->attr_handle); + + // Copy the data to a packet buffer. + data_len = OS_MBUF_PKTLEN(param->ctxt->om); + PacketBufferHandle buf = System::PacketBufferHandle::New(data_len, 0); + VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY); + VerifyOrExit(buf->AvailableDataLength() >= data_len, err = CHIP_ERROR_BUFFER_TOO_SMALL); + ble_hs_mbuf_to_flat(param->ctxt->om, buf->Start(), data_len, NULL); + buf->SetDataLength(data_len); + + // Post an event to the Chip queue to deliver the data into the Chip stack. + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEWriteReceived; + event.CHIPoBLEWriteReceived.ConId = param->conn_handle; + event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease(); + err = PlatformMgr().PostEvent(&event); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err)); + } +} + +void BLEManagerImpl::HandleTXCharRead(struct ble_gatt_char_context * param) +{ + /* Not supported */ + ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharRead() not supported"); +} + +void BLEManagerImpl::HandleTXCharCCCDRead(void * param) +{ + /* Not Supported */ + ChipLogError(DeviceLayer, "BLEManagerImpl::HandleTXCharCCCDRead() not supported"); +} + +void BLEManagerImpl::HandleTXCharCCCDWrite(struct ble_gap_event * gapEvent) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + bool indicationsEnabled; + + ChipLogProgress(DeviceLayer, + "Write request/command received for CHIPoBLE TX CCCD characteristic (con %u" + " ) indicate = %d", + gapEvent->subscribe.conn_handle, gapEvent->subscribe.cur_indicate); + + // Determine if the client is enabling or disabling indications. + indicationsEnabled = gapEvent->subscribe.cur_indicate; + + // If the client has requested to enabled indications + if (indicationsEnabled) + { + // If indications are not already enabled for the connection... + if (!IsSubscribed(gapEvent->subscribe.conn_handle)) + { + // Record that indications have been enabled for this connection. If this fails because + err = SetSubscribed(gapEvent->subscribe.conn_handle); + VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); + SuccessOrExit(err); + } + } + + else + { + // If indications had previously been enabled for this connection, record that they are no longer + // enabled. + UnsetSubscribed(gapEvent->subscribe.conn_handle); + } + + // Post an event to the Chip queue to process either a CHIPoBLE Subscribe or Unsubscribe based on + // whether the client is enabling or disabling indications. + { + ChipDeviceEvent event; + event.Type = (indicationsEnabled) ? DeviceEventType::kCHIPoBLESubscribe : DeviceEventType::kCHIPoBLEUnsubscribe; + event.CHIPoBLESubscribe.ConId = gapEvent->subscribe.conn_handle; + err = PlatformMgr().PostEvent(&event); + } + + ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", (indicationsEnabled) ? "subscribe" : "unsubscribe"); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err)); + // TODO: fail connection??? + } + + return; +} + +CHIP_ERROR BLEManagerImpl::HandleTXComplete(struct ble_gap_event * gapEvent) +{ + ChipLogProgress(DeviceLayer, "Confirm received for CHIPoBLE TX characteristic indication (con %u) status= %d ", + gapEvent->notify_tx.conn_handle, gapEvent->notify_tx.status); + + // Signal the BLE Layer that the outstanding indication is complete. + if (gapEvent->notify_tx.status == BLE_HS_EDONE) + { + // Post an event to the Chip queue to process the indicate confirmation. + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm; + event.CHIPoBLEIndicateConfirm.ConId = gapEvent->notify_tx.conn_handle; + ReturnErrorOnFailure(PlatformMgr().PostEvent(&event)); + } + + else + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEConnectionError; + event.CHIPoBLEConnectionError.ConId = gapEvent->notify_tx.conn_handle; + event.CHIPoBLEConnectionError.Reason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; + ReturnErrorOnFailure(PlatformMgr().PostEvent(&event)); + } + + return CHIP_NO_ERROR; +} + +uint16_t BLEManagerImpl::_NumConnections(void) +{ + uint16_t numCons = 0; + for (uint16_t i = 0; i < kMaxConnections; i++) + { + if (mSubscribedConIds[i] != BLE_CONNECTION_UNINITIALIZED) + { + numCons++; + } + } + + return numCons; +} + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +void BLEManagerImpl::HandleGAPConnectionFailed(struct ble_gap_event * gapEvent, CHIP_ERROR error) +{ + ChipLogError(Ble, "BLE GAP connection failed; status:%d", gapEvent->connect.status); + if (sInstance.mIsCentral) + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kPlatformESP32BLECentralConnectFailed; + event.Platform.BLECentralConnectFailed.mError = error; + PlatformMgr().PostEventOrDie(&event); + } +} + +void BLEManagerImpl::OnGattDiscComplete(const struct peer * peer, int status, void * arg) +{ + if (status != 0) + { + ChipLogError(Ble, "GATT discovery failed; status:%d", status); + ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM); + return; + } + + ChipLogProgress(Ble, "GATT discovery complete status:%d conn_handle:%d", status, peer->conn_handle); + + ChipDeviceEvent event; + event.Type = DeviceEventType::kPlatformESP32BLECentralConnected; + event.Platform.BLECentralConnected.mConnection = peer->conn_handle; + PlatformMgr().PostEventOrDie(&event); +} + +CHIP_ERROR BLEManagerImpl::HandleGAPCentralConnect(struct ble_gap_event * gapEvent) +{ + if (BLEManagerImpl::mBLEScanConfig.mBleScanState == BleScanState::kConnecting) + { + if (gapEvent->connect.status == 0) + { + // Track the number of active GAP connections. + mNumGAPCons++; + + ChipLogProgress(DeviceLayer, "BLE GAP connection established (con %u)", gapEvent->connect.conn_handle); + + // remember the peer + int rc = peer_add(gapEvent->connect.conn_handle); + if (rc != 0) + { + HandleGAPConnectionFailed(gapEvent, CHIP_ERROR_INTERNAL); + ChipLogError(DeviceLayer, "peer_add failed: %d", rc); + return CHIP_ERROR_INTERNAL; + } + + // Start the GATT discovery process + rc = peer_disc_all(gapEvent->connect.conn_handle, OnGattDiscComplete, NULL); + if (rc != 0) + { + HandleGAPConnectionFailed(gapEvent, CHIP_ERROR_INTERNAL); + ChipLogError(DeviceLayer, "peer_disc_al failed: %d", rc); + return CHIP_ERROR_INTERNAL; + } + } + else + { + HandleGAPConnectionFailed(gapEvent, CHIP_ERROR_INTERNAL); + return CHIP_ERROR_INTERNAL; + } + } + return CHIP_NO_ERROR; +} +#endif + +CHIP_ERROR BLEManagerImpl::HandleGAPPeripheralConnect(struct ble_gap_event * gapEvent) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + ChipLogProgress(DeviceLayer, "BLE GAP connection established (con %u)", gapEvent->connect.conn_handle); + + // Track the number of active GAP connections. + mNumGAPCons++; + err = SetSubscribed(gapEvent->connect.conn_handle); + VerifyOrExit(err != CHIP_ERROR_NO_MEMORY, err = CHIP_NO_ERROR); + SuccessOrExit(err); + + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + mFlags.Clear(Flags::kAdvertisingConfigured); + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::HandleGAPConnect(struct ble_gap_event * gapEvent) +{ +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + int rc; + + rc = ble_gattc_exchange_mtu(gapEvent->connect.conn_handle, NULL, NULL); + if (rc != 0) + { + return CHIP_ERROR_INTERNAL; + } + + return HandleGAPCentralConnect(gapEvent); +#else + return HandleGAPPeripheralConnect(gapEvent); +#endif +} + +CHIP_ERROR BLEManagerImpl::HandleGAPDisconnect(struct ble_gap_event * gapEvent) +{ + ChipLogProgress(DeviceLayer, "BLE GAP connection terminated (con %u reason 0x%02x)", gapEvent->disconnect.conn.conn_handle, + gapEvent->disconnect.reason); + + // Update the number of GAP connections. + if (mNumGAPCons > 0) + { + mNumGAPCons--; + } + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + peer_delete(gapEvent->disconnect.conn.conn_handle); +#endif + + // There can be a case where the BLE central disconnects without unsubscribing from the BLE characteristic. + // In such situations, it is necessary to clear the subscription and post a connection error event. + if (UnsetSubscribed(gapEvent->disconnect.conn.conn_handle)) + { + CHIP_ERROR disconReason; + switch (gapEvent->disconnect.reason) + { + case BLE_ERR_REM_USER_CONN_TERM: + disconReason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; + break; + case BLE_ERR_CONN_TERM_LOCAL: + disconReason = BLE_ERROR_APP_CLOSED_CONNECTION; + break; + default: + disconReason = BLE_ERROR_CHIPOBLE_PROTOCOL_ABORT; + break; + } + + ChipDeviceEvent connectionErrorEvent; + connectionErrorEvent.Type = DeviceEventType::kCHIPoBLEConnectionError; + connectionErrorEvent.CHIPoBLEConnectionError.ConId = gapEvent->disconnect.conn.conn_handle; + connectionErrorEvent.CHIPoBLEConnectionError.Reason = disconReason; + ReturnErrorOnFailure(PlatformMgr().PostEvent(&connectionErrorEvent)); + } + + ChipDeviceEvent disconnectEvent; + disconnectEvent.Type = DeviceEventType::kCHIPoBLEConnectionClosed; + ReturnErrorOnFailure(PlatformMgr().PostEvent(&disconnectEvent)); + + // Force a reconfiguration of advertising in case we switched to non-connectable mode when + // the BLE connection was established. + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + mFlags.Clear(Flags::kAdvertisingConfigured); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR BLEManagerImpl::SetSubscribed(uint16_t conId) +{ + uint16_t freeIndex = kMaxConnections; + + for (uint16_t i = 0; i < kMaxConnections; i++) + { + if (mSubscribedConIds[i] == conId) + { + return CHIP_NO_ERROR; + } + else if (mSubscribedConIds[i] == BLE_CONNECTION_UNINITIALIZED && i < freeIndex) + { + freeIndex = i; + } + } + + if (freeIndex < kMaxConnections) + { + mSubscribedConIds[freeIndex] = conId; + return CHIP_NO_ERROR; + } + else + { + return CHIP_ERROR_NO_MEMORY; + } +} + +bool BLEManagerImpl::UnsetSubscribed(uint16_t conId) +{ + for (uint16_t i = 0; i < kMaxConnections; i++) + { + if (mSubscribedConIds[i] == conId) + { + mSubscribedConIds[i] = BLE_CONNECTION_UNINITIALIZED; + return true; + } + } + return false; +} + +bool BLEManagerImpl::IsSubscribed(uint16_t conId) +{ + if (conId != BLE_CONNECTION_UNINITIALIZED) + { + for (uint16_t i = 0; i < kMaxConnections; i++) + { + if (mSubscribedConIds[i] == conId) + { + return true; + } + } + } + return false; +} + +int BLEManagerImpl::ble_svr_gap_event(struct ble_gap_event * event, void * arg) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + switch (event->type) + { + case BLE_GAP_EVENT_CONNECT: + /* A new connection was established or a connection attempt failed */ + err = sInstance.HandleGAPConnect(event); + SuccessOrExit(err); + break; + + case BLE_GAP_EVENT_DISCONNECT: + err = sInstance.HandleGAPDisconnect(event); + SuccessOrExit(err); + break; + + case BLE_GAP_EVENT_ADV_COMPLETE: + ESP_LOGD(TAG, "BLE_GAP_EVENT_ADV_COMPLETE event"); + break; + + case BLE_GAP_EVENT_SUBSCRIBE: + if (event->subscribe.attr_handle == sInstance.mTXCharCCCDAttrHandle) + { + sInstance.HandleTXCharCCCDWrite(event); + } + + break; + + case BLE_GAP_EVENT_NOTIFY_TX: + if (event->notify_tx.status != 0) + { + err = sInstance.HandleTXComplete(event); + SuccessOrExit(err); + } + break; + + case BLE_GAP_EVENT_MTU: + ESP_LOGD(TAG, "BLE_GAP_EVENT_MTU = %d channel id = %d", event->mtu.value, event->mtu.channel_id); + break; + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER + case BLE_GAP_EVENT_NOTIFY_RX: + ESP_LOGD(TAG, "BLE_GAP_EVENT_NOTIFY_RX received %s conn_handle:%d attr_handle:%d attr_len:%d", + event->notify_rx.indication ? "indication" : "notification", event->notify_rx.conn_handle, + event->notify_rx.attr_handle, OS_MBUF_PKTLEN(event->notify_rx.om)); + err = sInstance.HandleRXNotify(event); + SuccessOrExit(err); + break; +#endif + default: + break; + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); + sInstance.mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + } + + // Schedule DriveBLEState() to run. + PlatformMgr().ScheduleWork(DriveBLEState, 0); + + return err.AsInteger(); +} + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING +void BLEManagerImpl::HandleC3CharRead(struct ble_gatt_char_context * param) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::System::PacketBufferHandle bufferHandle; + + BitFlags additionalDataFields; + AdditionalDataPayloadGeneratorParams additionalDataPayloadParams; + +#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) + uint8_t rotatingDeviceIdUniqueId[ConfigurationManager::kRotatingDeviceIDUniqueIDLength] = {}; + MutableByteSpan rotatingDeviceIdUniqueIdSpan(rotatingDeviceIdUniqueId); + + err = DeviceLayer::GetDeviceInstanceInfoProvider()->GetRotatingDeviceIdUniqueId(rotatingDeviceIdUniqueIdSpan); + SuccessOrExit(err); + err = ConfigurationMgr().GetLifetimeCounter(additionalDataPayloadParams.rotatingDeviceIdLifetimeCounter); + SuccessOrExit(err); + additionalDataPayloadParams.rotatingDeviceIdUniqueId = rotatingDeviceIdUniqueIdSpan; + additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId); +#endif /* CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) */ + + err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(additionalDataPayloadParams, bufferHandle, + additionalDataFields); + SuccessOrExit(err); + + os_mbuf_append(param->ctxt->om, bufferHandle->Start(), bufferHandle->DataLength()); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data, err:%" CHIP_ERROR_FORMAT, err.Format()); + } + return; +} + +int BLEManagerImpl::gatt_svr_chr_access_additional_data(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt * ctxt, void * arg) +{ + struct ble_gatt_char_context param; + int err = 0; + + memset(¶m, 0, sizeof(struct ble_gatt_char_context)); + + switch (ctxt->op) + { + case BLE_GATT_ACCESS_OP_READ_CHR: + + param.conn_handle = conn_handle; + param.attr_handle = attr_handle; + param.ctxt = ctxt; + param.arg = arg; + sInstance.HandleC3CharRead(¶m); + break; + + default: + err = BLE_ATT_ERR_UNLIKELY; + break; + } + + PlatformMgr().ScheduleWork(DriveBLEState, 0); + + return err; +} +#endif /* CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING */ + +int BLEManagerImpl::gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt * ctxt, void * arg) +{ + struct ble_gatt_char_context param; + int err = 0; + + memset(¶m, 0, sizeof(struct ble_gatt_char_context)); + + switch (ctxt->op) + { + case BLE_GATT_ACCESS_OP_READ_CHR: + + param.conn_handle = conn_handle; + param.attr_handle = attr_handle; + param.ctxt = ctxt; + param.arg = arg; + sInstance.HandleTXCharRead(¶m); + break; + + case BLE_GATT_ACCESS_OP_READ_DSC: + + param.conn_handle = conn_handle; + param.attr_handle = attr_handle; + param.ctxt = ctxt; + param.arg = arg; + sInstance.HandleTXCharCCCDRead(¶m); + break; + + case BLE_GATT_ACCESS_OP_WRITE_CHR: + param.conn_handle = conn_handle; + param.attr_handle = attr_handle; + param.ctxt = ctxt; + param.arg = arg; + sInstance.HandleRXCharWrite(¶m); + break; + + default: + err = BLE_ATT_ERR_UNLIKELY; + break; + } + + PlatformMgr().ScheduleWork(DriveBLEState, 0); + + return err; +} + +CHIP_ERROR BLEManagerImpl::StartAdvertising(void) +{ + CHIP_ERROR err; + ble_gap_ext_adv_params adv_params; + memset(&adv_params, 0, sizeof(adv_params)); + adv_params.scannable = 1; + adv_params.own_addr_type = own_addr_type; + adv_params.legacy_pdu = 1; + + mFlags.Clear(Flags::kAdvertisingRefreshNeeded); + + // Advertise connectable if we haven't reached the maximum number of connections. + size_t numCons = _NumConnections(); + bool connectable = (numCons < kMaxConnections); + adv_params.connectable = connectable; + + // Advertise in fast mode if it is connectable advertisement and + // the application has expressly requested fast advertising. + if (connectable && mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN; + adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX; + } + else + { +#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING + if (!mFlags.Has(Flags::kExtAdvertisingEnabled)) + { + adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; + adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + } + else + { + adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MIN; + adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MAX; + } +#else + + adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; + adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + +#endif + } + + ChipLogProgress(DeviceLayer, "Configuring CHIPoBLE advertising (interval %" PRIu32 " ms, %sconnectable)", + (((uint32_t) adv_params.itvl_min) * 10) / 16, (connectable) ? "" : "non-"); + + { + if (ble_gap_ext_adv_active(kChipAdvInstance)) + { + /* Advertising is already active. Stop and restart with the new parameters */ + ChipLogProgress(DeviceLayer, "Device already advertising, stop active advertisement and restart"); + err = MapBLEError(ble_gap_ext_adv_stop(kChipAdvInstance)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_stop() failed: %s, cannot restart", ErrorStr(err)); + return err; + } + } + err = MapBLEError(ble_gap_ext_adv_configure(kChipAdvInstance, &adv_params, NULL, ble_svr_gap_event, NULL)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_configure failed: %s", ErrorStr(err)); + return err; + } + + ble_addr_t addr; + + /* generate new non-resolvable private address */ + err = MapBLEError(ble_hs_id_gen_rnd(1, &addr)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_hs_id_gen_rnd failed: %s", ErrorStr(err)); + return err; + } + + /* Set generated address */ + err = MapBLEError(ble_gap_ext_adv_set_addr(kChipAdvInstance, &addr)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_set_addr failed: %s", ErrorStr(err)); + return err; + } + + struct os_mbuf * data = os_msys_get_pkthdr(mAdvDataLen, 0); + assert(data); + err = MapBLEError(os_mbuf_append(data, mAdvData, mAdvDataLen)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "os_mbuf_append failed: %s", ErrorStr(err)); + return err; + } + + err = MapBLEError(ble_gap_ext_adv_set_data(kChipAdvInstance, data)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "os_mbuf_append failed: %s", ErrorStr(err)); + return err; + } + + if (mScanResponse.HasValue()) + { + uint16_t resp_size = static_cast(mScanResponse.Value().size()); + struct os_mbuf * resp_data = os_msys_get_pkthdr(resp_size, 0); + assert(resp_data); + err = MapBLEError(os_mbuf_append(resp_data, mScanResponse.Value().data(), resp_size)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "os_mbuf_append failed: %s", ErrorStr(err)); + return err; + } + err = MapBLEError(ble_gap_ext_adv_rsp_set_data(kChipAdvInstance, resp_data)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_rsp_set_data failed: %s", ErrorStr(err)); + return err; + } + } + err = MapBLEError(ble_gap_ext_adv_start(kChipAdvInstance, 0, 0)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_start() failed: %s", ErrorStr(err)); + } + } + return err; +} + + +int BLEManagerImpl::secondary_ble_svr_gap_event(struct ble_gap_event * event, void * arg) +{ + if (chip::DeviceLayer::Internal::BLEMgrImpl().mSecondaryBleGapEventHandler) { + return chip::DeviceLayer::Internal::BLEMgrImpl().mSecondaryBleGapEventHandler(event, arg); + } + return 0; +} + +CHIP_ERROR BLEManagerImpl::ConfigureSecondaryAdvertisingData(void) +{ + memset(&mSecondaryAdvFields, 0, sizeof(mSecondaryAdvFields)); + mSecondaryAdvFields.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP); + mSecondaryAdvFields.num_uuids128 = 1; + mSecondaryAdvFields.uuids128_is_complete = 1; + mSecondaryAdvFields.uuids128 = &mSecondaryAdvUuid; + + memset(&mSecondaryRespFields, 0, sizeof(mSecondaryRespFields)); + mSecondaryRespFields.name = (const uint8_t *)mSecondaryAdvDeviceName; + mSecondaryRespFields.name_len = (uint8_t)strlen(mSecondaryAdvDeviceName); + mSecondaryRespFields.name_is_complete = 1; + return CHIP_NO_ERROR; +} + +CHIP_ERROR BLEManagerImpl::StartSecondaryAdvertising(void) +{ + CHIP_ERROR err; + uint8_t secondary_own_addr_type; + err = MapBLEError(ble_hs_util_ensure_addr(0)); + if (err != CHIP_NO_ERROR) { + ESP_LOGE(TAG, "Error loading address"); + return err; + } + + /* Figure out address to use while advertising (no privacy for now) */ + err = MapBLEError(ble_hs_id_infer_auto(0, &secondary_own_addr_type)); + if (err != CHIP_NO_ERROR) { + ChipLogError(DeviceLayer, "ble_hs_id_infer_auto() failed: %s, cannot restart", ErrorStr(err)); + return err; + } + ble_gap_ext_adv_params adv_params; + memset(&adv_params, 0, sizeof(adv_params)); + adv_params.scannable = 1; + adv_params.own_addr_type = secondary_own_addr_type; + adv_params.legacy_pdu = 1; + adv_params.connectable = 1; + adv_params.itvl_min = 0x100; + adv_params.itvl_max = 0x100; + + if (ble_gap_ext_adv_active(kSecondaryAdvInstance)) + { + /* Advertising is already active. Stop and restart with the new parameters */ + ChipLogProgress(DeviceLayer, "Device already advertising, stop active advertisement and restart"); + err = MapBLEError(ble_gap_ext_adv_stop(kSecondaryAdvInstance)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_stop() failed: %s, cannot restart", ErrorStr(err)); + return err; + } + } + err = MapBLEError(ble_gap_ext_adv_configure(kSecondaryAdvInstance, &adv_params, NULL, secondary_ble_svr_gap_event, NULL)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_configure failed: %s", ErrorStr(err)); + return err; + } + + struct os_mbuf * data = os_msys_get_pkthdr(BLE_HCI_MAX_ADV_DATA_LEN, 0); + assert(data); + err = MapBLEError(ble_hs_adv_set_fields_mbuf(&mSecondaryAdvFields, data)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_hs_adv_set_fields_mbuf failed: %s", ErrorStr(err)); + return err; + } + err = MapBLEError(ble_gap_ext_adv_set_data(kSecondaryAdvInstance, data)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_set_data failed: %s", ErrorStr(err)); + return err; + } + + struct os_mbuf * resp_data = os_msys_get_pkthdr(BLE_HCI_MAX_ADV_DATA_LEN, 0); + assert(resp_data); + err = MapBLEError(ble_hs_adv_set_fields_mbuf(&mSecondaryRespFields, resp_data)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_hs_adv_set_fields_mbuf failed: %s", ErrorStr(err)); + return err; + } + err = MapBLEError(ble_gap_ext_adv_rsp_set_data(kSecondaryAdvInstance, resp_data)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_set_data failed: %s", ErrorStr(err)); + return err; + } + err = MapBLEError(ble_gap_ext_adv_start(kSecondaryAdvInstance, 0, 0)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_ext_adv_start() failed: %s", ErrorStr(err)); + } + return err; +} + +void BLEManagerImpl::DriveBLEState(intptr_t arg) +{ + sInstance.DriveBLEState(); +} + +#ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +CHIP_ERROR BLEManagerImpl::HandleRXNotify(struct ble_gap_event * ble_event) +{ + uint16_t dataLen = OS_MBUF_PKTLEN(ble_event->notify_rx.om); + System::PacketBufferHandle buf = System::PacketBufferHandle::New(dataLen, 0); + VerifyOrReturnError(!buf.IsNull(), CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(buf->AvailableDataLength() >= dataLen, CHIP_ERROR_BUFFER_TOO_SMALL); + ble_hs_mbuf_to_flat(ble_event->notify_rx.om, buf->Start(), dataLen, NULL); + buf->SetDataLength(dataLen); + + ChipLogDetail(DeviceLayer, "Indication received, conn = %d", ble_event->notify_rx.conn_handle); + + ChipDeviceEvent event; + event.Type = DeviceEventType::kPlatformESP32BLEIndicationReceived; + event.Platform.BLEIndicationReceived.mConnection = ble_event->notify_rx.conn_handle; + event.Platform.BLEIndicationReceived.mData = std::move(buf).UnsafeRelease(); + PlatformMgr().PostEventOrDie(&event); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR BLEManagerImpl::ConfigureBle(uint32_t aAdapterId, bool aIsCentral) +{ + mBLEAdvConfig.mpBleName = mDeviceName; + mBLEAdvConfig.mAdapterId = aAdapterId; + mBLEAdvConfig.mMajor = 1; + mBLEAdvConfig.mMinor = 1; + mBLEAdvConfig.mVendorId = 1; + mBLEAdvConfig.mProductId = 1; + mBLEAdvConfig.mDeviceId = 1; + mBLEAdvConfig.mDuration = 2; + mBLEAdvConfig.mPairingStatus = 0; + mBLEAdvConfig.mType = 1; + mBLEAdvConfig.mpAdvertisingUUID = "0xFFF6"; + + mIsCentral = aIsCentral; + if (mIsCentral) + { + int rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64); + assert(rc == 0); + } + + return CHIP_NO_ERROR; +} + +void BLEManagerImpl::OnDeviceScanned(const struct ble_hs_adv_fields & fields, const ble_addr_t & addr, + const chip::Ble::ChipBLEDeviceIdentificationInfo & info) +{ + + if (mBLEScanConfig.mBleScanState == BleScanState::kScanForDiscriminator) + { + if (!mBLEScanConfig.mDiscriminator.MatchesLongDiscriminator(info.GetDeviceDiscriminator())) + { + ChipLogProgress(Ble, "Discriminator did not match"); + return; + } + ChipLogProgress(Ble, "Device Discriminator match. Attempting to connect"); + } + else if (mBLEScanConfig.mBleScanState == BleScanState::kScanForAddress) + { + ChipLogProgress(Ble, "Device Address match. Attempting to connect"); + } + else + { + ChipLogProgress(Ble, "Unknown discovery type. Ignoring"); + } + + mBLEScanConfig.mBleScanState = BleScanState::kConnecting; + chip::DeviceLayer::PlatformMgr().LockChipStack(); + DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds16(kConnectTimeout), HandleConnectTimeout, nullptr); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + + mDeviceScanner.StopScan(); + + ConnectDevice(addr, kConnectTimeout); +} + +void BLEManagerImpl::OnScanComplete() +{ + if (mBLEScanConfig.mBleScanState != BleScanState::kScanForDiscriminator && + mBLEScanConfig.mBleScanState != BleScanState::kScanForAddress) + { + ChipLogProgress(Ble, "Scan complete notification without an active scan"); + return; + } + + BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, CHIP_ERROR_TIMEOUT); + mBLEScanConfig.mBleScanState = BleScanState::kNotScanning; +} + +void BLEManagerImpl::InitiateScan(BleScanState scanType) +{ + DriveBLEState(); + + // Check for a valid scan type + if (scanType == BleScanState::kNotScanning) + { + BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, CHIP_ERROR_INCORRECT_STATE); + ChipLogError(Ble, "Invalid scan type requested"); + return; + } + + // Initialize the device scanner + CHIP_ERROR err = mDeviceScanner.Init(this); + if (err != CHIP_NO_ERROR) + { + BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, err); + ChipLogError(Ble, "Failed to initialize device scanner: %s", ErrorStr(err)); + return; + } + + // Start scanning + mBLEScanConfig.mBleScanState = scanType; + err = mDeviceScanner.StartScan(kNewConnectionScanTimeout); + if (err != CHIP_NO_ERROR) + { + mBLEScanConfig.mBleScanState = BleScanState::kNotScanning; + ChipLogError(Ble, "Failed to start a BLE scan: %s", chip::ErrorStr(err)); + BleConnectionDelegate::OnConnectionError(mBLEScanConfig.mAppState, err); + return; + } +} + +void BLEManagerImpl::CleanScanConfig() +{ + if (BLEManagerImpl::mBLEScanConfig.mBleScanState == BleScanState::kConnecting) + { + DeviceLayer::SystemLayer().CancelTimer(HandleConnectTimeout, nullptr); + } + mBLEScanConfig.mBleScanState = BleScanState::kNotScanning; +} + +void BLEManagerImpl::InitiateScan(intptr_t arg) +{ + sInstance.InitiateScan(static_cast(arg)); +} + +void BLEManagerImpl::NewConnection(BleLayer * bleLayer, void * appState, const SetupDiscriminator & connDiscriminator) +{ + mBLEScanConfig.mDiscriminator = connDiscriminator; + mBLEScanConfig.mAppState = appState; + + // Initiate async scan + PlatformMgr().ScheduleWork(InitiateScan, static_cast(BleScanState::kScanForDiscriminator)); +} + +CHIP_ERROR BLEManagerImpl::CancelConnection() +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} +#endif + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif // CONFIG_BT_NIMBLE_ENABLED + +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/ChipDeviceScanner.cpp b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/ChipDeviceScanner.cpp new file mode 120000 index 000000000..2e8465095 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/ChipDeviceScanner.cpp @@ -0,0 +1 @@ +../../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/nimble/ChipDeviceScanner.cpp \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/blecent.h b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/blecent.h new file mode 120000 index 000000000..a11c8b384 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/blecent.h @@ -0,0 +1 @@ +../../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/nimble/blecent.h \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/misc.c b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/misc.c new file mode 120000 index 000000000..24d45abae --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/misc.c @@ -0,0 +1 @@ +../../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/nimble/misc.c \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/peer.c b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/peer.c new file mode 120000 index 000000000..6e4c2f7f2 --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/nimble/peer.c @@ -0,0 +1 @@ +../../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/nimble/peer.c \ No newline at end of file diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/platform_change.patch b/examples/common/secondary_ble_adv/platform/ESP32_custom/platform_change.patch new file mode 100644 index 000000000..23fee6cae --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/platform_change.patch @@ -0,0 +1,639 @@ +diff --git a/src/platform/ESP32/BLEManagerImpl.h b/src/platform/ESP32/BLEManagerImpl.h +index eeed125012..e5480505c5 100644 +--- a/src/platform/ESP32/BLEManagerImpl.h ++++ b/src/platform/ESP32/BLEManagerImpl.h +@@ -61,6 +61,9 @@ struct ble_gatt_char_context + void * arg; + }; + ++#define MAX_ADV_DATA_LEN 31 ++#define MAX_DEVICE_NAME_LEN 29 ++ + #endif // CONFIG_BT_BLUEDROID_ENABLED + + #include +@@ -144,6 +147,45 @@ public: + CHIP_ERROR ConfigureScanResponseData(ByteSpan data); + void ClearScanResponseData(void); + ++ CHIP_ERROR SetSecondaryGATTService(struct ble_gatt_svc_def *gatt_svc, size_t gattSvcIndex) ++ { ++ if (!gatt_svc || gattSvcIndex > 1) ++ { ++ return CHIP_ERROR_INVALID_ARGUMENT; ++ } ++ mSecondGATTServiceIndex = gattSvcIndex; ++ memcpy(&mGATTServices[gattSvcIndex], gatt_svc, sizeof(struct ble_gatt_svc_def)); ++ return CHIP_NO_ERROR; ++ } ++ ++ using BleGapEventHandler = int(*)(struct ble_gap_event * event, void * arg); ++ ++ void SetSecondaryAdvGapEventHandler(BleGapEventHandler handler) { mSecondaryBleGapEventHandler = handler; } ++ ++ CHIP_ERROR SetSecondaryAdvDeviceName(const char *deviceName) ++ { ++ strncpy(mSecondaryAdvDeviceName, deviceName, MAX_DEVICE_NAME_LEN); ++ mSecondaryAdvDeviceName[MAX_DEVICE_NAME_LEN] = 0; ++ return CHIP_NO_ERROR; ++ } ++ ++ CHIP_ERROR SetSecondaryAdvUuid(const ByteSpan &uuid) ++ { ++ if (uuid.size() != 16) ++ { ++ return CHIP_ERROR_INVALID_ARGUMENT; ++ } ++ mSecondaryAdvUuid.u.type = BLE_UUID_TYPE_128; ++ memcpy(mSecondaryAdvUuid.value, uuid.data(), uuid.size()); ++ return CHIP_NO_ERROR; ++ } ++ ++ void SetSecondaryBleSmConfig(bool bleBonding, bool bleSmSc) ++ { ++ mSecondaryBleBonding = bleBonding; ++ mSecondaryBleSmSc = bleSmSc; ++ } ++ + private: + chip::Optional mScanResponse; + +@@ -346,7 +388,7 @@ private: + static void bleprph_host_task(void * param); + static void bleprph_on_sync(void); + static void bleprph_on_reset(int); +- static const struct ble_gatt_svc_def CHIPoBLEGATTAttrs[]; ++ static const struct ble_gatt_svc_def CHIPoBLEGATTService; + static int ble_svr_gap_event(struct ble_gap_event * event, void * arg); + + static int gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt * ctxt, void * arg); +@@ -380,6 +422,31 @@ private: + #endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER + + static void DriveBLEState(intptr_t arg); ++ ++ uint8_t mAdvData[MAX_ADV_DATA_LEN]; ++ uint16_t mAdvDataLen; ++ static constexpr uint8_t kChipAdvInstance = 0; ++ // Three GATT service ++ // mGATTServices[0] is for Matter-over-BLE ++ // mGATTServices[1] is for wifi_provisioning over BLE ++ // mGATTServices[2] is NULL ++ struct ble_gatt_svc_def mGATTServices[3]; ++ ++ // Secondary Advertisement ++ static int secondary_ble_svr_gap_event(struct ble_gap_event * event, void * arg); ++ CHIP_ERROR ConfigureSecondaryAdvertisingData(void); ++ CHIP_ERROR StartSecondaryAdvertising(void); ++ char mSecondaryAdvDeviceName[MAX_DEVICE_NAME_LEN + 1]; ++ size_t mSecondGATTServiceIndex = 1; ++ ble_uuid128_t mSecondaryAdvUuid; ++ bool mSecondaryBleBonding; ++ bool mSecondaryBleSmSc; ++ ble_hs_adv_fields mSecondaryAdvFields; ++ ble_hs_adv_fields mSecondaryRespFields; ++ uint8_t *mSecondaryMfgData; ++ size_t mSecondaryMfgDataLen; ++ BleGapEventHandler mSecondaryBleGapEventHandler = nullptr; ++ static constexpr uint8_t kSecondaryAdvInstance = 1; + }; + + /** +diff --git a/src/platform/ESP32/ESP32Utils.cpp b/src/platform/ESP32/ESP32Utils.cpp +index ffa45ee722..7a7fcad299 100644 +--- a/src/platform/ESP32/ESP32Utils.cpp ++++ b/src/platform/ESP32/ESP32Utils.cpp +@@ -311,62 +311,7 @@ CHIP_ERROR ESP32Utils::ClearWiFiStationProvision(void) + + CHIP_ERROR ESP32Utils::InitWiFiStack(void) + { +- wifi_init_config_t cfg; +- uint8_t ap_mac[6]; +- wifi_mode_t mode; +- esp_err_t err = esp_netif_init(); +- if (err != ESP_OK) +- { +- return ESP32Utils::MapError(err); +- } +- +-#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP +- // Lets not create a default AP interface if already present +- if (!esp_netif_get_handle_from_ifkey(kDefaultWiFiAPNetifKey)) +- { +- if (!esp_netif_create_default_wifi_ap()) +- { +- ChipLogError(DeviceLayer, "Failed to create the WiFi AP netif"); +- return CHIP_ERROR_INTERNAL; +- } +- } +-#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP +- +- // Lets not create a default station interface if already present +- if (!esp_netif_get_handle_from_ifkey(kDefaultWiFiStationNetifKey)) +- { +- if (!esp_netif_create_default_wifi_sta()) +- { +- ChipLogError(DeviceLayer, "Failed to create the WiFi STA netif"); +- return CHIP_ERROR_INTERNAL; +- } +- } +- +- // Initialize the ESP WiFi layer. +- cfg = WIFI_INIT_CONFIG_DEFAULT(); +- err = esp_wifi_init(&cfg); +- if (err != ESP_OK) +- { +- return ESP32Utils::MapError(err); +- } +- +- esp_wifi_get_mode(&mode); +- if ((mode == WIFI_MODE_AP) || (mode == WIFI_MODE_APSTA)) +- { +- esp_fill_random(ap_mac, sizeof(ap_mac)); +- /* Bit 0 of the first octet of MAC Address should always be 0 */ +- ap_mac[0] &= (uint8_t) ~0x01; +- err = esp_wifi_set_mac(WIFI_IF_AP, ap_mac); +- if (err != ESP_OK) +- { +- return ESP32Utils::MapError(err); +- } +- } +- err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent, NULL); +- if (err != ESP_OK) +- { +- return ESP32Utils::MapError(err); +- } ++ // Intentionally make this function empty so that we can setup wifi stack in the example + return CHIP_NO_ERROR; + } + #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI +diff --git a/src/platform/ESP32/PlatformManagerImpl.cpp b/src/platform/ESP32/PlatformManagerImpl.cpp +index 2c73019933..35ff83c2df 100644 +--- a/src/platform/ESP32/PlatformManagerImpl.cpp ++++ b/src/platform/ESP32/PlatformManagerImpl.cpp +@@ -60,7 +60,18 @@ static int app_entropy_source(void * data, unsigned char * output, size_t len, s + return 0; + } + +-CHIP_ERROR PlatformManagerImpl::_InitChipStack() ++CHIP_ERROR PlatformManagerImpl::DisableESPEventDispatch() ++{ ++ esp_err_t err = esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent); ++ if (err != ESP_OK) ++ { ++ return Internal::ESP32Utils::MapError(err); ++ } ++ err = esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent); ++ return Internal::ESP32Utils::MapError(err); ++} ++ ++CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) + { + // Arrange for CHIP-encapsulated ESP32 errors to be translated to text + Internal::ESP32Utils::RegisterESP32ErrorFormatter(); +@@ -73,6 +84,10 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack() + esp_err_t err = esp_netif_init(); + VerifyOrReturnError(err == ESP_OK, Internal::ESP32Utils::MapError(err)); + ++#if CHIP_DEVICE_CONFIG_ENABLE_WIFI ++ err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent, nullptr); ++ VerifyOrReturnError(err == ESP_OK, Internal::ESP32Utils::MapError(err)); ++#endif + // Arrange for the ESP event loop to deliver events into the CHIP Device layer. + err = esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent, nullptr); + VerifyOrReturnError(err == ESP_OK, Internal::ESP32Utils::MapError(err)); +diff --git a/src/platform/ESP32/PlatformManagerImpl.h b/src/platform/ESP32/PlatformManagerImpl.h +index cc2b0eefe9..0d99857ef8 100644 +--- a/src/platform/ESP32/PlatformManagerImpl.h ++++ b/src/platform/ESP32/PlatformManagerImpl.h +@@ -52,6 +52,7 @@ public: + CHIP_ERROR InitLwIPCoreLock(void); + static void HandleESPSystemEvent(void * arg, esp_event_base_t eventBase, int32_t eventId, void * eventData); + System::Clock::Timestamp GetStartTime() { return mStartTime; } ++ static CHIP_ERROR DisableESPEventDispatch(); + + private: + // ===== Methods that implement the PlatformManager abstract interface. +diff --git a/src/platform/ESP32/nimble/BLEManagerImpl.cpp b/src/platform/ESP32/nimble/BLEManagerImpl.cpp +index d4d90f4536..75328ddb3c 100644 +--- a/src/platform/ESP32/nimble/BLEManagerImpl.cpp ++++ b/src/platform/ESP32/nimble/BLEManagerImpl.cpp +@@ -125,39 +125,35 @@ uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM; + ChipDeviceScanner & mDeviceScanner = Internal::ChipDeviceScanner::GetInstance(); + #endif + BLEManagerImpl BLEManagerImpl::sInstance; +-const struct ble_gatt_svc_def BLEManagerImpl::CHIPoBLEGATTAttrs[] = { +- { .type = BLE_GATT_SVC_TYPE_PRIMARY, +- .uuid = (ble_uuid_t *) (&ShortUUID_CHIPoBLEService), +- .characteristics = +- (struct ble_gatt_chr_def[]){ +- { +- .uuid = (ble_uuid_t *) (&UUID128_CHIPoBLEChar_RX), +- .access_cb = gatt_svr_chr_access, +- .flags = BLE_GATT_CHR_F_WRITE, +- .val_handle = &sInstance.mRXCharAttrHandle, +- }, +- { +- .uuid = (ble_uuid_t *) (&UUID_CHIPoBLEChar_TX), +- .access_cb = gatt_svr_chr_access, +- .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_INDICATE, +- .val_handle = &sInstance.mTXCharCCCDAttrHandle, +- }, ++const struct ble_gatt_svc_def BLEManagerImpl::CHIPoBLEGATTService = { ++ .type = BLE_GATT_SVC_TYPE_PRIMARY, ++ .uuid = (ble_uuid_t *) (&ShortUUID_CHIPoBLEService), ++ .characteristics = (struct ble_gatt_chr_def[]){ ++ { ++ .uuid = (ble_uuid_t *) (&UUID128_CHIPoBLEChar_RX), ++ .access_cb = gatt_svr_chr_access, ++ .flags = BLE_GATT_CHR_F_WRITE, ++ .val_handle = &sInstance.mRXCharAttrHandle, ++ }, ++ { ++ .uuid = (ble_uuid_t *) (&UUID_CHIPoBLEChar_TX), ++ .access_cb = gatt_svr_chr_access, ++ .flags = ++ BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_INDICATE, ++ .val_handle = &sInstance.mTXCharCCCDAttrHandle, ++ }, + #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING +- { +- .uuid = (ble_uuid_t *) (&UUID_CHIPoBLEChar_C3), +- .access_cb = gatt_svr_chr_access_additional_data, +- .flags = BLE_GATT_CHR_F_READ, +- .val_handle = &sInstance.mC3CharAttrHandle, +- }, ++ { ++ .uuid = (ble_uuid_t *) (&UUID_CHIPoBLEChar_C3), ++ .access_cb = gatt_svr_chr_access_additional_data, ++ .flags = BLE_GATT_CHR_F_READ, ++ .val_handle = &sInstance.mC3CharAttrHandle, ++ }, + #endif +- { +- 0, /* No more characteristics in this service */ +- }, +- } }, +- +- { +- 0, /* No more services. */ +- }, ++ { ++ 0, /* No more characteristics in this service */ ++ }, ++ } + }; + + #ifdef CONFIG_ENABLE_ESP32_BLE_CONTROLLER +@@ -773,6 +769,12 @@ void BLEManagerImpl::DriveBLEState(void) + ChipLogError(DeviceLayer, "Configure Adv Data failed: %s", ErrorStr(err)); + ExitNow(); + } ++ err = ConfigureSecondaryAdvertisingData(); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "Configure secondary Adv Data failed: %s", ErrorStr(err)); ++ ExitNow(); ++ } + } + + // Start advertising. This is also an asynchronous step. +@@ -783,6 +785,12 @@ void BLEManagerImpl::DriveBLEState(void) + ChipLogError(DeviceLayer, "Start advertising failed: %s", ErrorStr(err)); + ExitNow(); + } ++ err = StartSecondaryAdvertising(); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "Start secondary advertising failed: %s", ErrorStr(err)); ++ ExitNow(); ++ } + + mFlags.Clear(Flags::kAdvertisingRefreshNeeded); + // Transition to the Advertising state... +@@ -808,12 +816,12 @@ void BLEManagerImpl::DriveBLEState(void) + { + if (mFlags.Has(Flags::kAdvertising)) + { +- if (ble_gap_adv_active()) ++ if (ble_gap_ext_adv_active(kChipAdvInstance)) + { +- err = MapBLEError(ble_gap_adv_stop()); ++ err = MapBLEError(ble_gap_ext_adv_stop(kChipAdvInstance)); + if (err != CHIP_NO_ERROR) + { +- ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %s", ErrorStr(err)); ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_stop() failed: %s", ErrorStr(err)); + ExitNow(); + } + } +@@ -939,14 +947,15 @@ CHIP_ERROR BLEManagerImpl::InitESPBleLayer(void) + ble_svc_gap_init(); + ble_svc_gatt_init(); + +- err = MapBLEError(ble_gatts_count_cfg(CHIPoBLEGATTAttrs)); ++ mGATTServices[1 - mSecondGATTServiceIndex] = CHIPoBLEGATTService; ++ err = MapBLEError(ble_gatts_count_cfg(mGATTServices)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gatts_count_cfg failed: %s", ErrorStr(err)); + ExitNow(); + } + +- err = MapBLEError(ble_gatts_add_svcs(CHIPoBLEGATTAttrs)); ++ err = MapBLEError(ble_gatts_add_svcs(mGATTServices)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gatts_add_svcs failed: %s", ErrorStr(err)); +@@ -992,7 +1001,7 @@ void BLEManagerImpl::ClaimBLEMemory(System::Layer *, void *) + + #ifdef CONFIG_IDF_TARGET_ESP32 + err = esp_bt_mem_release(ESP_BT_MODE_BTDM); +-#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) || \ ++#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) || \ + defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C6) + err = esp_bt_mem_release(ESP_BT_MODE_BLE); + #endif +@@ -1024,7 +1033,6 @@ CHIP_ERROR BLEManagerImpl::DeinitBLE() + CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) + { + CHIP_ERROR err; +- uint8_t advData[MAX_ADV_DATA_LEN]; + uint8_t index = 0; + + constexpr uint8_t kServiceDataTypeSize = 1; +@@ -1050,14 +1058,14 @@ CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) + ExitNow(); + } + +- memset(advData, 0, sizeof(advData)); +- advData[index++] = 0x02; // length +- advData[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags +- advData[index++] = CHIP_ADV_DATA_FLAGS; // AD value +- advData[index++] = kServiceDataTypeSize + sizeof(ESP32ChipServiceData); // length +- advData[index++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type: (Service Data - 16-bit UUID) +- advData[index++] = static_cast(ShortUUID_CHIPoBLEService.value & 0xFF); // AD value +- advData[index++] = static_cast((ShortUUID_CHIPoBLEService.value >> 8) & 0xFF); // AD value ++ memset(mAdvData, 0, sizeof(mAdvData)); ++ mAdvData[index++] = 0x02; // length ++ mAdvData[index++] = CHIP_ADV_DATA_TYPE_FLAGS; // AD type : flags ++ mAdvData[index++] = CHIP_ADV_DATA_FLAGS; // AD value ++ mAdvData[index++] = kServiceDataTypeSize + sizeof(ESP32ChipServiceData); // length ++ mAdvData[index++] = CHIP_ADV_DATA_TYPE_SERVICE_DATA; // AD type: (Service Data - 16-bit UUID) ++ mAdvData[index++] = static_cast(ShortUUID_CHIPoBLEService.value & 0xFF); // AD value ++ mAdvData[index++] = static_cast((ShortUUID_CHIPoBLEService.value >> 8) & 0xFF); // AD value + + err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo); + if (err != CHIP_NO_ERROR) +@@ -1087,18 +1095,11 @@ CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) + } + #endif + +- VerifyOrExit(index + sizeof(deviceIdInfo) <= sizeof(advData), err = CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG); +- memcpy(&advData[index], &deviceIdInfo, sizeof(deviceIdInfo)); ++ VerifyOrExit(index + sizeof(deviceIdInfo) <= sizeof(mAdvData), err = CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG); ++ memcpy(&mAdvData[index], &deviceIdInfo, sizeof(deviceIdInfo)); + index = static_cast(index + sizeof(deviceIdInfo)); + +- // Construct the Chip BLE Service Data to be sent in the scan response packet. +- err = MapBLEError(ble_gap_adv_set_data(advData, sizeof(advData))); +- if (err != CHIP_NO_ERROR) +- { +- ChipLogError(DeviceLayer, "ble_gap_adv_set_data failed: %s %d", ErrorStr(err), discriminator); +- ExitNow(); +- } +- ++ mAdvDataLen = index; + exit: + return err; + } +@@ -1651,16 +1652,18 @@ int BLEManagerImpl::gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_hand + CHIP_ERROR BLEManagerImpl::StartAdvertising(void) + { + CHIP_ERROR err; +- ble_gap_adv_params adv_params; ++ ble_gap_ext_adv_params adv_params; + memset(&adv_params, 0, sizeof(adv_params)); +- adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; ++ adv_params.scannable = 1; ++ adv_params.own_addr_type = own_addr_type; ++ adv_params.legacy_pdu = 1; + + mFlags.Clear(Flags::kAdvertisingRefreshNeeded); + + // Advertise connectable if we haven't reached the maximum number of connections. +- size_t numCons = _NumConnections(); +- bool connectable = (numCons < kMaxConnections); +- adv_params.conn_mode = connectable ? BLE_GAP_CONN_MODE_UND : BLE_GAP_CONN_MODE_NON; ++ size_t numCons = _NumConnections(); ++ bool connectable = (numCons < kMaxConnections); ++ adv_params.connectable = connectable; + + // Advertise in fast mode if it is connectable advertisement and + // the application has expressly requested fast advertising. +@@ -1694,48 +1697,187 @@ CHIP_ERROR BLEManagerImpl::StartAdvertising(void) + (((uint32_t) adv_params.itvl_min) * 10) / 16, (connectable) ? "" : "non-"); + + { +- if (ble_gap_adv_active()) ++ if (ble_gap_ext_adv_active(kChipAdvInstance)) + { + /* Advertising is already active. Stop and restart with the new parameters */ + ChipLogProgress(DeviceLayer, "Device already advertising, stop active advertisement and restart"); +- err = MapBLEError(ble_gap_adv_stop()); ++ err = MapBLEError(ble_gap_ext_adv_stop(kChipAdvInstance)); + if (err != CHIP_NO_ERROR) + { +- ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %s, cannot restart", ErrorStr(err)); ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_stop() failed: %s, cannot restart", ErrorStr(err)); + return err; + } + } +-#ifdef CONFIG_BT_NIMBLE_HOST_BASED_PRIVACY +- else ++ err = MapBLEError(ble_gap_ext_adv_configure(kChipAdvInstance, &adv_params, NULL, ble_svr_gap_event, NULL)); ++ if (err != CHIP_NO_ERROR) + { +- err = MapBLEError(ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA)); ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_configure failed: %s", ErrorStr(err)); ++ return err; ++ } ++ ++ ble_addr_t addr; ++ ++ /* generate new non-resolvable private address */ ++ err = MapBLEError(ble_hs_id_gen_rnd(1, &addr)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "ble_hs_id_gen_rnd failed: %s", ErrorStr(err)); ++ return err; ++ } ++ ++ /* Set generated address */ ++ err = MapBLEError(ble_gap_ext_adv_set_addr(kChipAdvInstance, &addr)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_set_addr failed: %s", ErrorStr(err)); ++ return err; ++ } ++ ++ struct os_mbuf * data = os_msys_get_pkthdr(mAdvDataLen, 0); ++ assert(data); ++ err = MapBLEError(os_mbuf_append(data, mAdvData, mAdvDataLen)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "os_mbuf_append failed: %s", ErrorStr(err)); ++ return err; ++ } ++ ++ err = MapBLEError(ble_gap_ext_adv_set_data(kChipAdvInstance, data)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "os_mbuf_append failed: %s", ErrorStr(err)); ++ return err; ++ } ++ ++ if (mScanResponse.HasValue()) ++ { ++ uint16_t resp_size = static_cast(mScanResponse.Value().size()); ++ struct os_mbuf * resp_data = os_msys_get_pkthdr(resp_size, 0); ++ assert(resp_data); ++ err = MapBLEError(os_mbuf_append(resp_data, mScanResponse.Value().data(), resp_size)); + if (err != CHIP_NO_ERROR) + { +- ChipLogError(DeviceLayer, "RPA not set: %s", ErrorStr(err)); ++ ChipLogError(DeviceLayer, "os_mbuf_append failed: %s", ErrorStr(err)); + return err; + } +- } +-#endif +- if (mScanResponse.HasValue()) +- { +- err = MapBLEError(ble_gap_adv_rsp_set_data(mScanResponse.Value().data(), mScanResponse.Value().size())); ++ err = MapBLEError(ble_gap_ext_adv_rsp_set_data(kChipAdvInstance, resp_data)); + if (err != CHIP_NO_ERROR) + { +- ChipLogError(DeviceLayer, "ble_gap_adv_rsp_set_data failed: %s", ErrorStr(err)); ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_rsp_set_data failed: %s", ErrorStr(err)); + return err; + } + } +- err = MapBLEError(ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_svr_gap_event, NULL)); +- if (err == CHIP_NO_ERROR) ++ err = MapBLEError(ble_gap_ext_adv_start(kChipAdvInstance, 0, 0)); ++ if (err != CHIP_NO_ERROR) + { +- return CHIP_NO_ERROR; ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_start() failed: %s", ErrorStr(err)); + } +- else ++ } ++ return err; ++} ++ ++ ++int BLEManagerImpl::secondary_ble_svr_gap_event(struct ble_gap_event * event, void * arg) ++{ ++ if (chip::DeviceLayer::Internal::BLEMgrImpl().mSecondaryBleGapEventHandler) { ++ return chip::DeviceLayer::Internal::BLEMgrImpl().mSecondaryBleGapEventHandler(event, arg); ++ } ++ return 0; ++} ++ ++CHIP_ERROR BLEManagerImpl::ConfigureSecondaryAdvertisingData(void) ++{ ++ memset(&mSecondaryAdvFields, 0, sizeof(mSecondaryAdvFields)); ++ mSecondaryAdvFields.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP); ++ mSecondaryAdvFields.num_uuids128 = 1; ++ mSecondaryAdvFields.uuids128_is_complete = 1; ++ mSecondaryAdvFields.uuids128 = &mSecondaryAdvUuid; ++ ++ memset(&mSecondaryRespFields, 0, sizeof(mSecondaryRespFields)); ++ mSecondaryRespFields.name = (const uint8_t *)mSecondaryAdvDeviceName; ++ mSecondaryRespFields.name_len = (uint8_t)strlen(mSecondaryAdvDeviceName); ++ mSecondaryRespFields.name_is_complete = 1; ++ return CHIP_NO_ERROR; ++} ++ ++CHIP_ERROR BLEManagerImpl::StartSecondaryAdvertising(void) ++{ ++ CHIP_ERROR err; ++ uint8_t secondary_own_addr_type; ++ err = MapBLEError(ble_hs_util_ensure_addr(0)); ++ if (err != CHIP_NO_ERROR) { ++ ESP_LOGE(TAG, "Error loading address"); ++ return err; ++ } ++ ++ /* Figure out address to use while advertising (no privacy for now) */ ++ err = MapBLEError(ble_hs_id_infer_auto(0, &secondary_own_addr_type)); ++ if (err != CHIP_NO_ERROR) { ++ ChipLogError(DeviceLayer, "ble_hs_id_infer_auto() failed: %s, cannot restart", ErrorStr(err)); ++ return err; ++ } ++ ble_gap_ext_adv_params adv_params; ++ memset(&adv_params, 0, sizeof(adv_params)); ++ adv_params.scannable = 1; ++ adv_params.own_addr_type = secondary_own_addr_type; ++ adv_params.legacy_pdu = 1; ++ adv_params.connectable = 1; ++ adv_params.itvl_min = 0x100; ++ adv_params.itvl_max = 0x100; ++ ++ if (ble_gap_ext_adv_active(kSecondaryAdvInstance)) ++ { ++ /* Advertising is already active. Stop and restart with the new parameters */ ++ ChipLogProgress(DeviceLayer, "Device already advertising, stop active advertisement and restart"); ++ err = MapBLEError(ble_gap_ext_adv_stop(kSecondaryAdvInstance)); ++ if (err != CHIP_NO_ERROR) + { +- ChipLogError(DeviceLayer, "ble_gap_adv_start() failed: %s", ErrorStr(err)); ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_stop() failed: %s, cannot restart", ErrorStr(err)); + return err; + } + } ++ err = MapBLEError(ble_gap_ext_adv_configure(kSecondaryAdvInstance, &adv_params, NULL, secondary_ble_svr_gap_event, NULL)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_configure failed: %s", ErrorStr(err)); ++ return err; ++ } ++ ++ struct os_mbuf * data = os_msys_get_pkthdr(BLE_HCI_MAX_ADV_DATA_LEN, 0); ++ assert(data); ++ err = MapBLEError(ble_hs_adv_set_fields_mbuf(&mSecondaryAdvFields, data)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "ble_hs_adv_set_fields_mbuf failed: %s", ErrorStr(err)); ++ return err; ++ } ++ err = MapBLEError(ble_gap_ext_adv_set_data(kSecondaryAdvInstance, data)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_set_data failed: %s", ErrorStr(err)); ++ return err; ++ } ++ ++ struct os_mbuf * resp_data = os_msys_get_pkthdr(BLE_HCI_MAX_ADV_DATA_LEN, 0); ++ assert(resp_data); ++ err = MapBLEError(ble_hs_adv_set_fields_mbuf(&mSecondaryRespFields, resp_data)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "ble_hs_adv_set_fields_mbuf failed: %s", ErrorStr(err)); ++ return err; ++ } ++ err = MapBLEError(ble_gap_ext_adv_rsp_set_data(kSecondaryAdvInstance, resp_data)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_set_data failed: %s", ErrorStr(err)); ++ return err; ++ } ++ err = MapBLEError(ble_gap_ext_adv_start(kSecondaryAdvInstance, 0, 0)); ++ if (err != CHIP_NO_ERROR) ++ { ++ ChipLogError(DeviceLayer, "ble_gap_ext_adv_start() failed: %s", ErrorStr(err)); ++ } ++ return err; + } + + void BLEManagerImpl::DriveBLEState(intptr_t arg) diff --git a/examples/common/secondary_ble_adv/platform/ESP32_custom/route_hook b/examples/common/secondary_ble_adv/platform/ESP32_custom/route_hook new file mode 120000 index 000000000..6eb4f99ae --- /dev/null +++ b/examples/common/secondary_ble_adv/platform/ESP32_custom/route_hook @@ -0,0 +1 @@ +../../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/route_hook \ No newline at end of file diff --git a/examples/light_wifi_prov/CMakeLists.txt b/examples/light_wifi_prov/CMakeLists.txt new file mode 100644 index 000000000..992d6ed74 --- /dev/null +++ b/examples/light_wifi_prov/CMakeLists.txt @@ -0,0 +1,41 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +if(NOT DEFINED ENV{ESP_MATTER_PATH}) + message(FATAL_ERROR "Please set ESP_MATTER_PATH to the path of esp-matter repo") +endif(NOT DEFINED ENV{ESP_MATTER_PATH}) + +set(PROJECT_VER "1.0") +set(PROJECT_VER_NUMBER 1) + +set(ESP_MATTER_PATH $ENV{ESP_MATTER_PATH}) +set(MATTER_SDK_PATH ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip) + +# This should be done before using the IDF_TARGET variable. +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +include(${ESP_MATTER_PATH}/examples/common/cmake_common/components_include.cmake) + +set(EXTRA_COMPONENT_DIRS + "${ESP_MATTER_PATH}/examples/common" + "${MATTER_SDK_PATH}/config/esp32/components" + "${ESP_MATTER_PATH}/components" + ${extra_components_dirs_append}) + +project(light-wifi-prov) + +# WARNING: This is just an example for using key for decrypting the encrypted OTA image +# Please do not use it as is. +if(CONFIG_ENABLE_ENCRYPTED_OTA) + target_add_binary_data(light.elf "esp_image_encryption_key.pem" TEXT) +endif() + +if(CONFIG_IDF_TARGET_ESP32C2) + include(relinker) +endif() + +idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os;-DCHIP_HAVE_CONFIG_H;-Wno-overloaded-virtual" APPEND) +idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND) +# For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various +# flags that depend on -Wformat +idf_build_set_property(COMPILE_OPTIONS "-Wno-format-nonliteral;-Wno-format-security" APPEND) diff --git a/examples/light_wifi_prov/README.md b/examples/light_wifi_prov/README.md new file mode 100644 index 000000000..5c362f33e --- /dev/null +++ b/examples/light_wifi_prov/README.md @@ -0,0 +1,143 @@ +# Light with RainMaker-WiFi-Provisioning + +This example creates a Color Temperature Light device using the ESP Matter data model and is integrated with ESP-RainMaker and wifi_provisioning. + +See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html) for more information about building and flashing the firmware. + +## 1. Prerequisites + +- ESP32-S3-DevKitM / ESP32-C3-DevKitM +- chip-tool (For Matter commissioning) +- Android RainMaker APP of version 3.4.1 or iOS RainMaker APP of version 3.2.0 (For RainMaker Provisioning) +- [ESP-IDF](https://github.com/espressif/esp-idf) on tag v5.2.2 +- [ESP RainMaker](https://github.com/espressif/esp-rainmaker/tree/fd781295) on commit fd78129500aa1a8b2eee9e0dcc0720d7b14cd3dc +- [ESP Secure Cert Manager](https://github.com/espressif/esp_secure_cert_mgr) + +## 2. Additional Environment Setup + +### 2.1 Claiming device certificates + +This example will use [host driven claiming](https://rainmaker.espressif.com/docs/claiming/#host-driven-claiming) via the RainMaker CLI. + +Make sure your device is connected to the host machine, login into the CLI and execute this: +``` +$ cd $RMAKER_PATH/cli +$ ./rainmaker.py claim --matter +``` +The CLI will fetch the device certificates and flash them into the secure cert partition of your device. The certificates will be used for both the Matter device attestation verification and RainMaker MQTT connection. + +### 2.2 Generating the factory nvs binary + +The factory nvs (fctry partition) needs to be generated using the mfg_tool of esp-matter. It is released on pypi as [esp-matter-mfg-tool](https://pypi.org/project/esp-matter-mfg-tool) and can be installed by running `pip install esp-matter-mfg-tool` + +``` +$ export ESP_SECURE_CERT_PATH=/path/to/esp_secure_cert_mgr +$ esp-matter-mfg-tool -v 0x131B -p 0x2 -cd $RMAKER_PATH/examples/matter/mfg/cd_131B_0002.der --csv $RMAKER_PATH/examples/matter/mfg/keys.csv --mcsv $RMAKER_PATH/examples/matter/mfg/master.csv +``` +This not only generates the factory nvs binary required for matter, but also embeds the RainMaker MQTT Host url into it via the master.csv file. Optionally, you can embed the MQTT host into the firmware itself by using idf.py menuconfig -> ESP RainMaker Config -> ESP_RMAKER_READ_MQTT_HOST_FROM_CONFIG and then skipping the --csv and --mcsv options to mfg_tool + +The factory binary generated above should be flashed onto the fctry partition (default : 0x3e0000 for ESP32-S3 and ESP32-C3. Do check your partition table for exact address). + +``` +$ esptool.py write_flash 0x3e0000 out/131b_2//-partition.bin +``` + +### 2.3 Build the example + +Once the environment and required files are set up, we can now proceed to build and flash the example + +``` +$ idf.py set-target +$ idf.py build +$ idf.py flash monitor +``` + +## 3. Post Commissioning Setup + +See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html#commissioning-and-control) for the information about Matter commissioning with chip-tool. Note that you need to specific the PAA path to the `paa_cert` under the directory of this example when you use the chip-tool to commisioning the device. + +``` +$ ./chip-tool pairing ble-wifi --paa-trust-store-path +``` + +**Note**: The `setup-picode` and `discriminator` is generated with the factory partition binary. You can find it in the `out/131b_2//-onb_codes.csv`. + +## 4. External platform + +This example uses [external platform](../common/secondary_ble_adv/). + +In the external platform, `SetSecondaryXX()` APIs are added in the `BLEManagerImpl` class for setting up the secondary BLE advertisement and services. After you call these APIs of `BLEManagerImpl`, there will be an additional BLE advertisement and corresponding service for wifi_provisioning after you initialize the Matter stack. + +There are also some WiFi stack initialization changes to avoid duplicated Wi-Fi stack initialization of wifi_provisioning and Matter stack. + +## 5. RainMaker Provisioning + +After you flash the example to the DevKit board, the console will print the QR code for RainMaker Provisioning. After you scan the QR code with the RainMaker Phone App, the RainMaker provisioning will be done and the device will be added to your RainMaker home. + +## 6. Manufacturing Considerations + +This step is only suggested for Privately deployed Production and not required for test set up. + +### 6.1 RainMaker MQTT Host + +Find your private deployment's mqtt hostname (if applicable) by sending a GET request at `https:///mqtt_host`. You should replace the mqtt host in master.csv (As described in the section above) with this to generate the factory nvs binary. + +### 6.2 Matter VID/PID + +For production devices which may have a different matter vid and pid, please set the values of DEVICE_VENDOR_ID and DEVICE_PRODUCT_ID by using `idf.py menuconfig` -> `Component config` -> `CHIP Device Layer` -> `Device Identification Options`. These same should also be used in the `mfg_tool`. + +**Note**: The CD used by `mfg_tool` should also be changed when VID/PID is changed. Please refer to [this](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/certification.html#certification-declaration) about how to generate a test CD file. + +### 6.3 Matter DAC + +For public RainMaker, some test DACs are provided via claiming. For private deployments, test DACs can be generated using `mfg_tool`. + +``` +export ESP_SECURE_CERT_PATH=/path/to/esp_secure_cert_mgr +esp-matter-mfg-tool -v -p --pai -k -c -cd --csv /path/to/keys.csv --mcsv /path/to/master.csv +``` + +Samples of keys.csv and master.csv can be found in $RMAKER_PATH/examples/matter/mfg/. + +For testing, you can use the test VID, PID, PAI and CD as shown below. +``` +$ esp-matter-mfg-tool --dac-in-secure-cert -v 0xFFF2 -p 0x8001 --pai -k $ESP_MATTER_PATH/connectedhomeip/connectedhomeip/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Key.pem -c $ESP_MATTER_PATH/connectedhomeip/connectedhomeip/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem -cd $ESP_MATTER_PATH/connectedhomeip/connectedhomeip/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der --csv $RMAKER_PATH/examples/matter/mfg/keys.csv --mcsv $RMAKER_PATH/examples/matter/mfg/master.csv +``` + +Note the path where the files are generated after running the above command since it will be required later. + +### 6.4 Configure your app + +Open the project configuration menu using +``` +idf.py menuconfig +``` + +In the configuration menu, set the following additional configuration to use custom factory partition and different values for Data and Device Info Providers. + +1. Enable ESP32 Factory Data Provider [Component config → CHIP Device Layer → Commissioning options → Use ESP32 Factory Data Provider] + + Enable config option CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER to use ESP32 specific implementation of CommissionableDataProvider and DeviceAttestationCredentialsProvider. + +2. Enable ESP32 Device Instance Info Provider [Component config → CHIP Device Layer → Commissioning options → Use ESP32 Device Instance Info Provider] + + Enable config option ENABLE_ESP32_DEVICE_INSTANCE_INFO_PROVIDER to get device instance info from factory partition. + +3. Enable Attestation - Secure Cert [ Component config → ESP Matter → DAC Provider options → Attestation - Secure Cert] + + Enable config option CONFIG_FACTORY_PARTITION_DAC_PROVIDER to use DAC certificates from the secure_cert partition during Attestation. + +4. Set chip-factory namespace partition label [Component config → CHIP Device Layer → Matter Manufacturing Options → chip-factory namespace partition label] + + Set config option CHIP_FACTORY_NAMESPACE_PARTITION_LABEL to choose the label of the partition to store key-values in the "chip-factory" namespace. The default chosen partition label is nvs, change it to fctry. + + +Connect your esp32 device to your computer. Enter the below command to flash certificates and factory partition + +``` +$ esptool.py write_flash 0xd000 /out/_//_esp_secure_cert.bin 0x3e0000 ./out/_//-partition.bin +``` + +The csv file generate at `/out/_/cn_dacs--