diff --git a/examples/blemesh_bridge/CMakeLists.txt b/examples/blemesh_bridge/CMakeLists.txt new file mode 100644 index 000000000..9c4dce7e3 --- /dev/null +++ b/examples/blemesh_bridge/CMakeLists.txt @@ -0,0 +1,45 @@ +# 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}) + +if(NOT DEFINED ENV{ESP_MATTER_DEVICE_PATH}) + if("${IDF_TARGET}" STREQUAL "esp32" OR "${IDF_TARGET}" STREQUAL "") + set(ENV{ESP_MATTER_DEVICE_PATH} $ENV{ESP_MATTER_PATH}/device_hal/device/esp32_devkit_c) + elseif("${IDF_TARGET}" STREQUAL "esp32c3") + set(ENV{ESP_MATTER_DEVICE_PATH} $ENV{ESP_MATTER_PATH}/device_hal/device/esp32c3_devkit_m) + elseif("${IDF_TARGET}" STREQUAL "esp32s2") + set(ENV{ESP_MATTER_DEVICE_PATH} $ENV{ESP_MATTER_PATH}/device_hal/device/esp32s2_devkit_c) + elseif("${IDF_TARGET}" STREQUAL "esp32s3") + set(ENV{ESP_MATTER_DEVICE_PATH} $ENV{ESP_MATTER_PATH}/device_hal/device/esp32s3_devkit_c) + else() + message(FATAL_ERROR "Unsupported IDF_TARGET") + endif() +endif(NOT DEFINED ENV{ESP_MATTER_DEVICE_PATH}) + +set(ESP_MATTER_PATH $ENV{ESP_MATTER_PATH}) +set(MATTER_SDK_PATH ${ESP_MATTER_PATH}/connectedhomeip/connectedhomeip) +set(ZAP_GENERATED_PATH ${CMAKE_CURRENT_LIST_DIR}/main/zap-generated) + +# This should be done before using the IDF_TARGET variable. +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +include($ENV{ESP_MATTER_DEVICE_PATH}/esp_matter_device.cmake) + +set(EXTRA_COMPONENT_DIRS + "../common" + "${IDF_PATH}/examples/common_components/qrcode" + "${MATTER_SDK_PATH}/config/esp32/components" + "${ESP_MATTER_PATH}/components" + "${ESP_MATTER_PATH}/device_hal/device" + ${extra_components_dirs_append}) + +project(blemesh_bridge) + +idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++14;-Os;-DLWIP_IPV6_SCOPES=0;-DCHIP_HAVE_CONFIG_H;-fpermissive" APPEND) +idf_build_set_property(C_COMPILE_OPTIONS "-Os;-DLWIP_IPV6_SCOPES=0" 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/blemesh_bridge/README.md b/examples/blemesh_bridge/README.md new file mode 100644 index 000000000..23f282938 --- /dev/null +++ b/examples/blemesh_bridge/README.md @@ -0,0 +1,101 @@ +# BLE Mesh Bridge + +This example demonstrates a Matter-BLE Mesh Bridge that bridges BLE Mesh devices to Matter fabric. + +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. Commissioning Setup + +### 1.1 Discovering BLE Mesh Devices + +You can read the parts list from the Bridge to get the number of the +bridged devices. + +``` +chip-tool descriptor read parts-list 0x7283 0x0 +``` + +If there is no other BLE Mesh device on the BLE Mesh Network, you will get +an empty result. Example: + +``` +Data = [ + +], +``` + +### 1.2 Setup BLE Mesh Node on ESP32-C3 + +Build and run BLE Mesh onoff_server app on another ESP32-C3 board. + +``` +$ cd ${IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_node/onoff_server +$ idf.py set-target esp32c3 +$ idf.py -p build flash monitor +``` + +The BLE Mesh device will be provisioned by provisioner and a dynamic +endpoint will be added on the Bridge device. You can read the parts list +again to get the dynamic endpoint ID. + +``` +$ chip-tool descriptor read parts-list 12344321 0 +``` + +The data will now contain the information of the connected BLE Mesh +devices. Example: + +``` +Data = [ + 1, +], +``` + +It means that the BLE Mesh Node is added as Endpoint 1 on the Bridge +device. You can read the cluster servers list on the dynamic endpoint. + +``` +$ chip-tool descriptor read server-list 12344321 1 +``` + +This will give the list of supported server clusters. Example: + +``` +OnDescriptorServerListListAttributeResponse: 4 entries + [1]: 6 + [2]: 29 + [3]: 57 + [4]: 64 +``` + +### 1.3 Control the BLE Mesh Node with chip-tool + +Now you can control the BLE Mesh Node on chip tool. + +``` +$ ./out/chip-tool onoff toggle 12344321 1 +``` + +## 2. Device Performance + +### 2.1 Memory usage + +The following is the Memory and Flash Usage. + +- `Bootup` == Device just finished booting up. Device is not + commissioned or connected to wifi yet. +- `After Commissioning` == Device is connected to wifi and is also + commissioned and is rebooted. +- device used: esp32c3_devkit_m +- tested on: + [2d04492](https://github.com/espressif/esp-matter/commit/2d044929ab78e9b036e41ed54e155a242e1d2e73) + (2022-05-20) + +| | Bootup | After Commissioning | +|:- |:-: |:-: | +|**Free Internal Memory** |100KB |95KB | + +**Flash Usage**: Firmware binary size: 1.4MB + +This should give you a good idea about the amount of free memory that is +available for you to run your application's code. diff --git a/examples/blemesh_bridge/main/CMakeLists.txt b/examples/blemesh_bridge/main/CMakeLists.txt new file mode 100644 index 000000000..f2de25c7d --- /dev/null +++ b/examples/blemesh_bridge/main/CMakeLists.txt @@ -0,0 +1,8 @@ +set(PRIV_REQUIRES_LIST device esp_matter esp_matter_console route_hook app_qrcode esp_matter_ota app_bridge) + +idf_component_register(SRC_DIRS "." + PRIV_INCLUDE_DIRS "." + PRIV_REQUIRES ${PRIV_REQUIRES_LIST}) + +set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 14) +target_compile_options(${COMPONENT_LIB} PRIVATE "-DLWIP_IPV6_SCOPES=0" "-DCHIP_HAVE_CONFIG_H") diff --git a/examples/blemesh_bridge/main/app_blemesh.c b/examples/blemesh_bridge/main/app_blemesh.c new file mode 100644 index 000000000..86e55d49c --- /dev/null +++ b/examples/blemesh_bridge/main/app_blemesh.c @@ -0,0 +1,696 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "esp_nimble_hci.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "host/util/util.h" +#include "console/console.h" + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_ble_api.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" + +#include "app_blemesh.h" + +#define CID_ESP 0x02E5 +#define PROV_OWN_ADDR 0x0001 + +#define APP_KEY_IDX 0x0000 +#define APP_KEY_OCTET 0x12 + +#define COMP_DATA_PAGE_0 0x00 + +#define MSG_SEND_TTL 3 +#define MSG_SEND_REL false +#define MSG_TIMEOUT 0 +#define MSG_ROLE ROLE_PROVISIONER + +#define LED_OFF 0x00 +#define LED_ON 0x01 + +static const char *TAG = "app_ble_mesh"; + +static uint8_t dev_uuid[16]; + +static esp_ble_mesh_client_t config_client; +static esp_ble_mesh_client_t onoff_client; + +static esp_ble_mesh_cfg_srv_t config_server = { + /* 3 transmissions with 20ms interval */ + net_transmit : ESP_BLE_MESH_TRANSMIT(2, 20), + relay : ESP_BLE_MESH_RELAY_DISABLED, + relay_retransmit : ESP_BLE_MESH_TRANSMIT(2, 20), + beacon : ESP_BLE_MESH_BEACON_ENABLED, +#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + gatt_proxy : ESP_BLE_MESH_GATT_PROXY_ENABLED, +#else + gatt_proxy : ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif +#if defined(CONFIG_BLE_MESH_FRIEND) + friend_state : ESP_BLE_MESH_FRIEND_ENABLED, +#else + friend_state : ESP_BLE_MESH_FRIEND_NOT_SUPPORTED, +#endif + default_ttl : 7, +}; + +static esp_ble_mesh_model_t root_models[] = { + ESP_BLE_MESH_MODEL_CFG_SRV(&config_server), + ESP_BLE_MESH_MODEL_CFG_CLI(&config_client), + ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(NULL, &onoff_client), +}; + +static esp_ble_mesh_elem_t elements[] = { + ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE), +}; + +static esp_ble_mesh_comp_t composition = { + .cid = CID_ESP, + .element_count = ARRAY_SIZE(elements), + .elements = elements, +}; + +static esp_ble_mesh_prov_t provision = { + .prov_uuid = dev_uuid, + .prov_unicast_addr = PROV_OWN_ADDR, + .prov_start_address = 0x0005, + .prov_attention = 0x00, + .prov_algorithm = 0x00, + .prov_pub_key_oob = 0x00, + .prov_static_oob_val = NULL, + .prov_static_oob_len = 0x00, + .flags = 0x00, + .iv_index = 0x00, +}; + +static struct esp_ble_mesh_key { + uint16_t net_idx; + uint16_t app_idx; + uint8_t app_key[16]; +} prov_key; + +typedef struct { + uint8_t uuid[16]; + uint16_t unicast; + uint8_t elem_num; + uint8_t onoff; +} ble_mesh_node_info_t; + +static ble_mesh_node_info_t nodes[CONFIG_BLE_MESH_MAX_PROV_NODES] = { + { + .unicast = ESP_BLE_MESH_ADDR_UNASSIGNED, + .elem_num = 0, + .onoff = LED_OFF, + } +}; + +static esp_err_t ble_mesh_store_node_info(const uint8_t uuid[16], uint16_t unicast, + uint8_t elem_num, uint8_t onoff_state) +{ + if (!uuid || !ESP_BLE_MESH_ADDR_IS_UNICAST(unicast)) { + return ESP_ERR_INVALID_ARG; + } + + /* Judge if the device has been provisioned before */ + for (int i = 0; i < ARRAY_SIZE(nodes); i++) { + if (!memcmp(nodes[i].uuid, uuid, 16)) { + ESP_LOGW(TAG, "%s: reprovisioned device 0x%04x", __func__, unicast); + nodes[i].unicast = unicast; + nodes[i].elem_num = elem_num; + nodes[i].onoff = onoff_state; + return ESP_OK; + } + } + + for (int j = 0; j < ARRAY_SIZE(nodes); j++) { + if (nodes[j].unicast == ESP_BLE_MESH_ADDR_UNASSIGNED) { + memcpy(nodes[j].uuid, uuid, 16); + nodes[j].unicast = unicast; + nodes[j].elem_num = elem_num; + nodes[j].onoff = onoff_state; + return ESP_OK; + } + } + + return ESP_FAIL; +} + +static ble_mesh_node_info_t *ble_mesh_get_node_info(uint16_t unicast) +{ + if (!ESP_BLE_MESH_ADDR_IS_UNICAST(unicast)) { + return NULL; + } + + for (int i = 0; i < ARRAY_SIZE(nodes); i++) { + if (nodes[i].unicast <= unicast && + nodes[i].unicast + nodes[i].elem_num > unicast) { + return &nodes[i]; + } + } + + return NULL; +} + +static esp_err_t ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common, uint16_t unicast, + esp_ble_mesh_model_t *model, uint32_t opcode) +{ + if (!common || !model) { + return ESP_ERR_INVALID_ARG; + } + + common->opcode = opcode; + common->model = model; + common->ctx.net_idx = prov_key.net_idx; + common->ctx.app_idx = prov_key.app_idx; + common->ctx.addr = unicast; + common->ctx.send_ttl = MSG_SEND_TTL; + common->ctx.send_rel = MSG_SEND_REL; + common->msg_timeout = MSG_TIMEOUT; + common->msg_role = MSG_ROLE; + + return ESP_OK; +} + +static esp_err_t ble_mesh_prov_complete(int node_idx, const esp_ble_mesh_octet16_t uuid, + uint16_t unicast, uint8_t elem_num, uint16_t net_idx) +{ + esp_err_t err = ESP_OK; + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_cfg_client_get_state_t get_state = {0}; + ble_mesh_node_info_t *node = NULL; + char name[11] = {0}; + + ESP_LOGI(TAG, "node index: 0x%x, unicast address: 0x%02x, element num: %d, netkey index: 0x%02x", + node_idx, unicast, elem_num, net_idx); + ESP_LOGI(TAG, "device uuid: %s", bt_hex(uuid, 16)); + + sprintf(name, "%s%d", "NODE-", node_idx); + err = esp_ble_mesh_provisioner_set_node_name(node_idx, name); + if (err) { + ESP_LOGE(TAG, "%s: Set node name failed", __func__); + return ESP_FAIL; + } + + err = ble_mesh_store_node_info(uuid, unicast, elem_num, LED_OFF); + if (err) { + ESP_LOGE(TAG, "%s: Store node info failed", __func__); + return ESP_FAIL; + } + + node = ble_mesh_get_node_info(unicast); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return ESP_FAIL; + } + + ble_mesh_set_msg_common(&common, node->unicast, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET); + get_state.comp_data_get.page = COMP_DATA_PAGE_0; + err = esp_ble_mesh_config_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Send config comp data get failed", __func__); + return ESP_FAIL; + } + + return ESP_OK; +} + +static void ble_mesh_recv_unprov_adv_pkt(uint8_t dev_uuid[16], uint8_t addr[BD_ADDR_LEN], + esp_ble_mesh_addr_type_t addr_type, uint16_t oob_info, + uint8_t adv_type, esp_ble_mesh_prov_bearer_t bearer) +{ + esp_err_t err = ESP_OK; + esp_ble_mesh_unprov_dev_add_t add_dev = {0}; + + /* Due to the API esp_ble_mesh_provisioner_set_dev_uuid_match, Provisioner will only + * use this callback to report the devices, whose device UUID starts with 0xdd & 0xdd, + * to the application layer. + */ + + ESP_LOGI(TAG, "address: %s, address type: %d, adv type: %d", bt_hex(addr, BD_ADDR_LEN), addr_type, adv_type); + ESP_LOGI(TAG, "device uuid: %s", bt_hex(dev_uuid, 16)); + ESP_LOGI(TAG, "oob info: %d, bearer: %s", oob_info, (bearer & ESP_BLE_MESH_PROV_ADV) ? "PB-ADV" : "PB-GATT"); + + memcpy(add_dev.addr, addr, BD_ADDR_LEN); + add_dev.addr_type = (uint8_t)addr_type; + memcpy(add_dev.uuid, dev_uuid, 16); + add_dev.oob_info = oob_info; + add_dev.bearer = (uint8_t)bearer; + /* Note: If unprovisioned device adv packets have not been received, we should not add + device with ADD_DEV_START_PROV_NOW_FLAG set. */ + err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, + ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_START_PROV_NOW_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG); + if (err) { + ESP_LOGE(TAG, "%s: Add unprovisioned device into queue failed", __func__); + } + + return; +} + +esp_err_t app_ble_mesh_onoff_set(uint16_t blemesh_addr, bool onoff) +{ + esp_err_t err = ESP_OK; + + esp_ble_mesh_client_common_param_t common = {0}; + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + + ble_mesh_set_msg_common(&common, blemesh_addr, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET); + set_state.onoff_set.op_en = false; + set_state.onoff_set.onoff = onoff; + set_state.onoff_set.tid = 0; + + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + + return err; +} + +static void ble_mesh_ble_cb(esp_ble_mesh_ble_cb_event_t event, esp_ble_mesh_ble_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_START_BLE_ADVERTISING_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_START_BLE_ADVERTISING_COMP_EVT, index %d, err_code %d", param->start_ble_advertising_comp.index, param->start_ble_advertising_comp.err_code); + break; + case ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT, err_code %d", param->stop_ble_advertising_comp.err_code); + break; + default: + break; + } + + return; +} + +static void ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event, + esp_ble_mesh_prov_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT, err_code %d", param->provisioner_prov_enable_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT, err_code %d", param->provisioner_prov_disable_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT"); + ble_mesh_recv_unprov_adv_pkt(param->provisioner_recv_unprov_adv_pkt.dev_uuid, param->provisioner_recv_unprov_adv_pkt.addr, + param->provisioner_recv_unprov_adv_pkt.addr_type, param->provisioner_recv_unprov_adv_pkt.oob_info, + param->provisioner_recv_unprov_adv_pkt.adv_type, param->provisioner_recv_unprov_adv_pkt.bearer); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT: + ESP_LOGI(TAG, "%s link open", param->provisioner_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT"); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT: + ESP_LOGI(TAG, "%s link close, reason 0x%02x", + param->provisioner_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", param->provisioner_prov_link_close.reason); + break; + case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT: + ble_mesh_prov_complete(param->provisioner_prov_complete.node_idx, param->provisioner_prov_complete.device_uuid, + param->provisioner_prov_complete.unicast_addr, param->provisioner_prov_complete.element_num, + param->provisioner_prov_complete.netkey_idx); + break; + case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, err_code %d", param->provisioner_add_unprov_dev_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT, err_code %d", param->provisioner_set_dev_uuid_match_comp.err_code); + break; + case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, err_code %d", param->provisioner_set_node_name_comp.err_code); + if (param->provisioner_set_node_name_comp.err_code == ESP_OK) { + const char *name = esp_ble_mesh_provisioner_get_node_name(param->provisioner_set_node_name_comp.node_index); + if (!name) { + ESP_LOGE(TAG, "Get node name failed"); + return; + } + ESP_LOGI(TAG, "Node %d name is: %s", param->provisioner_set_node_name_comp.node_index, name); + } + break; + } + case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT: { + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, err_code %d", param->provisioner_add_app_key_comp.err_code); + if (param->provisioner_add_app_key_comp.err_code == ESP_OK) { + esp_err_t err = 0; + prov_key.app_idx = param->provisioner_add_app_key_comp.app_idx; + err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_key.app_idx, + ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, ESP_BLE_MESH_CID_NVAL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Provisioner bind local model appkey failed"); + return; + } + } + break; + } + case ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT, err_code %d", param->provisioner_bind_app_key_to_model_comp.err_code); + break; + default: + break; + } + + return; +} + +static void ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t event, + esp_ble_mesh_cfg_client_cb_param_t *param) +{ + esp_err_t err = ESP_OK; + + ble_mesh_node_info_t *node = NULL; + esp_ble_mesh_client_common_param_t common = {0}; + + uint32_t opcode = param->params->opcode; + uint16_t addr = param->params->ctx.addr; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x, opcode: 0x%04x", + __func__, param->error_code, event, param->params->ctx.addr, opcode); + + if (param->error_code) { + ESP_LOGE(TAG, "Send config client message failed, opcode 0x%04x", opcode); + return; + } + + node = ble_mesh_get_node_info(addr); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return; + } + + switch (event) { + case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: { + ESP_LOGI(TAG, "composition data %s", bt_hex(param->status_cb.comp_data_status.composition_data->data, + param->status_cb.comp_data_status.composition_data->len)); + + /** Find Expect Device */ + blemesh_bridge_match_bridged_onoff_light(param->status_cb.comp_data_status.composition_data->data, addr); + + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + ble_mesh_set_msg_common(&common, node->unicast, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD); + set_state.app_key_add.net_idx = prov_key.net_idx; + set_state.app_key_add.app_idx = prov_key.app_idx; + memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16); + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config AppKey Add failed", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + ble_mesh_set_msg_common(&common, node->unicast, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND); + set_state.model_app_bind.element_addr = node->unicast; + set_state.model_app_bind.model_app_idx = prov_key.app_idx; + set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV; + set_state.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL; + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: { + esp_ble_mesh_generic_client_get_state_t get_state = {0}; + ble_mesh_set_msg_common(&common, node->unicast, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET); + err = esp_ble_mesh_generic_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_STATUS: + ESP_LOG_BUFFER_HEX("composition data %s", param->status_cb.comp_data_status.composition_data->data, + param->status_cb.comp_data_status.composition_data->len); + break; + case ESP_BLE_MESH_MODEL_OP_APP_KEY_STATUS: + break; + default: + break; + } + break; + case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: { + esp_ble_mesh_cfg_client_get_state_t get_state = {0}; + ble_mesh_set_msg_common(&common, node->unicast, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET); + get_state.comp_data_get.page = COMP_DATA_PAGE_0; + err = esp_ble_mesh_config_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Composition Data Get failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + ble_mesh_set_msg_common(&common, node->unicast, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD); + set_state.app_key_add.net_idx = prov_key.net_idx; + set_state.app_key_add.app_idx = prov_key.app_idx; + memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16); + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config AppKey Add failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: { + esp_ble_mesh_cfg_client_set_state_t set_state = {0}; + ble_mesh_set_msg_common(&common, node->unicast, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND); + set_state.model_app_bind.element_addr = node->unicast; + set_state.model_app_bind.model_app_idx = prov_key.app_idx; + set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV; + set_state.model_app_bind.company_id = ESP_BLE_MESH_CID_NVAL; + err = esp_ble_mesh_config_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Config Model App Bind failed", __func__); + return; + } + break; + } + default: + break; + } + break; + default: + ESP_LOGE(TAG, "Not a config client status message event"); + break; + } +} + +static void ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_t event, + esp_ble_mesh_generic_client_cb_param_t *param) +{ + esp_err_t err = ESP_OK; + + ble_mesh_node_info_t *node = NULL; + esp_ble_mesh_client_common_param_t common = {0}; + + uint32_t opcode = param->params->opcode; + uint16_t addr = param->params->ctx.addr; + + ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x, opcode: 0x%04x", + __func__, param->error_code, event, param->params->ctx.addr, opcode); + + if (param->error_code) { + ESP_LOGE(TAG, "Send generic client message failed, opcode 0x%04x", opcode); + return; + } + + node = ble_mesh_get_node_info(addr); + if (!node) { + ESP_LOGE(TAG, "%s: Get node info failed", __func__); + return; + } + + switch (event) { + case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: { + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET onoff: 0x%02x", node->onoff); + /* After Generic OnOff Status for Generic OnOff Get is received, Generic OnOff Set will be sent */ + ble_mesh_set_msg_common(&common, node->unicast, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET); + set_state.onoff_set.op_en = false; + set_state.onoff_set.onoff = !node->onoff; + set_state.onoff_set.tid = 0; + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__); + return; + } + break; + } + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET onoff: 0x%02x", node->onoff); + break; + default: + break; + } + break; + case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: + break; + case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: + /* If failed to receive the responses, these messages will be resend */ + switch (opcode) { + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: { + esp_ble_mesh_generic_client_get_state_t get_state = {0}; + ble_mesh_set_msg_common(&common, node->unicast, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET); + err = esp_ble_mesh_generic_client_get_state(&common, &get_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__); + return; + } + break; + } + case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: { + esp_ble_mesh_generic_client_set_state_t set_state = {0}; + node->onoff = param->status_cb.onoff_status.present_onoff; + ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET onoff: 0x%02x", node->onoff); + ble_mesh_set_msg_common(&common, node->unicast, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET); + set_state.onoff_set.op_en = false; + set_state.onoff_set.onoff = !node->onoff; + set_state.onoff_set.tid = 0; + err = esp_ble_mesh_generic_client_set_state(&common, &set_state); + if (err) { + ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__); + return; + } + break; + } + default: + break; + } + break; + default: + ESP_LOGE(TAG, "Not a generic client status message event"); + break; + } +} + +static esp_err_t ble_mesh_init(void) +{ + esp_err_t err = ESP_OK; + uint8_t match[2] = {0xdd, 0xdd}; + + prov_key.net_idx = ESP_BLE_MESH_KEY_PRIMARY; + prov_key.app_idx = APP_KEY_IDX; + memset(prov_key.app_key, APP_KEY_OCTET, sizeof(prov_key.app_key)); + + // ble_gatts_reset(); + + // esp_ble_mesh_register_ble_callback(ble_mesh_ble_cb); + esp_ble_mesh_register_prov_callback(ble_mesh_provisioning_cb); + esp_ble_mesh_register_config_client_callback(ble_mesh_config_client_cb); + esp_ble_mesh_register_generic_client_callback(ble_mesh_generic_client_cb); + + err = esp_ble_mesh_init(&provision, &composition); + if (err) { + ESP_LOGE(TAG, "Initializing mesh failed, err: %d", err); + return err; + } + + err = esp_ble_mesh_provisioner_set_dev_uuid_match(match, sizeof(match), 0x0, false); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set matching device uuid (err %d)", err); + return err; + } + + err = esp_ble_mesh_provisioner_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to enable mesh provisioner (err %d)", err); + return err; + } + + err = esp_ble_mesh_provisioner_add_local_app_key(prov_key.app_key, prov_key.net_idx, prov_key.app_idx); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to add local AppKey (err %d)", err); + return err; + } + + ESP_LOGI(TAG, "BLE Mesh Provisioner initialized"); + + return err; +} + +void ble_mesh_get_dev_uuid(uint8_t *dev_uuid) +{ + uint8_t addr_val[6] = {0}; + + if (dev_uuid == NULL) { + ESP_LOGE(TAG, "%s, Invalid device uuid", __func__); + return; + } + + esp_read_mac(addr_val, ESP_MAC_BT); + + /* Copy device address to the device uuid with offset equals to 2 here. + * The first two bytes is used for matching device uuid by Provisioner. + * And using device address here is to avoid using the same device uuid + * by different unprovisioned devices. + */ + memcpy(dev_uuid + 2, addr_val, BD_ADDR_LEN); +} + +esp_err_t app_ble_mesh_init(void) +{ + esp_err_t err = ESP_OK; + + ble_mesh_get_dev_uuid(dev_uuid); + + /** + * @brief Initialize the Bluetooth Mesh Subsystem. + */ + err = ble_mesh_init(); + if (err) { + ESP_LOGE(TAG, "Bluetooth Mesh Init Failed (err %d)", err); + return err; + } + + return err; +} diff --git a/examples/blemesh_bridge/main/app_blemesh.h b/examples/blemesh_bridge/main/app_blemesh.h new file mode 100644 index 000000000..c0513ee06 --- /dev/null +++ b/examples/blemesh_bridge/main/app_blemesh.h @@ -0,0 +1,46 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @brief + * + * @return esp_err_t + */ +esp_err_t app_ble_mesh_init(void); + +/** + * @brief + * + * @param blemesh_addr + * @param onoff + * + * @return esp_err_t + */ +esp_err_t app_ble_mesh_onoff_set(uint16_t blemesh_addr, bool onoff); + +/** + * @brief + * + * @param composition_data + * @param blemesh_addr + * + * @return esp_err_t + */ +esp_err_t blemesh_bridge_match_bridged_onoff_light(uint8_t *composition_data, uint16_t blemesh_addr); + +#ifdef __cplusplus +} +#endif diff --git a/examples/blemesh_bridge/main/app_main.cpp b/examples/blemesh_bridge/main/app_main.cpp new file mode 100644 index 000000000..f9774710b --- /dev/null +++ b/examples/blemesh_bridge/main/app_main.cpp @@ -0,0 +1,91 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "blemesh_bridge.h" +#include "app_blemesh.h" + +static const char *TAG = "app_main"; + +using namespace esp_matter; +using namespace esp_matter::attribute; + +static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg) +{ + switch (event->Type) { + case chip::DeviceLayer::DeviceEventType::PublicEventTypes::kInterfaceIpAddressChanged: +#if !CHIP_DEVICE_CONFIG_ENABLE_THREAD + chip::app::DnssdServer::Instance().StartServer(); + esp_route_hook_init(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF")); +#endif + break; + + case chip::DeviceLayer::DeviceEventType::PublicEventTypes::kCommissioningComplete: + ESP_LOGI(TAG, "Commissioning complete"); + break; + + default: + break; + } +} + +static esp_err_t app_attribute_update_cb(callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id, + uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data) +{ + esp_err_t err = ESP_OK; + + if (type == PRE_UPDATE) { + err = blemesh_bridge_attribute_update(endpoint_id, cluster_id, attribute_id, val); + } + return err; +} + +extern "C" void app_main() +{ + esp_err_t err = ESP_OK; + + /* Initialize the ESP NVS layer */ + nvs_flash_init(); + + /* Create a Matter node */ + node::config_t node_config; + node_t *node = node::create(&node_config, app_attribute_update_cb, NULL); + + /* These node and endpoint handles can be used to create/add other endpoints and clusters. */ + if (!node) { + ESP_LOGE(TAG, "Matter node creation failed"); + } + + /* Matter start */ + err = esp_matter::start(app_event_cb); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Matter start failed: %d", err); + } + + app_qrcode_print(); + +#if CONFIG_ENABLE_CHIP_SHELL + esp_matter_console_diagnostics_register_commands(); + esp_matter_console_init(); +#endif + +#if CONFIG_ENABLE_OTA_REQUESTOR + esp_matter_ota_requestor_init(); +#endif +} diff --git a/examples/blemesh_bridge/main/blemesh_bridge.cpp b/examples/blemesh_bridge/main/blemesh_bridge.cpp new file mode 100644 index 000000000..75589f4d0 --- /dev/null +++ b/examples/blemesh_bridge/main/blemesh_bridge.cpp @@ -0,0 +1,99 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +static const char *TAG = "blemesh_bridge"; + +using namespace esp_matter; +using namespace esp_matter::cluster; + +/** Mesh Spec 4.2.1: "The Composition Data state contains information about a node, + * the elements it includes, and the supported models. Composition Data Page 0 is mandatory." + * Composition Data Page 0 can be used to determine device type. + * The following Composition Data Page 0 describes the information: + * CID is 0x02E5; PID is 0x0000; VID is 0x0000 + * CRPL is 0x000A + * Features is 0x0003 – Relay and Friend features. + * Loc is “unknown” – 0x0000 + * NumS is 2; NumV is 0 + * The Bluetooth SIG Models supported are: + * - 0x0000: Config Server Model + * - 0x1000: Generic OnOff Server Model */ +static uint8_t expect_composition[] = {/* CID */0XE5, 0x02, /* PID */0x00, 0x00, /* VID */0x00, 0x00, + /* CRPL */0X0A, 0x00, /* Features */0x03, 0x00, /* Loc */0x00, 0x00, + /* NumS */0x02, /* NumV */0x00, /* Config Server Model */0x00, 0x00, + /* Generic OnOff Server Model */0x00, 0x10}; + +static esp_err_t blemesh_bridge_init_bridged_onoff_light(esp_matter_bridge_device_t *dev) +{ + if (!dev) { + ESP_LOGE(TAG, "Invalid bridge device to be initialized"); + return ESP_ERR_INVALID_ARG; + } + on_off::config_t config; + on_off::create(dev->endpoint, &config, CLUSTER_MASK_SERVER, ESP_MATTER_NONE_FEATURE_ID); + endpoint::set_device_type_id(dev->endpoint, endpoint::on_off_light::get_device_type_id()); + if (endpoint::enable(dev->endpoint) != ESP_OK) { + ESP_LOGE(TAG, "ESP Matter enable dynamic endpoint failed"); + endpoint::destroy(dev->node, dev->endpoint); + return ESP_FAIL; + } + return ESP_OK; +} + +esp_err_t blemesh_bridge_match_bridged_onoff_light(uint8_t *composition_data, uint16_t blemesh_addr) +{ + /** Compare Composition Data Page 0 to find expected device */ + if (!memcmp(composition_data, expect_composition, sizeof(expect_composition))) { + ESP_LOGI(TAG, "This is an expected device ..."); + node_t *node = node::get(); + ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_STATE, TAG, "Could not find esp_matter node"); + if (app_bridge_get_device_by_blemesh_addr(blemesh_addr)) { + ESP_LOGI(TAG, "Bridged node for 0x%04x bridged device on endpoint %d has been created", blemesh_addr, + app_bridge_get_matter_endpointid_by_blemesh_addr(blemesh_addr)); + } else { + app_bridged_device_t *bridged_device = app_bridge_create_bridged_device(node, ESP_MATTER_BRIDGED_DEVICE_TYPE_BLEMESH, app_bridge_blemesh_address(blemesh_addr)); + ESP_RETURN_ON_FALSE(bridged_device, ESP_FAIL, TAG, "Failed to create bridged device (on_off light)"); + ESP_RETURN_ON_ERROR(blemesh_bridge_init_bridged_onoff_light(bridged_device->dev), TAG, "Failed to initialize the bridged node"); + ESP_LOGI(TAG, "Create/Update bridged node for 0x%04x bridged device on endpoint %d", blemesh_addr, + app_bridge_get_matter_endpointid_by_blemesh_addr(blemesh_addr)); + } + } else { + ESP_LOGW(TAG, "This isn't an unexpected device ..."); + } + return ESP_OK; +} + +esp_err_t blemesh_bridge_attribute_update(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, + esp_matter_attr_val_t *val) +{ + app_bridged_device_t *bridged_device = app_bridge_get_device_by_matter_endpointid(endpoint_id); + if (bridged_device && bridged_device->dev && bridged_device->dev->endpoint) { + if (cluster_id == OnOff::Id) { + if (attribute_id == OnOff::Attributes::OnOff::Id) { + ESP_LOGD(TAG, "Update Bridged Device, ep: %d, cluster: %d, att: %d", endpoint_id, cluster_id, attribute_id); + app_ble_mesh_onoff_set(bridged_device->dev_addr.blemesh_addr, val->val.b); + } + } + } + return ESP_OK; +} + +/** ToDo: Implement some keep-alive logic in BLE mesh + * so that we can remove them when they are offline */ diff --git a/examples/blemesh_bridge/main/blemesh_bridge.h b/examples/blemesh_bridge/main/blemesh_bridge.h new file mode 100644 index 000000000..7bc2eb62e --- /dev/null +++ b/examples/blemesh_bridge/main/blemesh_bridge.h @@ -0,0 +1,37 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include + +#include + +/** + * @brief + * + * @param endpoint_id + * @param cluster_id + * @param attribute_id + * @param val + * + * @return esp_err_t + */ +esp_err_t blemesh_bridge_attribute_update(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, + esp_matter_attr_val_t *val); + +#ifdef __cplusplus +} +#endif diff --git a/examples/blemesh_bridge/main/zap-generated/PluginApplicationCallbacks.h b/examples/blemesh_bridge/main/zap-generated/PluginApplicationCallbacks.h new file mode 100644 index 000000000..3fb313fc9 --- /dev/null +++ b/examples/blemesh_bridge/main/zap-generated/PluginApplicationCallbacks.h @@ -0,0 +1,24 @@ +/* + * + * Copyright (c) 2022 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. + */ + +// THIS FILE IS GENERATED BY ZAP + +#pragma once + +#include + +#define MATTER_PLUGINS_INIT esp_matter::cluster::plugin_init_callback_common(); diff --git a/examples/blemesh_bridge/main/zap-generated/af-gen-event.h b/examples/blemesh_bridge/main/zap-generated/af-gen-event.h new file mode 100644 index 000000000..0b0c75006 --- /dev/null +++ b/examples/blemesh_bridge/main/zap-generated/af-gen-event.h @@ -0,0 +1,48 @@ +/** + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * + * Copyright (c) 2020 Silicon Labs + * + * 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. + */ +// This file is generated by Simplicity Studio. Please do not edit manually. +// +// + +// Enclosing macro to prevent multiple inclusion +#ifndef __AF_GEN_EVENT__ +#define __AF_GEN_EVENT__ + +// Code used to configure the cluster event mechanism +#define EMBER_AF_GENERATED_EVENT_CODE +// EmberEventData structs used to populate the EmberEventData table +#define EMBER_AF_GENERATED_EVENTS +#define EMBER_AF_GENERATED_EVENT_STRINGS + +#endif // __AF_GEN_EVENT__ diff --git a/examples/blemesh_bridge/main/zap-generated/empty_file.cpp b/examples/blemesh_bridge/main/zap-generated/empty_file.cpp new file mode 100644 index 000000000..d47ae50bd --- /dev/null +++ b/examples/blemesh_bridge/main/zap-generated/empty_file.cpp @@ -0,0 +1,8 @@ +/** Empty File + * + * This file is just present to prevent cmake warnings about: + * No source files found for SRC_DIRS entry '/Users/chirag/work/gitlab/esp-matter/examples//main/zap-generated'. + * + * We need to keep the path in SRC_DIRS to be compatible with the zap data model. + */ + \ No newline at end of file diff --git a/examples/blemesh_bridge/main/zap-generated/endpoint_config.h b/examples/blemesh_bridge/main/zap-generated/endpoint_config.h new file mode 100644 index 000000000..cfd7f6fc1 --- /dev/null +++ b/examples/blemesh_bridge/main/zap-generated/endpoint_config.h @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2022 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. + */ + +// THIS FILE IS GENERATED BY ZAP + +// Prevent multiple inclusion +#pragma once + +#include + +#define GENERATED_ATTRIBUTES \ + {} + +#define GENERATED_CLUSTERS \ + {} + +#define GENERATED_ENDPOINT_TYPES \ + {} + +#define ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT 0 + +// Largest attribute size is needed for various buffers +#define ATTRIBUTE_LARGEST (259) + +static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, "ATTRIBUTE_LARGEST larger than expected"); + +// Total size of attribute storage +#define ATTRIBUTE_MAX_SIZE (0) + +// Number of fixed endpoints +#define FIXED_ENDPOINT_COUNT (0) +#ifdef CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT +#undef CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT +#endif +#define CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT (16) + +// Array of endpoints that are supported, the data inside +// the array is the endpoint number. +#define FIXED_ENDPOINT_ARRAY \ + {0} + +// Array of profile ids +#define FIXED_PROFILE_IDS \ + {0} + +// Array of device types +#define FIXED_DEVICE_TYPES \ + {0} + +// Array of device type offsets +#define FIXED_DEVICE_TYPE_OFFSETS \ + {0} + +// Array of device type lengths +#define FIXED_DEVICE_TYPE_LENGTHS \ + {0} + +// Array of endpoint types supported on each endpoint +#define FIXED_ENDPOINT_TYPES \ + {0} + +// Array of networks supported on each endpoint +#define FIXED_NETWORKS \ + {0} diff --git a/examples/blemesh_bridge/partitions.csv b/examples/blemesh_bridge/partitions.csv new file mode 100644 index 000000000..c590e73c3 --- /dev/null +++ b/examples/blemesh_bridge/partitions.csv @@ -0,0 +1,9 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: Firmware partition offset needs to be 64K aligned, initial 36K (9 sectors) are reserved for bootloader and partition table +sec_cert, 0x3F, ,0xd000, 0x3000, , # Never mark this as an encrypted partition +nvs, data, nvs, 0x10000, 0x6000, +otadata, data, ota, , 0x2000 +phy_init, data, phy, , 0x1000, +ota_0, app, ota_0, 0x20000, 0x1D0000, +ota_1, app, ota_1, , 0x1D0000, +fctry, data, nvs, , 0x6000, diff --git a/examples/blemesh_bridge/platform/ESP32_custom/BLEManagerImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/BLEManagerImpl.h new file mode 120000 index 000000000..507e4ff7d --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/BLEManagerImpl.h @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/BLEManagerImpl.h \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/BUILD.gn b/examples/blemesh_bridge/platform/ESP32_custom/BUILD.gn new file mode 100644 index 000000000..0c43300b6 --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/BUILD.gn @@ -0,0 +1,135 @@ +# Copyright (c) 2021 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/chip.gni") + +import("${chip_root}/build/chip/buildconfig_header.gni") +import("${chip_root}/src/platform/device.gni") + +chip_enable_wifi = true + +config("ESP32_custom_include") { + include_dirs = [ "../../" ] +} + +buildconfig_header("custom_buildconfig") { + header = "CHIPDeviceBuildConfig.h" + header_dir = "platform" + + defines = [ + "CHIP_DEVICE_CONFIG_ENABLE_WPA=true", + "CHIP_ENABLE_OPENTHREAD=false", + "CHIP_DEVICE_CONFIG_THREAD_FTD=false", + "CHIP_WITH_GIO=true", + "OPENTHREAD_CONFIG_ENABLE_TOBLE=false", + "CHIP_STACK_LOCK_TRACKING_ENABLED=true", + "CHIP_STACK_LOCK_TRACKING_ERROR_FATAL=true", + "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING=false", + "CHIP_DEVICE_CONFIG_RUN_AS_ROOT=true", + "CHIP_DISABLE_PLATFORM_KVS=false", + "CHIP_USE_TRANSITIONAL_COMMISSIONABLE_DATA_PROVIDER=true", + "CHIP_DEVICE_LAYER_TARGET_ESP32=1", + "CHIP_DEVICE_LAYER_TARGET=ESP32_custom", + "BLE_PLATFORM_CONFIG_INCLUDE=", + "CHIP_DEVICE_PLATFORM_CONFIG_INCLUDE=", + "CHIP_PLATFORM_CONFIG_INCLUDE=", + "INET_CONFIG_INCLUDE=", + "SYSTEM_PLATFORM_CONFIG_INCLUDE=", + ] + + if (chip_enable_ota_requestor) { + defines += [ "CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR=1" ] + } +} + +group("platform_buildconfig") { + public_deps = [ + ":custom_buildconfig", + ] + + public_configs = [ + ":ESP32_custom_include", + ] +} + +static_library("ESP32_custom") { + sources = [ + "${chip_root}/src/platform/SingletonConfigurationManager.cpp", + "BLEManagerImpl.h", + "CHIPDevicePlatformConfig.h", + "CHIPDevicePlatformEvent.h", + "ConfigurationManagerImpl.cpp", + "ConfigurationManagerImpl.h", + "ConnectivityManagerImpl.cpp", + "ConnectivityManagerImpl.h", + "DeviceNetworkProvisioningDelegateImpl.cpp", + "DeviceNetworkProvisioningDelegateImpl.h", + "DiagnosticDataProviderImpl.cpp", + "DiagnosticDataProviderImpl.h", + "ESP32Config.cpp", + "ESP32Config.h", + "ESP32FactoryDataProvider.cpp", + "ESP32FactoryDataProvider.h", + "ESP32Utils.cpp", + "ESP32Utils.h", + "KeyValueStoreManagerImpl.cpp", + "KeyValueStoreManagerImpl.h", + "Logging.cpp", + "LwIPCoreLock.cpp", + "PlatformManagerImpl.cpp", + "PlatformManagerImpl.h", + "SystemTimeSupport.cpp", + "SystemTimeSupport.h", + "bluedroid/BLEManagerImpl.cpp", + "nimble/BLEManagerImpl.cpp", + ] + + deps = [ + "${chip_root}/src/lib/dnssd:platform_header", + "${chip_root}/src/setup_payload", + ] + + public = [ "${chip_root}/src/credentials/DeviceAttestationCredsProvider.h" ] + + public_deps = [ + "${chip_root}/src/crypto", + "${chip_root}/src/platform:platform_base", + ":platform_buildconfig", + ] + + public_configs = [ + ":ESP32_custom_include", + ] + + if (chip_enable_ota_requestor) { + sources += [ + "OTAImageProcessorImpl.cpp", + "OTAImageProcessorImpl.h", + ] + } + + if (chip_enable_wifi) { + sources += [ + "ConnectivityManagerImpl_WiFi.cpp", + "NetworkCommissioningDriver.cpp", + "NetworkCommissioningDriver.h", + ] + if (chip_mdns == "platform") { + sources += [ + "DnssdImpl.cpp", + "DnssdImpl.h", + ] + } + } +} diff --git a/examples/blemesh_bridge/platform/ESP32_custom/BlePlatformConfig.h b/examples/blemesh_bridge/platform/ESP32_custom/BlePlatformConfig.h new file mode 120000 index 000000000..77d64bb5d --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/CHIPDevicePlatformConfig.h b/examples/blemesh_bridge/platform/ESP32_custom/CHIPDevicePlatformConfig.h new file mode 120000 index 000000000..50cfc04fe --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/CHIPDevicePlatformEvent.h b/examples/blemesh_bridge/platform/ESP32_custom/CHIPDevicePlatformEvent.h new file mode 120000 index 000000000..a090fee8d --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/CHIPPlatformConfig.h b/examples/blemesh_bridge/platform/ESP32_custom/CHIPPlatformConfig.h new file mode 120000 index 000000000..1a91e937d --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ConfigurationManagerImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/ConfigurationManagerImpl.cpp new file mode 120000 index 000000000..f5e56ad62 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ConfigurationManagerImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/ConfigurationManagerImpl.h new file mode 120000 index 000000000..3946c9030 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ConnectivityManagerImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/ConnectivityManagerImpl.cpp new file mode 120000 index 000000000..19127f455 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ConnectivityManagerImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/ConnectivityManagerImpl.h new file mode 120000 index 000000000..e05cdb2ce --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ConnectivityManagerImpl_WiFi.cpp b/examples/blemesh_bridge/platform/ESP32_custom/ConnectivityManagerImpl_WiFi.cpp new file mode 120000 index 000000000..bec52cc5a --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/DeviceNetworkProvisioningDelegateImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/DeviceNetworkProvisioningDelegateImpl.cpp new file mode 120000 index 000000000..2440f220f --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/DeviceNetworkProvisioningDelegateImpl.cpp @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/DeviceNetworkProvisioningDelegateImpl.cpp \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/DeviceNetworkProvisioningDelegateImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/DeviceNetworkProvisioningDelegateImpl.h new file mode 120000 index 000000000..b1ebe37f0 --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/DeviceNetworkProvisioningDelegateImpl.h @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/DeviceNetworkProvisioningDelegateImpl.h \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/DiagnosticDataProviderImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/DiagnosticDataProviderImpl.cpp new file mode 120000 index 000000000..d862b94f3 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/DiagnosticDataProviderImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/DiagnosticDataProviderImpl.h new file mode 120000 index 000000000..f511e3f96 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/DnssdImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/DnssdImpl.cpp new file mode 120000 index 000000000..7c3d1750e --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/DnssdImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/DnssdImpl.h new file mode 120000 index 000000000..def841260 --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/DnssdImpl.h @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/DnssdImpl.h \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/ESP32Config.cpp b/examples/blemesh_bridge/platform/ESP32_custom/ESP32Config.cpp new file mode 120000 index 000000000..35426336b --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ESP32Config.h b/examples/blemesh_bridge/platform/ESP32_custom/ESP32Config.h new file mode 120000 index 000000000..6da6614ca --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ESP32FactoryDataProvider.cpp b/examples/blemesh_bridge/platform/ESP32_custom/ESP32FactoryDataProvider.cpp new file mode 120000 index 000000000..7baa4c683 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ESP32FactoryDataProvider.h b/examples/blemesh_bridge/platform/ESP32_custom/ESP32FactoryDataProvider.h new file mode 120000 index 000000000..1b201888a --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ESP32Utils.cpp b/examples/blemesh_bridge/platform/ESP32_custom/ESP32Utils.cpp new file mode 120000 index 000000000..0b450b25d --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/ESP32Utils.cpp @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/ESP32Utils.cpp \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/ESP32Utils.h b/examples/blemesh_bridge/platform/ESP32_custom/ESP32Utils.h new file mode 120000 index 000000000..6c2662622 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/InetPlatformConfig.h b/examples/blemesh_bridge/platform/ESP32_custom/InetPlatformConfig.h new file mode 120000 index 000000000..df165cf5f --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/KeyValueStoreManagerImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/KeyValueStoreManagerImpl.cpp new file mode 120000 index 000000000..4719ba527 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/KeyValueStoreManagerImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/KeyValueStoreManagerImpl.h new file mode 120000 index 000000000..7a4fe11b4 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/Logging.cpp b/examples/blemesh_bridge/platform/ESP32_custom/Logging.cpp new file mode 120000 index 000000000..a26787a10 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/LwIPCoreLock.cpp b/examples/blemesh_bridge/platform/ESP32_custom/LwIPCoreLock.cpp new file mode 120000 index 000000000..a13ea0401 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/NetworkCommissioningDriver.cpp b/examples/blemesh_bridge/platform/ESP32_custom/NetworkCommissioningDriver.cpp new file mode 120000 index 000000000..8274bdc1f --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/NetworkCommissioningDriver.h b/examples/blemesh_bridge/platform/ESP32_custom/NetworkCommissioningDriver.h new file mode 120000 index 000000000..f155452ce --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/OTAImageProcessorImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/OTAImageProcessorImpl.cpp new file mode 120000 index 000000000..e3a2f4fe8 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/OTAImageProcessorImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/OTAImageProcessorImpl.h new file mode 120000 index 000000000..9ca0a59ce --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/OpenthreadConfig.h b/examples/blemesh_bridge/platform/ESP32_custom/OpenthreadConfig.h new file mode 120000 index 000000000..233273862 --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/OpenthreadConfig.h @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/OpenthreadConfig.h \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/OpenthreadLauncher.c b/examples/blemesh_bridge/platform/ESP32_custom/OpenthreadLauncher.c new file mode 120000 index 000000000..340af8979 --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/OpenthreadLauncher.c @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/OpenthreadLauncher.c \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/OpenthreadLauncher.h b/examples/blemesh_bridge/platform/ESP32_custom/OpenthreadLauncher.h new file mode 120000 index 000000000..f8ff66bec --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/PlatformManagerImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/PlatformManagerImpl.cpp new file mode 120000 index 000000000..d1aa66386 --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/PlatformManagerImpl.cpp @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/PlatformManagerImpl.cpp \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/PlatformManagerImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/PlatformManagerImpl.h new file mode 120000 index 000000000..f1cc30be5 --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/PlatformManagerImpl.h @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/PlatformManagerImpl.h \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/ScopedNvsHandle.h b/examples/blemesh_bridge/platform/ESP32_custom/ScopedNvsHandle.h new file mode 120000 index 000000000..a6c58071b --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/SystemPlatformConfig.h b/examples/blemesh_bridge/platform/ESP32_custom/SystemPlatformConfig.h new file mode 120000 index 000000000..d2a9e2733 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/SystemTimeSupport.cpp b/examples/blemesh_bridge/platform/ESP32_custom/SystemTimeSupport.cpp new file mode 120000 index 000000000..7a55addaf --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/SystemTimeSupport.h b/examples/blemesh_bridge/platform/ESP32_custom/SystemTimeSupport.h new file mode 120000 index 000000000..2a8ab803f --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ThreadStackManagerImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/ThreadStackManagerImpl.cpp new file mode 120000 index 000000000..5c7137c11 --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/ThreadStackManagerImpl.h b/examples/blemesh_bridge/platform/ESP32_custom/ThreadStackManagerImpl.h new file mode 120000 index 000000000..6f2dbc44b --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/WarmPlatformConfig.h b/examples/blemesh_bridge/platform/ESP32_custom/WarmPlatformConfig.h new file mode 120000 index 000000000..3e4449f3c --- /dev/null +++ b/examples/blemesh_bridge/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/blemesh_bridge/platform/ESP32_custom/bluedroid b/examples/blemesh_bridge/platform/ESP32_custom/bluedroid new file mode 120000 index 000000000..fb50c353e --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/bluedroid @@ -0,0 +1 @@ +../../../../connectedhomeip/connectedhomeip/src/platform/ESP32/bluedroid \ No newline at end of file diff --git a/examples/blemesh_bridge/platform/ESP32_custom/nimble/BLEManagerImpl.cpp b/examples/blemesh_bridge/platform/ESP32_custom/nimble/BLEManagerImpl.cpp new file mode 100644 index 000000000..28c89518d --- /dev/null +++ b/examples/blemesh_bridge/platform/ESP32_custom/nimble/BLEManagerImpl.cpp @@ -0,0 +1,1364 @@ +/* + * + * 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" + +#if CONFIG_BT_NIMBLE_ENABLED + +#include +#include +#include +#include +#include +#include +#include + +#include "esp_log.h" +#include "esp_nimble_hci.h" +#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" + +#if CONFIG_BLE_MESH + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_ble_api.h" +#include "esp_ble_mesh_proxy_api.h" +#include "esp_ble_mesh_common_api.h" +#include "esp_ble_mesh_low_power_api.h" +#include "esp_ble_mesh_networking_api.h" +#include "esp_ble_mesh_provisioning_api.h" +#include "esp_ble_mesh_local_data_operation_api.h" + +#include "esp_ble_mesh_config_model_api.h" +#include "esp_ble_mesh_generic_model_api.h" + +#endif + +#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 { + +struct ESP32ChipServiceData +{ + uint8_t ServiceUUID[2]; + ChipBLEDeviceIdentificationInfo DeviceIdInfo; +}; + +const ble_uuid16_t ShortUUID_CHIPoBLEService = { BLE_UUID_TYPE_16, 0xFFF6 }; + +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 ChipBleUUID chipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x11 } }; + +const ChipBleUUID chipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, + 0x9D, 0x12 } }; +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 } +}; + +#if 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 + +SemaphoreHandle_t semaphoreHandle = NULL; + +} // unnamed namespace + +BLEManagerImpl BLEManagerImpl::sInstance; +constexpr System::Clock::Timeout BLEManagerImpl::kAdvertiseTimeout; +constexpr System::Clock::Timeout BLEManagerImpl::kFastAdvertiseTimeout; + +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_NOTIFY, + .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 */ + }, + } }, + + { + 0, /* No more services. */ + }, +}; + +CHIP_ERROR BLEManagerImpl::_Init() +{ + CHIP_ERROR err; + + // Initialize the Chip BleLayer. + err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer()); + SuccessOrExit(err); + + mRXCharAttrHandle = 0; +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + mC3CharAttrHandle = 0; +#endif + mTXCharCCCDAttrHandle = 0; + mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART); + mFlags.Set(Flags::kFastAdvertisingEnabled, true); + mNumGAPCons = 0; + memset(mCons, 0, sizeof(mCons)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + memset(mDeviceName, 0, sizeof(mDeviceName)); + + PlatformMgr().ScheduleWork(DriveBLEState, 0); + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (val != mServiceMode) + { + mServiceMode = val; + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (val) + { + mAdvertiseStartTime = System::SystemClock().GetMonotonicTimestamp(); + ReturnErrorOnFailure(DeviceLayer::SystemLayer().StartTimer(kAdvertiseTimeout, HandleAdvertisementTimer, this)); + ReturnErrorOnFailure(DeviceLayer::SystemLayer().StartTimer(kFastAdvertiseTimeout, HandleFastAdvertisementTimer, this)); + } + + mFlags.Set(Flags::kFastAdvertisingEnabled, val); + mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); + mFlags.Set(Flags::kAdvertisingEnabled, val); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + +exit: + return err; +} + +void BLEManagerImpl::HandleAdvertisementTimer(System::Layer * systemLayer, void * context) +{ + static_cast(context)->HandleAdvertisementTimer(); +} + +void BLEManagerImpl::HandleAdvertisementTimer() +{ + System::Clock::Timestamp currentTimestamp = System::SystemClock().GetMonotonicTimestamp(); + + if (currentTimestamp - mAdvertiseStartTime >= kAdvertiseTimeout) + { + mFlags.Set(Flags::kAdvertisingEnabled, 0); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } +} + +void BLEManagerImpl::HandleFastAdvertisementTimer(System::Layer * systemLayer, void * context) +{ + static_cast(context)->HandleFastAdvertisementTimer(); +} + +void BLEManagerImpl::HandleFastAdvertisementTimer() +{ + System::Clock::Timestamp currentTimestamp = System::SystemClock().GetMonotonicTimestamp(); + + if (currentTimestamp - mAdvertiseStartTime >= kFastAdvertiseTimeout) + { + mFlags.Set(Flags::kFastAdvertisingEnabled, 0); + mFlags.Set(Flags::kAdvertisingRefreshNeeded, 1); + 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, &chipUUID_CHIPoBLEChar_TX); + { + ChipDeviceEvent connectionEvent; + connectionEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; + PlatformMgr().PostEventOrDie(&connectionEvent); + } + break; + + case DeviceEventType::kCHIPoBLEUnsubscribe: + HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); + break; + + case DeviceEventType::kCHIPoBLEWriteReceived: + HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_RX, + PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); + break; + + case DeviceEventType::kCHIPoBLEIndicateConfirm: + HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &chipUUID_CHIPoBLEChar_TX); + break; + + case DeviceEventType::kCHIPoBLEConnectionError: + HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); + break; + + case DeviceEventType::kFabricMembershipChange: + case DeviceEventType::kServiceProvisioningChange: + case DeviceEventType::kAccountPairingChange: + case DeviceEventType::kWiFiConnectivityChange: + + // If CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, and there is a change to the + // device's provisioning state, then automatically disable CHIPoBLE advertising if the device + // is now fully provisioned. +#if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED + if (ConfigurationMgr().IsFullyProvisioned()) + { + mFlags.Clear(Flags::kAdvertisingEnabled); + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned"); + } +#endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED + + // 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: + break; + } +} + +bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogProgress(DeviceLayer, "BLEManagerImpl::SubscribeCharacteristic() not supported"); + return false; +} + +bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogProgress(DeviceLayer, "BLEManagerImpl::UnsubscribeCharacteristic() not supported"); + return false; +} + +bool 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)); + } + + // Force a refresh of the advertising state. + mFlags.Set(Flags::kAdvertisingRefreshNeeded); + mFlags.Clear(Flags::kAdvertisingConfigured); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + + return (err == CHIP_NO_ERROR); +} + +uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const +{ + return ble_att_mtu(conId); +} + +bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + 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()); + + om = ble_hs_mbuf_from_flat(data->Start(), data->DataLength()); + if (om == NULL) + { + ChipLogError(DeviceLayer, "ble_hs_mbuf_from_flat failed:"); + err = CHIP_ERROR_NO_MEMORY; + ExitNow(); + } + + err = MapBLEError(ble_gattc_notify_custom(conId, mTXCharCCCDAttrHandle, om)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gattc_notify_custom() failed: %s", ErrorStr(err)); + ExitNow(); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "BLEManagerImpl::SendIndication() failed: %s", ErrorStr(err)); + return false; + } + return true; +} + +bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogError(DeviceLayer, "BLEManagerImpl::SendWriteRequest() not supported"); + return false; +} + +bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogError(DeviceLayer, "BLEManagerImpl::SendReadRequest() not supported"); + return false; +} + +bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, + const ChipBleUUID * svcId, const ChipBleUUID * charId) +{ + ChipLogError(DeviceLayer, "BLEManagerImpl::SendReadResponse() not supported"); + return false; +} + +void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) {} + +CHIP_ERROR BLEManagerImpl::MapBLEError(int bleErr) +{ + switch (bleErr) + { + case ESP_OK: + return CHIP_NO_ERROR; + case BLE_HS_EMSGSIZE: + return CHIP_ERROR_INVALID_MESSAGE_LENGTH; + 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_READ_FAILED; + 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); + } +} + +#if CONFIG_BLE_MESH + +extern "C" esp_err_t app_ble_mesh_init(void); + +static uint8_t chipoble_index = 0xFF; +static esp_ble_mesh_ble_adv_data_t chipoble_adv_packet = {0}; +static struct ble_gap_event_listener chipoble_gap_event_listener = {0}; + +static void ble_mesh_ble_cb(esp_ble_mesh_ble_cb_event_t event, esp_ble_mesh_ble_cb_param_t *param) +{ + switch (event) { + case ESP_BLE_MESH_START_BLE_ADVERTISING_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_START_BLE_ADVERTISING_COMP_EVT, index %d, err_code %d", param->start_ble_advertising_comp.index, param->start_ble_advertising_comp.err_code); + chipoble_index = param->start_ble_advertising_comp.index; + break; + case ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT: + ESP_LOGI(TAG, "ESP_BLE_MESH_STOP_BLE_ADVERTISING_COMP_EVT, err_code %d", param->stop_ble_advertising_comp.err_code); + chipoble_index = 0xFF; + break; + default: + break; + } + + return; +} + +#endif + +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); + + // If CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, + // disable CHIPoBLE advertising if the device is fully provisioned. +#if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED + if (ConfigurationMgr().IsFullyProvisioned()) + { + mFlags.Clear(Flags::kAdvertisingEnabled); + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned"); + } +#endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED + } + + // 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_RATE_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(); + } + } + + // 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(); + } + + 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 CONFIG_BLE_MESH + if (chipoble_index != 0xFF) +#else + if (ble_gap_adv_active()) +#endif + { +#if CONFIG_BLE_MESH + ChipLogError(DeviceLayer, "adv stop"); + err = MapBLEError(esp_ble_mesh_stop_ble_advertising(chipoble_index)); +#else + err = MapBLEError(ble_gap_adv_stop()); +#endif + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %s", ErrorStr(err)); + ExitNow(); + } + } + // mFlags.Clear(Flags::kAdvertisingRefreshNeeded); + + // Transition to the not Advertising state... + if (mFlags.Has(Flags::kAdvertising)) + { + mFlags.Clear(Flags::kAdvertising); + mFlags.Set(Flags::kFastAdvertisingEnabled, true); + + ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped"); + + // 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)) + { + // TODO: Not supported + } + +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); +} + +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; + } + + err = MapBLEError(esp_nimble_hci_and_controller_init()); + SuccessOrExit(err); + + 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(); + + err = MapBLEError(ble_gatts_count_cfg(CHIPoBLEGATTAttrs)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gatts_count_cfg failed: %s", ErrorStr(err)); + ExitNow(); + } + + err = MapBLEError(ble_gatts_add_svcs(CHIPoBLEGATTAttrs)); + 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; + +#if CONFIG_BLE_MESH + esp_ble_mesh_register_ble_callback(ble_mesh_ble_cb); + app_ble_mesh_init(); +#endif + + sInstance.mFlags.Set(Flags::kESPBLELayerInitialized); + sInstance.mFlags.Set(Flags::kGATTServiceStarted); + +exit: + return err; +} + +CHIP_ERROR BLEManagerImpl::ConfigureAdvertisingData(void) +{ + CHIP_ERROR err; + uint8_t advData[MAX_ADV_DATA_LEN]; + 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(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 + + err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(deviceIdInfo); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "GetBLEDeviceIdentificationInfo(): %s", ErrorStr(err)); + ExitNow(); + } + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + deviceIdInfo.SetAdditionalDataFlag(true); +#endif + + VerifyOrExit(index + sizeof(deviceIdInfo) <= sizeof(advData), err = CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG); + memcpy(&advData[index], &deviceIdInfo, sizeof(deviceIdInfo)); + index = static_cast(index + sizeof(deviceIdInfo)); + +#if CONFIG_BLE_MESH + chipoble_adv_packet.adv_data_len = sizeof(advData); + memcpy(chipoble_adv_packet.adv_data, advData, sizeof(advData)); + ESP_LOGD(TAG, "set chipoble advertisement data"); +#else + // 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(); + } +#endif + +exit: + return err; +} + +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; + bool notificationsEnabled; + + ChipLogProgress(DeviceLayer, + "Write request/command received for CHIPoBLE TX CCCD characteristic (con %u" + " ) indicate = %d notify = %d", + gapEvent->subscribe.conn_handle, gapEvent->subscribe.cur_indicate, gapEvent->subscribe.cur_notify); + + // Determine if the client is enabling or disabling indications/notification. + indicationsEnabled = gapEvent->subscribe.cur_indicate; + notificationsEnabled = gapEvent->subscribe.cur_notify; + + // If the client has requested to enabled indications/notifications + if (indicationsEnabled || notificationsEnabled) + { + // 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 || notificationsEnabled) ? DeviceEventType::kCHIPoBLESubscribe + : DeviceEventType::kCHIPoBLEUnsubscribe; + event.CHIPoBLESubscribe.ConId = gapEvent->subscribe.conn_handle; + err = PlatformMgr().PostEvent(&event); + } + + ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", + (indicationsEnabled || notificationsEnabled) ? "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 == 0 || 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; +} + +CHIP_ERROR BLEManagerImpl::HandleGAPConnect(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::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--; + } + + 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; + } + HandleConnectionError(gapEvent->disconnect.conn.conn_handle, disconReason); + } + + 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: + 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; + + default: + break; + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); + sInstance.mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + } + +#if CONFIG_BLE_MESH + if (event->type != BLE_GAP_EVENT_DISC) { +#endif + // Schedule DriveBLEState() to run. + PlatformMgr().ScheduleWork(DriveBLEState, 0); +#if CONFIG_BLE_MESH + } +#endif + + 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 = ConfigurationMgr().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 (%s)", __func__); + } + 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_adv_params adv_params; + memset(&adv_params, 0, sizeof(adv_params)); +#ifdef CONFIG_BT_NIMBLE_HOST_BASED_PRIVACY + uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM; +#else + uint8_t own_addr_type = BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT; +#endif + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; + + 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; + + // 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 + { + adv_params.itvl_min = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; + adv_params.itvl_max = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + } + + ChipLogProgress(DeviceLayer, "Configuring CHIPoBLE advertising (interval %" PRIu32 " ms, %sconnectable, device name %s)", + (((uint32_t) adv_params.itvl_min) * 10) / 16, (connectable) ? "" : "non-", mDeviceName); + + { +#if CONFIG_BLE_MESH + if (chipoble_index != 0xFF) +#else + if (ble_gap_adv_active()) +#endif + { + /* Advertising is already active. Stop and restart with the new parameters */ + ChipLogProgress(DeviceLayer, "Device already advertising, stop active advertisement and restart"); +#if CONFIG_BLE_MESH + err = MapBLEError(esp_ble_mesh_stop_ble_advertising(chipoble_index)); +#else + err = MapBLEError(ble_gap_adv_stop()); +#endif + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "ble_gap_adv_stop() failed: %s, cannot restart", ErrorStr(err)); + return err; + } + } +#if CONFIG_BT_NIMBLE_HOST_BASED_PRIVACY + else + { + err = MapBLEError(ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA)); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "RPA not set: %s", ErrorStr(err)); + return err; + } + } +#endif + +#if CONFIG_BLE_MESH + esp_ble_mesh_ble_adv_param_t chipoble_adv_param = { + // .interval = interval, + // .adv_type = BLE_MESH_ADV_IND, + .own_addr_type = own_addr_type, + .duration = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN, + .period = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX, + .count = 0XFFFF, + .priority = BLE_MESH_BLE_ADV_PRIO_LOW, + }; + + chipoble_adv_param.adv_type = connectable ? BLE_MESH_ADV_IND : BLE_MESH_ADV_NONCONN_IND; + // Advertise in fast mode if it is connectable advertisement and + // the application has expressly requested fast advertising. + if (connectable && mFlags.Has(Flags::kFastAdvertisingEnabled)) { + chipoble_adv_param.interval = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN; + } else { + chipoble_adv_param.interval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN; + } + + ble_gap_event_listener_register(&chipoble_gap_event_listener, ble_svr_gap_event, NULL); + + err = MapBLEError(esp_ble_mesh_start_ble_advertising(&chipoble_adv_param, &chipoble_adv_packet)); + ESP_LOGD(TAG, "start chipoble advertisement"); +#else + err = MapBLEError(ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER, &adv_params, ble_svr_gap_event, NULL)); +#endif + if (err == CHIP_NO_ERROR) + { + return CHIP_NO_ERROR; + } + else + { + ChipLogError(DeviceLayer, "ble_gap_adv_start() failed: %s", ErrorStr(err)); + return err; + } + } +} + +void BLEManagerImpl::DriveBLEState(intptr_t arg) +{ + sInstance.DriveBLEState(); +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif // CONFIG_BT_NIMBLE_ENABLED + +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/examples/blemesh_bridge/sdkconfig.defaults b/examples/blemesh_bridge/sdkconfig.defaults new file mode 100644 index 000000000..de7501bb4 --- /dev/null +++ b/examples/blemesh_bridge/sdkconfig.defaults @@ -0,0 +1,46 @@ +# Default to 921600 baud when flashing and monitoring device +CONFIG_ESPTOOLPY_BAUD_921600B=y +CONFIG_ESPTOOLPY_BAUD=921600 +CONFIG_ESPTOOLPY_COMPRESSED=y +CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y + +# Enable BT +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +CONFIG_BT_NIMBLE_TASK_STACK_SIZE=5120 +CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y +CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y + +# Enable BLE MESH +CONFIG_BLE_MESH=y +CONFIG_BLE_MESH_PROVISIONER=y +CONFIG_BLE_MESH_PB_GATT=y +CONFIG_BLE_MESH_SETTINGS=y +CONFIG_BLE_MESH_CFG_CLI=y +CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y +CONFIG_BLE_MESH_SUPPORT_BLE_ADV=y + +# Enable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=y + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" + +# Disable chip shell and test +CONFIG_ENABLE_CHIP_SHELL=n +CONFIG_BUILD_CHIP_TESTS=n + +# Enable External Platform +CONFIG_CHIP_ENABLE_EXTERNAL_PLATFORM=y +CONFIG_CHIP_EXTERNAL_PLATFORM_DIR="../../../../examples/blemesh_bridge/platform/ESP32_custom" + +# Enable lwIP route hooks +CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y +CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y + +# Watchdog +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n +CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=n diff --git a/examples/common/app_bridge/CMakeLists.txt b/examples/common/app_bridge/CMakeLists.txt index 338b9269a..79a3af679 100644 --- a/examples/common/app_bridge/CMakeLists.txt +++ b/examples/common/app_bridge/CMakeLists.txt @@ -1,7 +1,3 @@ -if(CONFIG_ZB_ENABLED) - set(srcs app_zigbee_bridge_device.cpp) -endif() - -idf_component_register(SRCS "${srcs}" +idf_component_register(SRCS "app_bridged_device.cpp" INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}" REQUIRES esp_matter_bridge) diff --git a/examples/common/app_bridge/app_bridged_device.cpp b/examples/common/app_bridge/app_bridged_device.cpp new file mode 100644 index 000000000..dc898370d --- /dev/null +++ b/examples/common/app_bridge/app_bridged_device.cpp @@ -0,0 +1,192 @@ +// Copyright 2022 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include + +using esp_matter::node_t; + +static const char *TAG = "app_bridged_device"; +static app_bridged_device_t *g_bridged_device_list = NULL; +static uint8_t g_current_bridged_device_count = 0; + +/** Bridged Device's Address APIs */ +app_bridged_device_address_t app_bridge_zigbee_address(uint8_t zigbee_endpointid, uint16_t zigbee_shortaddr) +{ + app_bridged_device_address_t bridged_address = { + { + .zigbee_endpointid = zigbee_endpointid, + .zigbee_shortaddr = zigbee_shortaddr, + }, + }; + return bridged_address; +} + +app_bridged_device_address_t app_bridge_blemesh_address(uint16_t blemesh_addr) +{ + app_bridged_device_address_t bridged_address = { + .blemesh_addr = blemesh_addr, + }; + return bridged_address; +} + +/** Bridged Device APIs */ +app_bridged_device_t *app_bridge_create_bridged_device(node_t *node, + app_bridged_device_type_t bridged_device_type, app_bridged_device_address_t bridged_device_address) +{ + if (g_current_bridged_device_count >= MAX_BRIDGED_DEVICE_COUNT) { + ESP_LOGE(TAG, "The device list is full, Could not add a zigbee bridged device"); + return NULL; + } + app_bridged_device_t *new_dev = (app_bridged_device_t *)calloc(1, sizeof(app_bridged_device_t)); + new_dev->dev = esp_matter_bridge_create_device(node); + if (!(new_dev->dev)) { + ESP_LOGE(TAG, "Failed to create the basic bridged device"); + free(new_dev); + return NULL; + } + new_dev->dev_type = bridged_device_type; + new_dev->dev_addr = bridged_device_address; + new_dev->next = g_bridged_device_list; + g_bridged_device_list = new_dev; + g_current_bridged_device_count++; + return new_dev; +} + +app_bridged_device_t *app_bridge_get_device_by_matter_endpointid(uint16_t matter_endpointid) +{ + app_bridged_device_t *current_dev = g_bridged_device_list; + while (current_dev) { + if (current_dev->dev && (current_dev->dev->endpoint_id == matter_endpointid)) { + return current_dev; + } + current_dev = current_dev->next; + } + return NULL; +} + +esp_err_t app_bridge_remove_device(app_bridged_device_t *bridged_device) +{ + esp_err_t error = ESP_OK; + app_bridged_device_t *current_dev = NULL; + if (!bridged_device) { + return ESP_ERR_INVALID_ARG; + } + if (g_bridged_device_list == bridged_device) { + // the delete bridged device is on the head of device list + g_bridged_device_list = bridged_device->next; + } else { + current_dev = g_bridged_device_list; + while (current_dev && current_dev->next) { + if (current_dev->next == bridged_device) { + break; + } + current_dev = current_dev->next; + } + if (current_dev->next == bridged_device) { + current_dev->next = bridged_device->next; + } else { + return ESP_ERR_NOT_FOUND; + } + } + error = esp_matter_bridge_remove_device(bridged_device->dev); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Failed to delete basic bridged devie"); + } + free(bridged_device); + return error; +} + +/** ZigBee Device APIs */ +app_bridged_device_t *app_bridge_get_device_by_zigbee_shortaddr(uint16_t zigbee_shortaddr) +{ + app_bridged_device_t *current_dev = g_bridged_device_list; + while (current_dev) { + if (current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_ZIGBEE && current_dev->dev + && current_dev->dev_addr.zigbee_shortaddr == zigbee_shortaddr) { + return current_dev; + } + current_dev = current_dev->next; + } + return NULL; +} + +uint16_t app_bridge_get_matter_endpointid_by_zigbee_shortaddr(uint16_t zigbee_shortaddr) +{ + app_bridged_device_t *current_dev = g_bridged_device_list; + while (current_dev) { + if (current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_ZIGBEE && current_dev->dev + && current_dev->dev_addr.zigbee_shortaddr == zigbee_shortaddr) { + return current_dev->dev->endpoint_id; + } + current_dev = current_dev->next; + } + return 0xFFFF; +} + +uint16_t app_bridge_get_zigbee_shortaddr_by_matter_endpointid(uint16_t matter_endpointid) +{ + app_bridged_device_t *current_dev = g_bridged_device_list; + while (current_dev) { + if ((current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_ZIGBEE) && current_dev->dev + && (current_dev->dev->endpoint_id == matter_endpointid)) { + return current_dev->dev_addr.zigbee_shortaddr; + } + current_dev = current_dev->next; + } + return 0xFFFF; +} + +/** BLE Mesh Device APIs */ +app_bridged_device_t *app_bridge_get_device_by_blemesh_addr(uint16_t blemesh_addr) +{ + app_bridged_device_t *current_dev = g_bridged_device_list; + while (current_dev) { + if ((current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_BLEMESH) && current_dev->dev + && (current_dev->dev_addr.blemesh_addr == blemesh_addr)) { + return current_dev; + } + current_dev = current_dev->next; + } + return NULL; +} + +uint16_t app_bridge_get_matter_endpointid_by_blemesh_addr(uint16_t blemesh_addr) +{ + app_bridged_device_t *current_dev = g_bridged_device_list; + while (current_dev) { + if ((current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_BLEMESH) && current_dev->dev + && (current_dev->dev_addr.blemesh_addr == blemesh_addr)) { + return current_dev->dev->endpoint_id; + } + current_dev = current_dev->next; + } + return 0xFFFF; +} + +uint16_t app_bridge_get_blemesh_addr_by_matter_endpointid(uint16_t matter_endpointid) +{ + app_bridged_device_t *current_dev = g_bridged_device_list; + while (current_dev) { + if ((current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_BLEMESH) && current_dev->dev + && (current_dev->dev->endpoint_id == matter_endpointid)) { + return current_dev->dev_addr.blemesh_addr; + } + current_dev = current_dev->next; + } + return 0xFFFF; +} diff --git a/examples/common/app_bridge/app_bridged_device.h b/examples/common/app_bridge/app_bridged_device.h new file mode 100644 index 000000000..64025ba1e --- /dev/null +++ b/examples/common/app_bridge/app_bridged_device.h @@ -0,0 +1,81 @@ +// Copyright 2022 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include + +using esp_matter::node_t; + +/** Bridged Device Type */ +typedef enum { + /** ZigBee */ + ESP_MATTER_BRIDGED_DEVICE_TYPE_ZIGBEE = 0, + /** BLE Mesh */ + ESP_MATTER_BRIDGED_DEVICE_TYPE_BLEMESH, +} app_bridged_device_type_t; + +/* Bridged Device Address */ +typedef union { + /** ZigBee */ + struct { + uint8_t zigbee_endpointid; + uint16_t zigbee_shortaddr; + }; + /** BLE Mesh */ + struct { + uint16_t blemesh_addr; + }; +} app_bridged_device_address_t; + +/* Bridged Device */ +typedef struct app_bridged_device { + /** Bridged Device */ + esp_matter_bridge_device_t *dev; + /** Type of Bridged Device */ + app_bridged_device_type_t dev_type; + /** Address of Bridged Device */ + app_bridged_device_address_t dev_addr; + /** Pointer of Next Bridged Device */ + struct app_bridged_device *next; +} app_bridged_device_t; + +/** Bridged Device's Address APIs */ +app_bridged_device_address_t app_bridge_zigbee_address(uint8_t zigbee_endpointid, uint16_t zigbee_shortaddr); + +app_bridged_device_address_t app_bridge_blemesh_address(uint16_t blemesh_addr); + +/** Bridged Device APIs */ +app_bridged_device_t *app_bridge_create_bridged_device(node_t *node, + app_bridged_device_type_t bridged_device_type, app_bridged_device_address_t bridged_device_address); + +app_bridged_device_t *app_bridge_get_device_by_matter_endpointid(uint16_t matter_endpointid); + +esp_err_t app_bridge_remove_device(app_bridged_device_t *bridged_device); + +/** ZigBee Device APIs */ +app_bridged_device_t *app_bridge_get_device_by_zigbee_shortaddr(uint16_t zigbee_shortaddr); + +uint16_t app_bridge_get_matter_endpointid_by_zigbee_shortaddr(uint16_t zigbee_shortaddr); + +uint16_t app_bridge_get_zigbee_shortaddr_by_matter_endpointid(uint16_t matter_endpointid); + +/** BLE Mesh Device APIs */ +app_bridged_device_t *app_bridge_get_device_by_blemesh_addr(uint16_t blemesh_addr); + +uint16_t app_bridge_get_matter_endpointid_by_blemesh_addr(uint16_t blemesh_addr); + +uint16_t app_bridge_get_blemesh_addr_by_matter_endpointid(uint16_t matter_endpointid); diff --git a/examples/common/app_bridge/app_zigbee_bridge_device.cpp b/examples/common/app_bridge/app_zigbee_bridge_device.cpp deleted file mode 100644 index 419137b55..000000000 --- a/examples/common/app_bridge/app_zigbee_bridge_device.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2022 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include - -using esp_matter::node_t; - -static const char *TAG = "esp_matter_zigbee_bridge"; -static app_zigbee_bridge_device_t *device_list = NULL; -static uint8_t current_bridged_device_count = 0; - -app_zigbee_bridge_device_t *app_bridge_create_zigbee_device(node_t *node, uint8_t zigbee_endpointid, - uint16_t zigbee_shortaddr) -{ - if (current_bridged_device_count >= MAX_BRIDGED_DEVICE_COUNT) { - ESP_LOGE(TAG, "The device list is full, Could not add a zigbee bridged device"); - return NULL; - } - app_zigbee_bridge_device_t *new_dev = (app_zigbee_bridge_device_t *)calloc(1, sizeof(app_zigbee_bridge_device_t)); - new_dev->dev = esp_matter_bridge_create_device(node); - if (!(new_dev->dev)) { - ESP_LOGE(TAG, "Failed to create the basic bridged device"); - free(new_dev); - return NULL; - } - new_dev->zigbee_shortaddr = zigbee_shortaddr; - new_dev->zigbee_endpointid = zigbee_endpointid; - new_dev->next = device_list; - device_list = new_dev; - current_bridged_device_count++; - return new_dev; -} - -uint16_t app_bridge_get_zigbee_shortaddr_by_matter_endpointid(uint16_t matter_endpointid) -{ - app_zigbee_bridge_device_t *current_dev = device_list; - while (current_dev) { - if (current_dev->dev && (current_dev->dev->endpoint_id == matter_endpointid)) { - return current_dev->zigbee_shortaddr; - } - current_dev = current_dev->next; - } - return 0xffff; -} - -uint16_t app_bridge_get_matter_endpointid_by_zigbee_shortaddr(uint16_t zigbee_shortaddr) -{ - app_zigbee_bridge_device_t *current_dev = device_list; - while (current_dev) { - if (current_dev->zigbee_shortaddr == zigbee_shortaddr && current_dev->dev) { - return current_dev->dev->endpoint_id; - } - current_dev = current_dev->next; - } - return 0xFFFF; -} - -app_zigbee_bridge_device_t *app_bridge_get_zigbee_device_by_matter_endpointid(uint16_t matter_endpointid) -{ - app_zigbee_bridge_device_t *current_dev = device_list; - while (current_dev) { - if (current_dev->dev && (current_dev->dev->endpoint_id == matter_endpointid)) { - return current_dev; - } - current_dev = current_dev->next; - } - return NULL; -} - -app_zigbee_bridge_device_t *app_bridge_get_zigbee_device_by_zigbee_shortaddr(uint16_t zigbee_shortaddr) -{ - app_zigbee_bridge_device_t *current_dev = device_list; - while (current_dev) { - if (current_dev->zigbee_shortaddr == zigbee_shortaddr && current_dev->dev) { - return current_dev; - } - current_dev = current_dev->next; - } - return NULL; -} - -esp_err_t app_bridge_remove_zigbee_device(app_zigbee_bridge_device_t *bridged_device) -{ - esp_err_t error = ESP_OK; - app_zigbee_bridge_device_t *current_dev = NULL; - if (!bridged_device) { - return ESP_ERR_INVALID_ARG; - } - if (device_list == bridged_device) { - // the delete bridged device is on the head of device list - device_list = bridged_device->next; - } else { - current_dev = device_list; - while (current_dev && current_dev->next) { - if (current_dev->next == bridged_device) { - break; - } - current_dev = current_dev->next; - } - if (current_dev->next == bridged_device) { - current_dev->next = bridged_device->next; - } else { - return ESP_ERR_NOT_FOUND; - } - } - error = esp_matter_bridge_remove_device(bridged_device->dev); - if (error != ESP_OK) { - ESP_LOGE(TAG, "Failed to delete basic bridged devie"); - } - free(bridged_device); - return error; -} diff --git a/examples/common/app_bridge/app_zigbee_bridge_device.h b/examples/common/app_bridge/app_zigbee_bridge_device.h deleted file mode 100644 index 11b9d62ea..000000000 --- a/examples/common/app_bridge/app_zigbee_bridge_device.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2022 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once -#include -#if CONFIG_ZB_ENABLED -#include - -using esp_matter::node_t; - -typedef struct app_zigbee_bridge_device { - esp_matter_bridge_device_t *dev; - uint8_t zigbee_endpointid; - uint16_t zigbee_shortaddr; - struct app_zigbee_bridge_device *next; -} app_zigbee_bridge_device_t; - -app_zigbee_bridge_device_t *app_bridge_create_zigbee_device(node_t *node, uint8_t zigbee_endpointid, - uint16_t zigbee_shortaddr); - -uint16_t app_bridge_get_zigbee_shortaddr_by_matter_endpointid(uint16_t matter_endpointid); - -uint16_t app_bridge_get_matter_endpointid_by_zigbee_shortaddr(uint16_t zigbee_shortaddr); - -app_zigbee_bridge_device_t *app_bridge_get_zigbee_device_by_matter_endpointid(uint16_t matter_endpointid); - -app_zigbee_bridge_device_t *app_bridge_get_zigbee_device_by_zigbee_shortaddr(uint16_t zigbee_shortaddr); - -esp_err_t app_bridge_remove_zigbee_device(app_zigbee_bridge_device_t *bridged_device); -#endif diff --git a/examples/zigbee_bridge/README.md b/examples/zigbee_bridge/README.md index 689a239a5..09ba1d7d1 100644 --- a/examples/zigbee_bridge/README.md +++ b/examples/zigbee_bridge/README.md @@ -112,8 +112,8 @@ chip-tool onoff toggle 0x7283 0x1 The following is the Memory and Flash Usage. - `Bootup` == Device just finished booting up. Device is not - commissionined or connected to wifi yet. -- `After Commissioning` == Device is conneted to wifi and is also + commissioned or connected to wifi yet. +- `After Commissioning` == Device is connected to wifi and is also commissioned and is rebooted. - device used: esp32c3_devkit_m - tested on: diff --git a/examples/zigbee_bridge/main/app_main.cpp b/examples/zigbee_bridge/main/app_main.cpp index a0bce089c..a26aedcf0 100644 --- a/examples/zigbee_bridge/main/app_main.cpp +++ b/examples/zigbee_bridge/main/app_main.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include static const char *TAG = "app_main"; diff --git a/examples/zigbee_bridge/main/zigbee_bridge.cpp b/examples/zigbee_bridge/main/zigbee_bridge.cpp index 194f3d368..7e24c6f40 100644 --- a/examples/zigbee_bridge/main/zigbee_bridge.cpp +++ b/examples/zigbee_bridge/main/zigbee_bridge.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include @@ -23,7 +23,7 @@ static const char *TAG = "zigbee_bridge"; using namespace esp_matter; using namespace esp_matter::cluster; -static esp_err_t init_bridged_onoff_light(esp_matter_bridge_device_t *dev) +static esp_err_t zigbee_bridge_init_bridged_onoff_light(esp_matter_bridge_device_t *dev) { if (!dev) { ESP_LOGE(TAG, "Invalid bridge device to be initialized"); @@ -52,13 +52,13 @@ void zigbee_bridge_match_bridged_onoff_light_cb(zb_bufid_t bufid) p_match_ep = (zb_uint8_t *)(p_resp + 1); node_t *node = node::get(); ESP_GOTO_ON_FALSE(node, ESP_ERR_INVALID_STATE, exit, TAG, "Could not find esp_matter node"); - if (app_bridge_get_zigbee_device_by_zigbee_shortaddr(p_ind->src_addr)) { + if (app_bridge_get_device_by_zigbee_shortaddr(p_ind->src_addr)) { ESP_LOGI(TAG, "Bridged node for 0x%04x zigbee device on endpoint %d has been created", p_ind->src_addr, app_bridge_get_matter_endpointid_by_zigbee_shortaddr(p_ind->src_addr)); } else { - app_zigbee_bridge_device_t *dev = app_bridge_create_zigbee_device(node, *p_match_ep, p_ind->src_addr); - ESP_GOTO_ON_FALSE(dev, ESP_FAIL, exit, TAG, "Failed to create zigbee bridged device (on_off light)"); - ESP_GOTO_ON_ERROR(init_bridged_onoff_light(dev->dev), exit, TAG, "Failed to initialize the bridged node"); + app_bridged_device_t *bridged_device = app_bridge_create_bridged_device(node, ESP_MATTER_BRIDGED_DEVICE_TYPE_ZIGBEE, app_bridge_zigbee_address(*p_match_ep, p_ind->src_addr)); + ESP_GOTO_ON_FALSE(bridged_device, ESP_FAIL, exit, TAG, "Failed to create zigbee bridged device (on_off light)"); + ESP_GOTO_ON_ERROR(zigbee_bridge_init_bridged_onoff_light(bridged_device->dev), exit, TAG, "Failed to initialize the bridged node"); ESP_LOGI(TAG, "Create/Update bridged node for 0x%04x zigbee device on endpoint %d", p_ind->src_addr, app_bridge_get_matter_endpointid_by_zigbee_shortaddr(p_ind->src_addr)); } @@ -106,29 +106,30 @@ void zigbee_bridge_match_bridged_onoff_light_timeout(zb_bufid_t bufid) void zigbee_bridge_send_on(zb_uint8_t buf, zb_uint16_t zigbee_shortaddr) { - app_zigbee_bridge_device_t *dev = app_bridge_get_zigbee_device_by_zigbee_shortaddr(zigbee_shortaddr); - ZB_ZCL_ON_OFF_SEND_REQ(buf, zigbee_shortaddr, ZB_APS_ADDR_MODE_16_ENDP_PRESENT, dev->zigbee_endpointid, - dev->dev->endpoint_id, ZB_AF_HA_PROFILE_ID, ZB_ZCL_DISABLE_DEFAULT_RESPONSE, + app_bridged_device_t *zigbee_device = app_bridge_get_device_by_zigbee_shortaddr(zigbee_shortaddr); + ZB_ZCL_ON_OFF_SEND_REQ(buf, zigbee_shortaddr, ZB_APS_ADDR_MODE_16_ENDP_PRESENT, zigbee_device->dev_addr.zigbee_endpointid, + zigbee_device->dev->endpoint_id, ZB_AF_HA_PROFILE_ID, ZB_ZCL_DISABLE_DEFAULT_RESPONSE, ZB_ZCL_CMD_ON_OFF_ON_ID, NULL); } void zigbee_bridge_send_off(zb_uint8_t buf, zb_uint16_t zigbee_shortaddr) { - app_zigbee_bridge_device_t *dev = app_bridge_get_zigbee_device_by_zigbee_shortaddr(zigbee_shortaddr); - ZB_ZCL_ON_OFF_SEND_REQ(buf, zigbee_shortaddr, ZB_APS_ADDR_MODE_16_ENDP_PRESENT, dev->zigbee_endpointid, - dev->dev->endpoint_id, ZB_AF_HA_PROFILE_ID, ZB_ZCL_DISABLE_DEFAULT_RESPONSE, + app_bridged_device_t *zigbee_device = app_bridge_get_device_by_zigbee_shortaddr(zigbee_shortaddr); + ZB_ZCL_ON_OFF_SEND_REQ(buf, zigbee_shortaddr, ZB_APS_ADDR_MODE_16_ENDP_PRESENT, zigbee_device->dev_addr.zigbee_endpointid, + zigbee_device->dev->endpoint_id, ZB_AF_HA_PROFILE_ID, ZB_ZCL_DISABLE_DEFAULT_RESPONSE, ZB_ZCL_CMD_ON_OFF_OFF_ID, NULL); } esp_err_t zigbee_bridge_attribute_update(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val) { - app_zigbee_bridge_device_t *zigbee_device = app_bridge_get_zigbee_device_by_matter_endpointid(endpoint_id); + app_bridged_device_t *zigbee_device = app_bridge_get_device_by_matter_endpointid(endpoint_id); if (zigbee_device && zigbee_device->dev && zigbee_device->dev->endpoint) { if (cluster_id == OnOff::Id) { if (attribute_id == OnOff::Attributes::OnOff::Id) { + ESP_LOGD(TAG, "Update Bridged Device, ep: %d, cluster: %d, att: %d", endpoint_id, cluster_id, attribute_id); zb_buf_get_out_delayed_ext((val->val.b ? zigbee_bridge_send_on : zigbee_bridge_send_off), - zigbee_device->zigbee_shortaddr, 0); + zigbee_device->dev_addr.zigbee_shortaddr, 0); } } } diff --git a/examples/zigbee_bridge/sdkconfig.defaults b/examples/zigbee_bridge/sdkconfig.defaults index 7a08e56a6..05abd1277 100644 --- a/examples/zigbee_bridge/sdkconfig.defaults +++ b/examples/zigbee_bridge/sdkconfig.defaults @@ -6,16 +6,16 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -#enable BT +# Enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_TASK_STACK_SIZE=5120 CONFIG_BT_NIMBLE_ACL_BUF_SIZE=255 -#enable FreeRTOS legacy API +# Enable FreeRTOS legacy API CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y -#enable lwip ipv6 autoconfig +# Enable lwip ipv6 autoconfig CONFIG_LWIP_IPV6_AUTOCONFIG=y # Use a custom partition table @@ -25,7 +25,7 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" # Enable chip shell CONFIG_ENABLE_CHIP_SHELL=y -#enable lwIP route hooks +# Enable lwIP route hooks CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y