From 7c6d8e4761c879522cb577f41a6e52c07cce31e0 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Thu, 28 Aug 2025 15:30:15 +0800 Subject: [PATCH 001/156] feat(ble/bluedroid): Added BLE debug LOG for bluedroid --- components/bt/common/btc/core/btc_alarm.c | 2 +- .../bt/host/bluedroid/bta/dm/bta_dm_co.c | 26 +++++- .../host/bluedroid/bta/gatt/bta_gattc_utils.c | 3 +- .../bt/host/bluedroid/btc/core/btc_dev.c | 2 +- .../bt/host/bluedroid/btc/core/btc_dm.c | 1 + .../bt/host/bluedroid/btc/core/btc_main.c | 89 ++++++++++++------ .../bluedroid/btc/core/btc_profile_queue.c | 3 + .../btc/profile/std/gap/btc_gap_ble.c | 5 +- .../btc/profile/std/gap/btc_gap_bt.c | 4 +- .../btc/profile/std/gatt/btc_gatt_common.c | 3 +- .../btc/profile/std/gatt/btc_gattc.c | 8 +- .../btc/profile/std/gatt/btc_gatts.c | 7 +- .../btc/profile/std/hf_ag/btc_hf_ag.c | 2 + .../bluedroid/btc/profile/std/hid/btc_hd.c | 5 + .../bluedroid/btc/profile/std/hid/btc_hh.c | 3 + .../btc/profile/std/l2cap/btc_l2cap.c | 4 + components/bt/host/bluedroid/hci/hci_layer.c | 93 +++++++++++++++++++ .../bluedroid/hci/include/hci/hci_layer.h | 2 + .../bt/host/bluedroid/hci/packet_fragmenter.c | 5 +- .../bt/host/bluedroid/stack/btm/btm_ble.c | 9 ++ .../host/bluedroid/stack/btm/btm_ble_5_gap.c | 6 ++ .../bluedroid/stack/btm/btm_ble_privacy.c | 4 + .../bt/host/bluedroid/stack/btm/btm_dev.c | 11 ++- .../bt/host/bluedroid/stack/btm/btm_main.c | 9 ++ .../bt/host/bluedroid/stack/btu/btu_hcif.c | 12 ++- .../bt/host/bluedroid/stack/l2cap/l2c_utils.c | 9 ++ .../bt/host/bluedroid/stack/smp/smp_main.c | 6 +- 27 files changed, 281 insertions(+), 52 deletions(-) diff --git a/components/bt/common/btc/core/btc_alarm.c b/components/bt/common/btc/core/btc_alarm.c index 6c6177f7a3..67604332c1 100644 --- a/components/bt/common/btc/core/btc_alarm.c +++ b/components/bt/common/btc/core/btc_alarm.c @@ -12,7 +12,7 @@ void btc_alarm_handler(btc_msg_t *msg) { btc_alarm_args_t *arg = (btc_alarm_args_t *)msg->arg; - BTC_TRACE_DEBUG("%s act %d\n", __FUNCTION__, msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); if (arg->cb) { arg->cb(arg->cb_data); diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_co.c b/components/bt/host/bluedroid/bta/dm/bta_dm_co.c index 5c7ee9bded..085697acb9 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_co.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_co.c @@ -63,7 +63,15 @@ void bta_dm_co_security_param_init(void) bte_appl_cfg.ble_min_key_size = BTM_BLE_MIN_KEY_SIZE; bte_appl_cfg.ble_accept_auth_enable = BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_DISABLE; bte_appl_cfg.oob_support = BTM_BLE_OOB_DISABLE; -}; + + APPL_TRACE_DEBUG("%s: auth_req=%u, io_cap=%u, init_key=%u, resp_key=%u, " + "max_key_size=%u, min_key_size=%u, accept_auth=%u, oob=%u", + __func__, + bte_appl_cfg.ble_auth_req, bte_appl_cfg.ble_io_cap, + bte_appl_cfg.ble_init_key, bte_appl_cfg.ble_resp_key, + bte_appl_cfg.ble_max_key_size, bte_appl_cfg.ble_min_key_size, + bte_appl_cfg.ble_accept_auth_enable, bte_appl_cfg.oob_support); +} #endif #if (defined CLASSIC_BT_INCLUDED && CLASSIC_BT_INCLUDED == TRUE) @@ -379,6 +387,7 @@ void bta_dm_co_ble_set_io_cap(UINT8 ble_io_cap) #if (SMP_INCLUDED == TRUE) if(ble_io_cap < BTM_IO_CAP_MAX ) { bte_appl_cfg.ble_io_cap = ble_io_cap; + APPL_TRACE_DEBUG("%s: ble_io_cap set to %u", __func__, ble_io_cap); } else { APPL_TRACE_ERROR("%s error:Invalid io cap value.",__func__); } @@ -389,22 +398,25 @@ void bta_dm_co_ble_set_auth_req(UINT8 ble_auth_req) { #if (SMP_INCLUDED == TRUE) bte_appl_cfg.ble_auth_req = ble_auth_req; -#endif ///SMP_INCLUDED == TRUE + APPL_TRACE_DEBUG("%s: ble_auth_req set to %u", __func__, ble_auth_req); +#endif } void bta_dm_co_ble_set_init_key_req(UINT8 init_key) { #if (SMP_INCLUDED == TRUE) - init_key &= 0x0f; // 4~7bit reservd, only used the 0~3bit + init_key &= 0x0f; // 4~7bit reserved, only used the 0~3bit bte_appl_cfg.ble_init_key = init_key; -#endif ///SMP_INCLUDED == TRUE + APPL_TRACE_DEBUG("%s: init_key set to 0x%x", __func__, init_key); +#endif } void bta_dm_co_ble_set_rsp_key_req(UINT8 rsp_key) { #if (SMP_INCLUDED == TRUE) - rsp_key &= 0x0f; // 4~7bit reservd, only used the 0~3bit + rsp_key &= 0x0f; // 4~7bit reserved, only used the 0~3bit bte_appl_cfg.ble_resp_key = rsp_key; + APPL_TRACE_DEBUG("%s: rsp_key set to 0x%x", __func__, rsp_key); #endif ///SMP_INCLUDED == TRUE } @@ -413,6 +425,7 @@ void bta_dm_co_ble_set_max_key_size(UINT8 ble_key_size) #if (SMP_INCLUDED == TRUE) if(ble_key_size >= bte_appl_cfg.ble_min_key_size && ble_key_size <= BTM_BLE_MAX_KEY_SIZE) { bte_appl_cfg.ble_max_key_size = ble_key_size; + APPL_TRACE_DEBUG("%s: max_key_size set to %d", __func__, ble_key_size); } else { APPL_TRACE_ERROR("%s error:Invalid key size value, key_size =%d",__func__, ble_key_size); } @@ -424,6 +437,7 @@ void bta_dm_co_ble_set_min_key_size(UINT8 ble_key_size) #if (SMP_INCLUDED == TRUE) if(ble_key_size >= BTM_BLE_MIN_KEY_SIZE && ble_key_size <= bte_appl_cfg.ble_max_key_size) { bte_appl_cfg.ble_min_key_size = ble_key_size; + APPL_TRACE_DEBUG("%s: min_key_size set to %u", __func__, ble_key_size); } else { APPL_TRACE_ERROR("%s error:Invalid key size value, key_size =%d",__func__, ble_key_size); } @@ -437,6 +451,7 @@ void bta_dm_co_ble_set_accept_auth_enable(UINT8 enable) enable = BTM_BLE_ONLY_ACCEPT_SPECIFIED_SEC_AUTH_ENABLE; } bte_appl_cfg.ble_accept_auth_enable = enable; + APPL_TRACE_DEBUG("%s: accept_auth_enable set to %u", __func__, enable); #endif ///SMP_INCLUDED == TRUE } @@ -464,6 +479,7 @@ void bta_dm_co_ble_oob_support(UINT8 enable) } else { bte_appl_cfg.oob_support = BTM_BLE_OOB_DISABLE; } + APPL_TRACE_DEBUG("%s: oob_support set to %u", __func__, bte_appl_cfg.oob_support); #endif ///SMP_INCLUDED == TRUE } diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c index b47a9d9733..18632d2dfa 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_utils.c @@ -523,7 +523,8 @@ BOOLEAN bta_gattc_enqueue(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data) cmd_data->api_write.p_value = (UINT8 *)(cmd_data + 1); memcpy(cmd_data->api_write.p_value, p_data->api_write.p_value, len); } else { - APPL_TRACE_ERROR("%s(), line = %d, alloc fail, no memory.", __func__, __LINE__); + APPL_TRACE_ERROR("%s(), line = %d, alloc fail, size %d, no memory. free=%d, largest_block=%d", __func__, __LINE__, + sizeof(tBTA_GATTC_DATA) + len, heap_caps_get_free_size(MALLOC_CAP_DEFAULT), heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT)); return FALSE; } } else { diff --git a/components/bt/host/bluedroid/btc/core/btc_dev.c b/components/bt/host/bluedroid/btc/core/btc_dev.c index 18cda3e0d8..424dfe93e5 100644 --- a/components/bt/host/bluedroid/btc/core/btc_dev.c +++ b/components/bt/host/bluedroid/btc/core/btc_dev.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/bt/host/bluedroid/btc/core/btc_dm.c b/components/bt/host/bluedroid/btc/core/btc_dm.c index 782569c299..02b5a16ef4 100644 --- a/components/bt/host/bluedroid/btc/core/btc_dm.c +++ b/components/bt/host/bluedroid/btc/core/btc_dm.c @@ -784,6 +784,7 @@ void btc_dm_sec_cb_handler(btc_msg_t *msg) ble_msg->pid = BTC_PID_GAP_BLE; // tBTA_SERVICE_MASK service_mask; BTC_TRACE_DEBUG("btc_dm_upstreams_cback ev: %d\n", msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); switch (msg->act) { case BTA_DM_ENABLE_EVT: { diff --git a/components/bt/host/bluedroid/btc/core/btc_main.c b/components/bt/host/bluedroid/btc/core/btc_main.c index d7330cc6f7..593bb99e07 100644 --- a/components/bt/host/bluedroid/btc/core/btc_main.c +++ b/components/bt/host/bluedroid/btc/core/btc_main.c @@ -97,7 +97,7 @@ static void btc_deinit_bluetooth(void) void btc_main_call_handler(btc_msg_t *msg) { - BTC_TRACE_DEBUG("%s act %d\n", __func__, msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); switch (msg->act) { case BTC_MAIN_ACT_INIT: @@ -127,101 +127,132 @@ uint32_t btc_get_ble_status(void) return status; } - #if (BLE_INCLUDED == TRUE) +#if (BLE_INCLUDED == TRUE) // Number of active advertising extern uint8_t btm_ble_adv_active_count(void); - if (btm_ble_adv_active_count()) { + uint8_t adv_cnt = btm_ble_adv_active_count(); + if (adv_cnt) { + BTC_TRACE_WARNING("%s advertising active, cnt %d", __func__, adv_cnt); status |= BIT(BTC_BLE_STATUS_ADV); } // Number of active scanning extern uint8_t btm_ble_scan_active_count(void); - if (btm_ble_scan_active_count()) { + uint8_t scan_cnt = btm_ble_scan_active_count(); + if (scan_cnt) { + BTC_TRACE_WARNING("%s scan active, cnt %d", __func__, scan_cnt); status |= BIT(BTC_BLE_STATUS_SCAN); } // Number of active GATT tcb extern uint8_t gatt_tcb_active_count(void); - if (gatt_tcb_active_count()) { + uint8_t gatt_tcb_cnt = gatt_tcb_active_count(); + if (gatt_tcb_cnt) { + BTC_TRACE_WARNING("%s gatt tcb active, cnt %d", __func__, gatt_tcb_cnt); status |= BIT(BTC_BLE_STATUS_CONN); } // Number of active ACL connection extern uint8_t btm_ble_acl_active_count(void); - if (btm_ble_acl_active_count()) { + uint8_t acl_cnt = btm_ble_acl_active_count(); + if (acl_cnt) { + BTC_TRACE_WARNING("%s acl connection active, cnt %d", __func__, acl_cnt); status |= BIT(BTC_BLE_STATUS_CONN); } // Number of active L2C plcb extern uint8_t l2cu_ble_plcb_active_count(void); - if (l2cu_ble_plcb_active_count()) { + uint8_t plcb_cnt = l2cu_ble_plcb_active_count(); + if (plcb_cnt) { + BTC_TRACE_WARNING("%s l2c plcb active, cnt %d", __func__, plcb_cnt); status |= BIT(BTC_BLE_STATUS_CONN); } // Address resolve status extern uint8_t btm_get_ble_addr_resolve_disable_status(void); - if (btm_get_ble_addr_resolve_disable_status()) { + uint8_t addr_resolve_disable = btm_get_ble_addr_resolve_disable_status(); + if (addr_resolve_disable) { + BTC_TRACE_WARNING("%s address resolve disabled", __func__); status |= BIT(BTC_BLE_STATUS_ADDR_RESOLVE_DISABLE); } - #if (SMP_INCLUDED == TRUE) +#if (SMP_INCLUDED == TRUE) // Number of recorded devices extern uint8_t btm_ble_sec_dev_record_count(void); - if (btm_ble_sec_dev_record_count()) { + uint8_t sec_dev_cnt = btm_ble_sec_dev_record_count(); + if (sec_dev_cnt) { + BTC_TRACE_WARNING("%s security device record count %d", __func__, sec_dev_cnt); status |= BIT(BTC_BLE_STATUS_DEVICE_REC); } // Number of saved bonded devices - if (btc_storage_get_num_ble_bond_devices()) { + int bond_cnt = btc_storage_get_num_ble_bond_devices(); + if (bond_cnt) { + BTC_TRACE_WARNING("%s bonded devices count %d", __func__, bond_cnt); status |= BIT(BTC_BLE_STATUS_BOND); } - #endif +#endif // SMP_INCLUDED - #if (BLE_PRIVACY_SPT == TRUE) +#if (BLE_PRIVACY_SPT == TRUE) // Privacy enabled extern uint8_t btm_ble_privacy_is_enabled(void); - if (btm_ble_privacy_is_enabled()) { + uint8_t privacy_en = btm_ble_privacy_is_enabled(); + if (privacy_en) { + BTC_TRACE_WARNING("%s privacy enabled", __func__); status |= BIT(BTC_BLE_STATUS_PRIVACY); } - #endif - #endif +#endif // BLE_PRIVACY_SPT - #if (BLE_50_EXTEND_ADV_EN == TRUE) +#endif // BLE_INCLUDED + +#if (BLE_50_EXTEND_ADV_EN == TRUE) // Number of active extended advertsing extern uint8_t btm_ble_ext_adv_active_count(void); - if (btm_ble_ext_adv_active_count()) { + uint8_t ext_adv_cnt = btm_ble_ext_adv_active_count(); + if (ext_adv_cnt) { + BTC_TRACE_WARNING("%s extended advertising active, cnt %d", __func__, ext_adv_cnt); status |= BIT(BTC_BLE_STATUS_EXT_ADV); } - #endif +#endif // (BLE_50_EXTEND_ADV_EN == TRUE) - #if (GATTC_INCLUDED == TRUE) +#if (GATTC_INCLUDED == TRUE) // Number of registered GATTC APP extern uint8_t bta_gattc_cl_rcb_active_count(void); - if (bta_gattc_cl_rcb_active_count()) { + uint8_t gattc_app_cnt = bta_gattc_cl_rcb_active_count(); + if (gattc_app_cnt) { + BTC_TRACE_WARNING("%s GATTC app active, cnt %d", __func__, gattc_app_cnt); status |= BIT(BTC_BLE_STATUS_GATTC_APP); } // Number of saved GATTC cache extern UINT8 bta_gattc_co_get_addr_num(void); - if (bta_gattc_co_get_addr_num()) { + uint8_t gattc_cache_cnt = bta_gattc_co_get_addr_num(); + if (gattc_cache_cnt) { + BTC_TRACE_WARNING("%s GATTC cache count %d", __func__, gattc_cache_cnt); status |= BIT(BTC_BLE_STATUS_GATTC_CACHE); } - #endif +#endif // GATTC_INCLUDED - #if (GATTS_INCLUDED == TRUE) +#if (GATTS_INCLUDED == TRUE) // Number of registered GATTS service extern uint8_t bta_gatts_srvc_active_count(void); - if (bta_gatts_srvc_active_count()) { + uint8_t gatts_srvc_cnt = bta_gatts_srvc_active_count(); + if (gatts_srvc_cnt) { + BTC_TRACE_WARNING("%s GATTS service active, cnt %d", __func__, gatts_srvc_cnt); status |= BIT(BTC_BLE_STATUS_GATTS_SRVC); } - #endif +#endif // GATTS_INCLUDED - #if SMP_INCLUDED == TRUE +#if (SMP_INCLUDED == TRUE) extern uint8_t smp_get_state(void); - if (smp_get_state()) { + uint8_t smp_state = smp_get_state(); + if (smp_state) { + BTC_TRACE_WARNING("%s SMP state active, state=%d", __func__, smp_state); status |= BIT(BTC_BLE_STATUS_SMP_STATE); } - #endif +#endif // SMP_INCLUDED + + BTC_TRACE_WARNING("%s exit, final status=0x%x", __func__, status); return status; } diff --git a/components/bt/host/bluedroid/btc/core/btc_profile_queue.c b/components/bt/host/bluedroid/btc/core/btc_profile_queue.c index 4f35903043..5e63dfe54c 100644 --- a/components/bt/host/bluedroid/btc/core/btc_profile_queue.c +++ b/components/bt/host/bluedroid/btc/core/btc_profile_queue.c @@ -62,6 +62,9 @@ static void queue_int_advance(void) void btc_profile_queue_handler(btc_msg_t *msg) { btc_prf_que_args_t *arg = (btc_prf_que_args_t *)(msg->arg); + + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_PRF_QUE_CONNECT: queue_int_add(&(arg->connect_node)); diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c index 0c690065a2..67b54deea8 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_ble.c @@ -61,6 +61,7 @@ static inline void btc_gap_ble_cb_to_app(esp_gap_ble_cb_event_t event, esp_ble_g esp_gap_ble_cb_t btc_gap_ble_cb = (esp_gap_ble_cb_t)btc_profile_cb_get(BTC_PID_GAP_BLE); if (btc_gap_ble_cb) { btc_gap_ble_cb(event, param); + BTC_TRACE_DEBUG("btc_gap_ble_cb_to_app, event=%d", event); } } @@ -1768,6 +1769,8 @@ void btc_gap_ble_cb_handler(btc_msg_t *msg) { esp_ble_gap_cb_param_t *param = (esp_ble_gap_cb_param_t *)msg->arg; + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + if (msg->act < ESP_GAP_BLE_EVT_MAX) { btc_gap_ble_cb_to_app(msg->act, param); } else { @@ -2177,7 +2180,7 @@ void btc_gap_ble_call_handler(btc_msg_t *msg) btc_ble_5_gap_args_t *arg_5 = (btc_ble_5_gap_args_t *)msg->arg; #endif // #if (BLE_50_FEATURE_SUPPORT == TRUE) - BTC_TRACE_DEBUG("%s act %d\n", __FUNCTION__, msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); switch (msg->act) { #if (BLE_42_FEATURE_SUPPORT == TRUE) diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c index e1278954c4..4d5e7a497a 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c @@ -1063,7 +1063,9 @@ void btc_gap_bt_arg_deep_free(btc_msg_t *msg) void btc_gap_bt_call_handler(btc_msg_t *msg) { btc_gap_bt_args_t *arg = (btc_gap_bt_args_t *)msg->arg; - BTC_TRACE_DEBUG("%s act %d\n", __func__, msg->act); + + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_GAP_BT_ACT_SET_SCAN_MODE: { btc_bt_set_scan_mode(arg->set_scan_mode.c_mode, arg->set_scan_mode.d_mode); diff --git a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c index 45a2b834b5..754878f0cb 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c +++ b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatt_common.c @@ -23,7 +23,8 @@ static void btc_set_local_mtu(uint16_t mtu) void btc_gatt_com_call_handler(btc_msg_t *msg) { - BTC_TRACE_DEBUG("%s act %d\n", __func__, msg->act); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_GATT_ACT_SET_LOCAL_MTU: { diff --git a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c index 86221e3c89..e8f7444368 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c +++ b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gattc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 @@ -24,6 +24,7 @@ static inline void btc_gattc_cb_to_app(esp_gattc_cb_event_t event, esp_gatt_if_t esp_gattc_cb_t btc_gattc_cb = (esp_gattc_cb_t )btc_profile_cb_get(BTC_PID_GATTC); if (btc_gattc_cb) { btc_gattc_cb(event, gattc_if, param); + BTC_TRACE_DEBUG("btc_gattc_cb_to_app, gattc_if %d, event=%d", gattc_if, event); } } @@ -714,6 +715,9 @@ static void btc_gattc_unreg_for_notify(btc_ble_gattc_args_t *arg) void btc_gattc_call_handler(btc_msg_t *msg) { btc_ble_gattc_args_t *arg = (btc_ble_gattc_args_t *)(msg->arg); + + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_GATTC_ACT_APP_REGISTER: btc_gattc_app_register(arg); @@ -803,6 +807,8 @@ void btc_gattc_cb_handler(btc_msg_t *msg) memset(¶m, 0, sizeof(esp_ble_gattc_cb_param_t)); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTA_GATTC_REG_EVT: { tBTA_GATTC_REG *reg_oper = &arg->reg_oper; diff --git a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c index 7eab806e2f..e1b06cffba 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c +++ b/components/bt/host/bluedroid/btc/profile/std/gatt/btc_gatts.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -37,6 +37,7 @@ static inline void btc_gatts_cb_to_app(esp_gatts_cb_event_t event, esp_gatt_if_t { esp_gatts_cb_t btc_gatts_cb = (esp_gatts_cb_t)btc_profile_cb_get(BTC_PID_GATTS); if (btc_gatts_cb) { + BTC_TRACE_DEBUG("btc_gatts_cb_to_app, gatts_if %d, event=%d", gatts_if, event); btc_gatts_cb(event, gatts_if, param); } } @@ -616,6 +617,8 @@ void btc_gatts_call_handler(btc_msg_t *msg) { btc_ble_gatts_args_t *arg = (btc_ble_gatts_args_t *)msg->arg; + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_GATTS_ACT_APP_REGISTER: { tBT_UUID uuid; @@ -764,6 +767,8 @@ void btc_gatts_cb_handler(btc_msg_t *msg) tBTA_GATTS *p_data = (tBTA_GATTS *)msg->arg; esp_gatt_if_t gatts_if; + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTA_GATTS_REG_EVT: { gatts_if = p_data->reg_oper.server_if; diff --git a/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c b/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c index 0e4947ee41..b5a731f6a7 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c +++ b/components/bt/host/bluedroid/btc/profile/std/hf_ag/btc_hf_ag.c @@ -1134,6 +1134,8 @@ void btc_hf_call_handler(btc_msg_t *msg) { btc_hf_args_t *arg = (btc_hf_args_t *)(msg->arg); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_HF_INIT_EVT: { diff --git a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c index 29019fc881..5986943bfa 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c +++ b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hd.c @@ -723,6 +723,9 @@ void btc_hd_call_arg_deep_free(btc_msg_t *msg) void btc_hd_call_handler(btc_msg_t *msg) { btc_hidd_args_t *arg = (btc_hidd_args_t *)(msg->arg); + + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_HD_INIT_EVT: btc_hd_init(); @@ -781,6 +784,8 @@ void btc_hd_cb_handler(btc_msg_t *msg) esp_hidd_cb_param_t param = {0}; BTC_TRACE_API("%s: event=%s", __func__, dump_hd_event(event)); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (event) { case BTA_HD_ENABLE_EVT: BTC_TRACE_DEBUG("%s: status=%d", __func__, p_data->status); diff --git a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c index c7adef2006..dda5d0bf9d 100644 --- a/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c +++ b/components/bt/host/bluedroid/btc/profile/std/hid/btc_hh.c @@ -1121,6 +1121,8 @@ void btc_hh_call_arg_deep_free(btc_msg_t *msg) void btc_hh_call_handler(btc_msg_t *msg) { btc_hidh_args_t *arg = (btc_hidh_args_t *)(msg->arg); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (msg->act) { case BTC_HH_INIT_EVT: btc_hh_init(); @@ -1229,6 +1231,7 @@ void btc_hh_cb_handler(btc_msg_t *msg) btc_hh_device_t *p_dev = NULL; int len, i; BTC_TRACE_DEBUG("%s: event=%s dereg = %d", __func__, dump_hh_event(msg->act), btc_hh_cb.service_dereg_active); + switch (msg->act) { case BTA_HH_ENABLE_EVT: if (p_data->status == BTA_HH_OK) { diff --git a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c index 9155784fb8..63477d6ce5 100644 --- a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c +++ b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c @@ -300,6 +300,7 @@ static inline void btc_l2cap_cb_to_app(esp_bt_l2cap_cb_event_t event, esp_bt_l2c { esp_bt_l2cap_cb_t btc_l2cap_cb = (esp_bt_l2cap_cb_t)btc_profile_cb_get(BTC_PID_L2CAP); if (btc_l2cap_cb) { + BTC_TRACE_DEBUG("btc_l2cap_cb_to_app, event=%d", event); btc_l2cap_cb(event, param); } } @@ -772,6 +773,7 @@ static void btc_l2cap_disconnect(uint32_t handle) void btc_l2cap_call_handler(btc_msg_t *msg) { btc_l2cap_args_t *arg = (btc_l2cap_args_t *)(msg->arg); + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); switch (msg->act) { case BTC_L2CAP_ACT_INIT: btc_l2cap_init(); @@ -809,6 +811,8 @@ void btc_l2cap_cb_handler(btc_msg_t *msg) uint8_t serial = 0; uint32_t count = 0; + BTC_TRACE_DEBUG("%s act %d", __func__, msg->act); + switch (event) { case BTA_JV_ENABLE_EVT: param.init.status = p_data->status; diff --git a/components/bt/host/bluedroid/hci/hci_layer.c b/components/bt/host/bluedroid/hci/hci_layer.c index e5cd263fbc..59b69bc0a7 100644 --- a/components/bt/host/bluedroid/hci/hci_layer.c +++ b/components/bt/host/bluedroid/hci/hci_layer.c @@ -614,3 +614,96 @@ const hci_t *hci_layer_get_interface(void) init_layer_interface(); return &interface; } + +#if !UC_BT_STACK_NO_LOG +/******************************************************************************* +** +** Function hci_status_code_to_string +** +** Description Converts an HCI status code to a human-readable string. +** If the code is not defined in the specification, the +** function returns "Unknown Status (0xXX)" where XX is the +** actual code value. +** Reference: BLUETOOTH CORE SPECIFICATION Version 5.4, +** Vol 1, Part F, p. 376 +** +** Parameters status : HCI status code +** +** Returns const char* : readable description of the status +** +*******************************************************************************/ +const char *hci_status_code_to_string(uint8_t status) +{ + switch (status) { + case HCI_SUCCESS: return "Success"; /* 0x00 */ + case HCI_ERR_ILLEGAL_COMMAND: return "Illegal Command"; /* 0x01 */ + case HCI_ERR_NO_CONNECTION: return "No Connection"; /* 0x02 */ + case HCI_ERR_HW_FAILURE: return "HW Failure"; /* 0x03 */ + case HCI_ERR_PAGE_TIMEOUT: return "Page Timeout"; /* 0x04 */ + case HCI_ERR_AUTH_FAILURE: return "Auth Failure"; /* 0x05 */ + case HCI_ERR_KEY_MISSING: return "Key Missing"; /* 0x06 */ + case HCI_ERR_MEMORY_FULL: return "Memory Full"; /* 0x07 */ + case HCI_ERR_CONNECTION_TOUT: return "Conn Timeout"; /* 0x08 */ + case HCI_ERR_MAX_NUM_OF_CONNECTIONS: return "Conn Limit Exceeded"; /* 0x09 */ + case HCI_ERR_MAX_NUM_OF_SCOS: return "Sync Conn Limit Exceeded"; /* 0x0A */ + case HCI_ERR_CONNECTION_EXISTS: return "Conn Exists"; /* 0x0B */ + case HCI_ERR_COMMAND_DISALLOWED: return "Cmd Disallowed"; /* 0x0C */ + case HCI_ERR_HOST_REJECT_RESOURCES: return "Rejected: Resources"; /* 0x0D */ + case HCI_ERR_HOST_REJECT_SECURITY: return "Rejected: Security"; /* 0x0E */ + case HCI_ERR_HOST_REJECT_DEVICE: return "Rejected: BD_ADDR"; /* 0x0F */ + case HCI_ERR_HOST_TIMEOUT: return "Accept Timeout"; /* 0x10 */ + case HCI_ERR_UNSUPPORTED_VALUE: return "Unsupported Value"; /* 0x11 */ + case HCI_ERR_ILLEGAL_PARAMETER_FMT: return "Invalid Param"; /* 0x12 */ + case HCI_ERR_PEER_USER: return "Terminated by Peer"; /* 0x13 */ + case HCI_ERR_PEER_LOW_RESOURCES: return "Peer Low Resources"; /* 0x14 */ + case HCI_ERR_PEER_POWER_OFF: return "Peer Power Off"; /* 0x15 */ + case HCI_ERR_CONN_CAUSE_LOCAL_HOST: return "Terminated by Host"; /* 0x16 */ + case HCI_ERR_REPEATED_ATTEMPTS: return "Repeated Attempts"; /* 0x17 */ + case HCI_ERR_PAIRING_NOT_ALLOWED: return "Pairing Not Allowed"; /* 0x18 */ + case HCI_ERR_UNKNOWN_LMP_PDU: return "Unknown LMP PDU"; /* 0x19 */ + case HCI_ERR_UNSUPPORTED_REM_FEATURE: return "Unsupported Remote Feature"; /* 0x1A */ + case HCI_ERR_SCO_OFFSET_REJECTED: return "SCO Offset Rejected"; /* 0x1B */ + case HCI_ERR_SCO_INTERVAL_REJECTED: return "SCO Interval Rejected"; /* 0x1C */ + case HCI_ERR_SCO_AIR_MODE: return "SCO Air Mode Rejected"; /* 0x1D */ + case HCI_ERR_INVALID_LMP_PARAM: return "Invalid LMP/LL Param"; /* 0x1E */ + case HCI_ERR_UNSPECIFIED: return "Unspecified Error"; /* 0x1F */ + case HCI_ERR_UNSUPPORTED_LMP_PARAMETERS: return "Unsupported LMP/LL"; /* 0x20 */ + case HCI_ERR_ROLE_CHANGE_NOT_ALLOWED: return "Role Change Not Allowed"; /* 0x21 */ + case HCI_ERR_LMP_RESPONSE_TIMEOUT: return "LMP/LL Response Timeout"; /* 0x22 */ + case HCI_ERR_LMP_ERR_TRANS_COLLISION: return "Transaction Collision"; /* 0x23 */ + case HCI_ERR_LMP_PDU_NOT_ALLOWED: return "LMP PDU Not Allowed"; /* 0x24 */ + case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE: return "Encryption Not Acceptable"; /* 0x25 */ + case HCI_ERR_UNIT_KEY_USED: return "Link Key Used"; /* 0x26 */ + case HCI_ERR_QOS_NOT_SUPPORTED: return "QoS Not Supported"; /* 0x27 */ + case HCI_ERR_INSTANT_PASSED: return "Instant Passed"; /* 0x28 */ + case HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED: return "Pairing w/ Unit Key Not Supported"; /* 0x29 */ + case HCI_ERR_DIFF_TRANSACTION_COLLISION: return "Transaction Collision"; /* 0x2A */ + case HCI_ERR_UNDEFINED_0x2B: return "Reserved"; /* 0x2B */ + case HCI_ERR_QOS_UNACCEPTABLE_PARAM: return "QoS Unacceptable"; /* 0x2C */ + case HCI_ERR_QOS_REJECTED: return "QoS Rejected"; /* 0x2D */ + case HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED: return "Chan Classif Not Supported"; /* 0x2E */ + case HCI_ERR_INSUFFCIENT_SECURITY: return "Insufficient Security"; /* 0x2F */ + case HCI_ERR_PARAM_OUT_OF_RANGE: return "Param Out of Range"; /* 0x30 */ + case HCI_ERR_UNDEFINED_0x31: return "Reserved"; /* 0x31 */ + case HCI_ERR_ROLE_SWITCH_PENDING: return "Role Switch Pending"; /* 0x32 */ + case HCI_ERR_UNDEFINED_0x33: return "Reserved"; /* 0x33 */ + case HCI_ERR_RESERVED_SLOT_VIOLATION: return "Slot Violation"; /* 0x34 */ + case HCI_ERR_ROLE_SWITCH_FAILED: return "Role Switch Failed"; /* 0x35 */ + case HCI_ERR_INQ_RSP_DATA_TOO_LARGE: return "Inquiry Response Too Large"; /* 0x36 */ + case HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED: return "Simple Pairing Not Supported"; /* 0x37 */ + case HCI_ERR_HOST_BUSY_PAIRING: return "Host Busy"; /* 0x38 */ + case HCI_ERR_REJ_NO_SUITABLE_CHANNEL: return "No Suitable Channel"; /* 0x39 */ + case HCI_ERR_CONTROLLER_BUSY: return "Controller Busy"; /* 0x3A */ + case HCI_ERR_UNACCEPT_CONN_INTERVAL: return "Unacceptable Conn Interval"; /* 0x3B */ + case HCI_ERR_DIRECTED_ADVERTISING_TIMEOUT: return "Adv Timeout"; /* 0x3C */ + case HCI_ERR_CONN_TOUT_DUE_TO_MIC_FAILURE: return "MIC Failure"; /* 0x3D */ + case HCI_ERR_CONN_FAILED_ESTABLISHMENT: return "Conn Failed"; /* 0x3E */ + case HCI_ERR_MAC_CONNECTION_FAILED: return "Previously Used"; /* 0x3F */ + default: { + static char buf[24]; + snprintf(buf, sizeof(buf), "Unknown Status (0x%02X)", status); + return buf; + } + } +} +#endif diff --git a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h index c48d05655e..356f2c044b 100644 --- a/components/bt/host/bluedroid/hci/include/hci/hci_layer.h +++ b/components/bt/host/bluedroid/hci/include/hci/hci_layer.h @@ -112,3 +112,5 @@ int hci_adv_credits_force_release(uint16_t num); #endif #endif // #if (BLE_42_SCAN_EN == TRUE) #endif /* _HCI_LAYER_H_ */ + +const char *hci_status_code_to_string(uint8_t status); diff --git a/components/bt/host/bluedroid/hci/packet_fragmenter.c b/components/bt/host/bluedroid/hci/packet_fragmenter.c index d8f2ff918f..dff48be0a3 100644 --- a/components/bt/host/bluedroid/hci/packet_fragmenter.c +++ b/components/bt/host/bluedroid/hci/packet_fragmenter.c @@ -26,7 +26,7 @@ #include "osi/hash_map.h" #include "osi/hash_functions.h" #include "common/bt_trace.h" - +#include "esp_log.h" #define APPLY_CONTINUATION_FLAG(handle) (((handle) & 0xCFFF) | 0x1000) #define APPLY_START_FLAG(handle) (((handle) & 0xCFFF) | 0x2000) @@ -173,7 +173,8 @@ static void reassemble_and_dispatch(BT_HDR *packet) partial_packet = (BT_HDR *)osi_calloc(full_length + sizeof(BT_HDR)); if (partial_packet == NULL) { - HCI_TRACE_WARNING("%s full_length %d no memory.\n", __func__, full_length); + HCI_TRACE_WARNING("%s full_length %d no memory, free=%d, largest_block=%d", __func__, full_length, + heap_caps_get_free_size(MALLOC_CAP_DEFAULT), heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT)); assert(0); } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble.c b/components/bt/host/bluedroid/stack/btm/btm_ble.c index 8f676a655a..da8137e432 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble.c @@ -2956,6 +2956,15 @@ uint8_t btm_ble_sec_dev_record_count(void) for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) { p_dev_rec = list_node(p_node); if (p_dev_rec && (p_dev_rec->sec_flags & BTM_SEC_IN_USE) && (p_dev_rec->ble.key_type != BTM_LE_KEY_NONE)) { + BTM_TRACE_DEBUG("%s BLE security device #%d: bd_addr=%02X:%02X:%02X:%02X:%02X:%02X", + __func__, + count, + p_dev_rec->bd_addr[0], + p_dev_rec->bd_addr[1], + p_dev_rec->bd_addr[2], + p_dev_rec->bd_addr[3], + p_dev_rec->bd_addr[4], + p_dev_rec->bd_addr[5]); count++; } } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c index 76fe63c08a..764ca477bf 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_5_gap.c @@ -1390,6 +1390,12 @@ uint8_t btm_ble_ext_adv_active_count(void) for (uint8_t i = 0; i < MAX_BLE_ADV_INSTANCE; i++) { if (adv_record[i].enabled == true) { + BTM_TRACE_DEBUG("%s EXT ADV active #%d: instance=%d, duration=%d, max_events=%d", + __func__, + count, + adv_record[i].instance, + adv_record[i].duration, + adv_record[i].max_events); count++; } } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c index 39784bb11a..16617f3bd0 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c @@ -984,6 +984,10 @@ BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec) *******************************************************************************/ void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec) { + BTM_TRACE_EVENT ("%s - bd_addr=%02x:%02x:%02x:%02x:%02x:%02x", __func__, + p_dev_rec->bd_addr[0], p_dev_rec->bd_addr[1], p_dev_rec->bd_addr[2], + p_dev_rec->bd_addr[3], p_dev_rec->bd_addr[4], p_dev_rec->bd_addr[5]); + UINT8 rl_mask = btm_cb.ble_ctr_cb.rl_state; BTM_TRACE_EVENT ("%s\n", __func__); diff --git a/components/bt/host/bluedroid/stack/btm/btm_dev.c b/components/bt/host/bluedroid/stack/btm/btm_dev.c index 7e1095f4a5..1784d4a353 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_dev.c +++ b/components/bt/host/bluedroid/stack/btm/btm_dev.c @@ -335,7 +335,8 @@ tBTM_SEC_DEV_REC *btm_sec_alloc_dev (BD_ADDR bd_addr) BOOLEAN new_entry_found = FALSE; BOOLEAN old_entry_found = FALSE; BOOLEAN malloc_new_entry = FALSE; - BTM_TRACE_EVENT ("btm_sec_alloc_dev\n"); + BTM_TRACE_EVENT ("btm_sec_alloc_dev - start alloc for device %02x:%02x:%02x:%02x:%02x:%02x", + bd_addr[0], bd_addr[1], bd_addr[2], bd_addr[3], bd_addr[4], bd_addr[5]); for (p_node = list_begin(btm_cb.p_sec_dev_rec_list); p_node; p_node = list_next(p_node)) { p_dev_old_rec = list_node(p_node); /* look for old entry which match the bd_addr and the BTM_SEC_IN_USE is cleared */ @@ -691,6 +692,14 @@ tBTM_SEC_DEV_REC *btm_find_oldest_dev (void) old_ts = p_dev_rec->timestamp; } } + + if (p_oldest) { + BTM_TRACE_EVENT("oldest paired device found: bd_addr=%02x:%02x:%02x:%02x:%02x:%02x, timestamp=%u", + p_oldest->bd_addr[0], p_oldest->bd_addr[1], p_oldest->bd_addr[2], + p_oldest->bd_addr[3], p_oldest->bd_addr[4], p_oldest->bd_addr[5], + p_oldest->timestamp); + } + return (p_oldest); } /******************************************************************************* diff --git a/components/bt/host/bluedroid/stack/btm/btm_main.c b/components/bt/host/bluedroid/stack/btm/btm_main.c index 67882af0ef..b109e5395b 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_main.c +++ b/components/bt/host/bluedroid/stack/btm/btm_main.c @@ -136,6 +136,15 @@ uint8_t btm_ble_acl_active_count(void) for (p_node = list_begin(btm_cb.p_acl_db_list); p_node; p_node = list_next(p_node)) { p_acl_conn = list_node(p_node); if (p_acl_conn && p_acl_conn->in_use && p_acl_conn->transport == BT_TRANSPORT_LE) { + BTM_TRACE_DEBUG("%s LE ACL active #%d: remote_addr=%02X:%02X:%02X:%02X:%02X:%02X", + __func__, + count, + p_acl_conn->remote_addr[0], + p_acl_conn->remote_addr[1], + p_acl_conn->remote_addr[2], + p_acl_conn->remote_addr[3], + p_acl_conn->remote_addr[4], + p_acl_conn->remote_addr[5]); count++; } } diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index eb2995b958..c9891b66b4 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1128,7 +1128,9 @@ static void btu_hcif_esco_connection_chg_evt (UINT8 *p) static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_len, void *p_cplt_cback) { +#if (BLE_INCLUDED == TRUE) uint8_t status; +#endif // (BLE_INCLUDED == TRUE) switch (opcode) { #if (CLASSIC_BT_INCLUDED == TRUE) case HCI_INQUIRY_CANCEL: @@ -1395,10 +1397,6 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC) { btm_vsc_complete (p, opcode, evt_len, (tBTM_CMPL_CB *)p_cplt_cback); } - STREAM_TO_UINT8 (status, p); - if(status != HCI_SUCCESS) { - HCI_TRACE_ERROR("CC evt: op=0x%x, status=0x%x", opcode, status); - } break; } } @@ -1421,6 +1419,10 @@ static void btu_hcif_command_complete_evt_on_task(BT_HDR *event) uint8_t *stream = hack->response->data + hack->response->offset + 3; // 2 to skip the event headers, 1 to skip the command credits STREAM_TO_UINT16(opcode, stream); + if (*stream != HCI_SUCCESS) { + HCI_TRACE_WARNING("opcode=0x%04x, status= %02x: %s", opcode, *stream, hci_status_code_to_string(*stream)); + } + btu_hcif_hdl_command_complete( opcode, stream, @@ -1506,7 +1508,7 @@ static void btu_hcif_hdl_command_status (UINT16 opcode, UINT8 status, UINT8 *p_c void *p_vsc_status_cback) { if (status != HCI_SUCCESS){ - HCI_TRACE_WARNING("%s,opcode:0x%04x,status:0x%02x", __func__, opcode,status); + HCI_TRACE_WARNING("opcode=0x%04x, status= %02x: %s", opcode, status, hci_status_code_to_string(status)); } BD_ADDR bd_addr; UINT16 handle; diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c index a48eb0d150..97cae231f7 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c @@ -345,6 +345,15 @@ uint8_t l2cu_ble_plcb_active_count(void) for (p_node = list_begin(l2cb.p_lcb_pool); p_node; p_node = list_next(p_node)) { p_lcb = list_node(p_node); if (p_lcb && p_lcb->in_use && p_lcb->transport == BT_TRANSPORT_LE) { + L2CAP_TRACE_DEBUG("%s LE PLCB active #%d: remote_addr=%02X:%02X:%02X:%02X:%02X:%02X", + __func__, + active_count, + p_lcb->remote_bd_addr[0], + p_lcb->remote_bd_addr[1], + p_lcb->remote_bd_addr[2], + p_lcb->remote_bd_addr[3], + p_lcb->remote_bd_addr[4], + p_lcb->remote_bd_addr[5]); active_count ++; } } diff --git a/components/bt/host/bluedroid/stack/smp/smp_main.c b/components/bt/host/bluedroid/stack/smp/smp_main.c index 512aca0a8c..fa4d5ffbe3 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_main.c +++ b/components/bt/host/bluedroid/stack/smp/smp_main.c @@ -388,7 +388,7 @@ static const UINT8 smp_master_wait_dhk_check_table[][SMP_SM_NUM_COLS] = { static const UINT8 smp_master_dhk_check_table[][SMP_SM_NUM_COLS] = { /* Event Action Next State */ - /* locally calculated peer dhkey check is ready -> compare it withs DHKey Check actually received from peer */ + /* locally calculated peer dhkey check is ready -> compare it with DHKey Check actually received from peer */ /* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, /* locally calculated peer dhkey check is ready -> calculate STK, go to sending */ /* HCI LE Start Encryption command */ @@ -580,7 +580,7 @@ static const UINT8 smp_slave_wait_dhk_check_table[][SMP_SM_NUM_COLS] = { static const UINT8 smp_slave_dhk_check_table[][SMP_SM_NUM_COLS] = { /* Event Action Next State */ - /* locally calculated peer dhkey check is ready -> compare it withs DHKey Check */ + /* locally calculated peer dhkey check is ready -> compare it with DHKey Check */ /* actually received from peer */ /* SC_KEY_READY */{SMP_MATCH_DHKEY_CHECKS, SMP_SM_NO_ACTION, SMP_STATE_DHK_CHECK}, @@ -771,6 +771,8 @@ void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data) /* execute action functions */ for (i = 0; i < SMP_NUM_ACTIONS; i++) { if ((action = state_table[entry - 1][i]) != SMP_SM_NO_ACTION && smp_sm_action[action] != NULL) { + SMP_TRACE_DEBUG("smp action %d for state %s, event %s", + action, smp_get_state_name(curr_state), smp_get_event_name(event)); (*smp_sm_action[action])(p_cb, (tSMP_INT_DATA *)p_data); } else { break; From d6d882b82f9a43338bc0f3cae06e43f3ea5bd1de Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 7 Nov 2025 15:50:54 +0800 Subject: [PATCH 002/156] change(ble): [AUTO_MR] Update lib_esp32c2 to 27b6e1dc --- components/bt/controller/lib_esp32c2/esp32c2-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib index c82c623de4..7c104a8d09 160000 --- a/components/bt/controller/lib_esp32c2/esp32c2-bt-lib +++ b/components/bt/controller/lib_esp32c2/esp32c2-bt-lib @@ -1 +1 @@ -Subproject commit c82c623de457e1b06cf0dad5c963d023dbb6fe76 +Subproject commit 7c104a8d09e35f3244636fcf01004d5c767f12c2 From e83efa9767f8657a982be7949b112e02353e497f Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Wed, 5 Nov 2025 11:24:44 +0800 Subject: [PATCH 003/156] change(ble): [AUTO_MR] updated rom linker script for ESP32-C2 --- components/esp_rom/esp32c2/ld/esp32c2.rom.ble-eco4.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_rom/esp32c2/ld/esp32c2.rom.ble-eco4.ld b/components/esp_rom/esp32c2/ld/esp32c2.rom.ble-eco4.ld index a76958638a..12aa1d0ed7 100644 --- a/components/esp_rom/esp32c2/ld/esp32c2.rom.ble-eco4.ld +++ b/components/esp_rom/esp32c2/ld/esp32c2.rom.ble-eco4.ld @@ -811,7 +811,7 @@ r_ble_lll_scan_sched_next_aux = 0x40001700; r_ble_lll_scan_sched_remove = 0x40001704; //r_ble_lll_scan_start = 0x40001708; //r_ble_lll_scan_start_rx = 0x4000170c; -r_ble_lll_scan_stop = 0x40001710; +//r_ble_lll_scan_stop = 0x40001710; r_ble_lll_scan_targeta_is_matched = 0x40001714; r_ble_lll_scan_timer_cb = 0x40001718; r_ble_lll_sched_adv_new = 0x4000171c; From bef5b134a71312f501a882befe26eb37465f5aac Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 7 Nov 2025 15:51:16 +0800 Subject: [PATCH 004/156] change(ble): [AUTO_MR] Update lib_esp32h2 to b6027aeb --- components/bt/controller/lib_esp32h2/esp32h2-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib index efca94610a..a568fa5a03 160000 --- a/components/bt/controller/lib_esp32h2/esp32h2-bt-lib +++ b/components/bt/controller/lib_esp32h2/esp32h2-bt-lib @@ -1 +1 @@ -Subproject commit efca94610a5e62b8d18abf8a5f6a07b6b23b72ca +Subproject commit a568fa5a03545dd133a301ccdbae99afa3692923 From 5811c72e6a77c36b6d190a430389440cb5381894 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 7 Nov 2025 15:51:34 +0800 Subject: [PATCH 005/156] change(ble): [AUTO_MR] Update lib_esp32c6 to b6027aeb --- components/bt/controller/lib_esp32c6/esp32c6-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib index d2dffe0556..cf7c287226 160000 --- a/components/bt/controller/lib_esp32c6/esp32c6-bt-lib +++ b/components/bt/controller/lib_esp32c6/esp32c6-bt-lib @@ -1 +1 @@ -Subproject commit d2dffe055672f10ff5fbeb359c533d9561c33ea4 +Subproject commit cf7c287226c2c8575dc1cb9896d54a14a18d1dd4 From a18213cc8a15dd0e1e78137ff23daf610fc2f293 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 7 Nov 2025 15:52:03 +0800 Subject: [PATCH 006/156] change(ble): [AUTO_MR] Update lib_esp32c5 to b6027aeb --- components/bt/controller/lib_esp32c5/esp32c5-bt-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib index e97692ec30..a5feba34e1 160000 --- a/components/bt/controller/lib_esp32c5/esp32c5-bt-lib +++ b/components/bt/controller/lib_esp32c5/esp32c5-bt-lib @@ -1 +1 @@ -Subproject commit e97692ec3090b03cba9e49a75d248e2dbbfda25c +Subproject commit a5feba34e144c82374fb9818108d6efc5216dc1f From 3030f4770fb14468de26f94a7237e17d90921b11 Mon Sep 17 00:00:00 2001 From: Zhao Wei Liang Date: Fri, 7 Nov 2025 15:13:23 +0800 Subject: [PATCH 007/156] feat: rename ble sleep related apt on ESP32-C6 (cherry picked from commit 8e1292e1f29795d02226d178debf6c1564f6e33d) Co-authored-by: cjin --- components/bt/controller/esp32c6/bt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bt/controller/esp32c6/bt.c b/components/bt/controller/esp32c6/bt.c index 0b7825de34..a442f8d85c 100644 --- a/components/bt/controller/esp32c6/bt.c +++ b/components/bt/controller/esp32c6/bt.c @@ -167,7 +167,7 @@ extern void esp_unregister_npl_funcs (void); extern void npl_freertos_mempool_deinit(void); extern uint32_t r_os_cputime_get32(void); extern uint32_t r_os_cputime_ticks_to_usecs(uint32_t ticks); -extern void r_ble_lll_rfmgmt_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, +extern void r_ble_lll_sleep_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, void *w_arg, uint32_t us_to_enabled); extern void r_ble_rtc_wake_up_state_clr(void); extern int os_msys_init(void); @@ -848,10 +848,10 @@ esp_err_t controller_sleep_init(void) #ifdef CONFIG_BT_LE_SLEEP_ENABLE ESP_LOGW(NIMBLE_PORT_LOG_TAG, "BLE modem sleep is enabled"); #if CONFIG_FREERTOS_USE_TICKLESS_IDLE - r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + r_ble_lll_sleep_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, BLE_RTC_DELAY_US_LIGHT_SLEEP); #else - r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + r_ble_lll_sleep_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, BLE_RTC_DELAY_US_MODEM_SLEEP); #endif /* FREERTOS_USE_TICKLESS_IDLE */ #endif // CONFIG_BT_LE_SLEEP_ENABLE From 975a3f92e6ebd3a49a5c040cfb751ede50d8c5a3 Mon Sep 17 00:00:00 2001 From: Zhao Wei Liang Date: Fri, 7 Nov 2025 15:13:24 +0800 Subject: [PATCH 008/156] feat: rename ble sleep related apt on ESP32-H2 (cherry picked from commit 658efa27f071c33b6a35d43b465f5ac32b2e20f7) Co-authored-by: cjin --- components/bt/controller/esp32h2/bt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bt/controller/esp32h2/bt.c b/components/bt/controller/esp32h2/bt.c index 4daa9d3fbe..6ea4185a27 100644 --- a/components/bt/controller/esp32h2/bt.c +++ b/components/bt/controller/esp32h2/bt.c @@ -159,7 +159,7 @@ extern void esp_unregister_npl_funcs (void); extern void npl_freertos_mempool_deinit(void); extern uint32_t r_os_cputime_get32(void); extern uint32_t r_os_cputime_ticks_to_usecs(uint32_t ticks); -extern void r_ble_lll_rfmgmt_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, +extern void r_ble_lll_sleep_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, void *w_arg, uint32_t us_to_enabled); extern void r_ble_rtc_wake_up_state_clr(void); extern int os_msys_init(void); @@ -816,10 +816,10 @@ esp_err_t controller_sleep_init(void) #ifdef CONFIG_BT_LE_SLEEP_ENABLE ESP_LOGW(NIMBLE_PORT_LOG_TAG, "BLE modem sleep is enabled"); #if CONFIG_FREERTOS_USE_TICKLESS_IDLE - r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + r_ble_lll_sleep_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, BLE_RTC_DELAY_US_LIGHT_SLEEP); #else - r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + r_ble_lll_sleep_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, BLE_RTC_DELAY_US_MODEM_SLEEP); #endif /* FREERTOS_USE_TICKLESS_IDLE */ #endif // CONFIG_BT_LE_SLEEP_ENABLE From 0633afea3bd66217ef3bda194ab8aaa17015547b Mon Sep 17 00:00:00 2001 From: Zhao Wei Liang Date: Fri, 7 Nov 2025 15:13:24 +0800 Subject: [PATCH 009/156] feat: rename ble sleep related apt on ESP32-C5 (cherry picked from commit ed6587b1324a8b603bd05287993758eb6974bbe5) Co-authored-by: cjin --- components/bt/controller/esp32c5/bt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/bt/controller/esp32c5/bt.c b/components/bt/controller/esp32c5/bt.c index d543b571e0..7453a6917f 100644 --- a/components/bt/controller/esp32c5/bt.c +++ b/components/bt/controller/esp32c5/bt.c @@ -155,7 +155,7 @@ extern void esp_unregister_npl_funcs (void); extern void npl_freertos_mempool_deinit(void); extern uint32_t r_os_cputime_get32(void); extern uint32_t r_os_cputime_ticks_to_usecs(uint32_t ticks); -extern void r_ble_lll_rfmgmt_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, +extern void r_ble_lll_sleep_set_sleep_cb(void *s_cb, void *w_cb, void *s_arg, void *w_arg, uint32_t us_to_enabled); extern void r_ble_rtc_wake_up_state_clr(void); extern int os_msys_init(void); @@ -788,10 +788,10 @@ esp_err_t controller_sleep_init(void) #ifdef CONFIG_BT_LE_SLEEP_ENABLE ESP_LOGW(NIMBLE_PORT_LOG_TAG, "BLE modem sleep is enabled"); #if CONFIG_FREERTOS_USE_TICKLESS_IDLE - r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + r_ble_lll_sleep_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, BLE_RTC_DELAY_US_LIGHT_SLEEP); #else - r_ble_lll_rfmgmt_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, + r_ble_lll_sleep_set_sleep_cb(controller_sleep_cb, controller_wakeup_cb, 0, 0, BLE_RTC_DELAY_US_MODEM_SLEEP); #endif /* FREERTOS_USE_TICKLESS_IDLE */ #endif // CONFIG_BT_LE_SLEEP_ENABLE From 5e63d62db91c3bb51c1900771d87969a473ed8d7 Mon Sep 17 00:00:00 2001 From: Zhao Wei Liang Date: Fri, 7 Nov 2025 15:13:24 +0800 Subject: [PATCH 010/156] feat(ble): add peripheral fast rx data in latency config on ESP32-C6 (cherry picked from commit 0f03da43c8cab9a8cd54d56e81782e693dcac789) Co-authored-by: zhaoweiliang --- components/bt/controller/esp32c6/Kconfig.in | 8 ++++++++ components/bt/controller/esp32c6/esp_bt_cfg.h | 6 ++++++ components/bt/controller/esp32h2/Kconfig.in | 8 ++++++++ components/bt/controller/esp32h2/esp_bt_cfg.h | 6 ++++++ components/bt/include/esp32c6/include/esp_bt.h | 5 ++++- components/bt/include/esp32h2/include/esp_bt.h | 4 +++- 6 files changed, 35 insertions(+), 2 deletions(-) diff --git a/components/bt/controller/esp32c6/Kconfig.in b/components/bt/controller/esp32c6/Kconfig.in index 93ba378454..a2f5ec997b 100644 --- a/components/bt/controller/esp32c6/Kconfig.in +++ b/components/bt/controller/esp32c6/Kconfig.in @@ -977,3 +977,11 @@ menu "Scheduling Priority Level Config" default 2 if BT_LE_SYNC_SCHED_PRIO_HIGH_LEVEL default 1 endmenu + +config BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN + bool "Enable Peripheral fast PDU reception during latency" + default n + help + When this option is enabled, the Controller continues receiving PDUs + In the next connection event instead of entering latency + After a data packet is received. diff --git a/components/bt/controller/esp32c6/esp_bt_cfg.h b/components/bt/controller/esp32c6/esp_bt_cfg.h index 2586976c90..71f7f9d194 100644 --- a/components/bt/controller/esp32c6/esp_bt_cfg.h +++ b/components/bt/controller/esp32c6/esp_bt_cfg.h @@ -212,6 +212,12 @@ extern "C" { #define DEFAULT_BT_LE_CTRL_FAST_CONN_DATA_TX_EN (0) #endif +#if defined(CONFIG_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN) +#define DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN (CONFIG_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN) +#else +#define DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN (0) +#endif + #ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART #define HCI_UART_EN CONFIG_BT_LE_HCI_INTERFACE_USE_UART #else diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index 17a1d9abf2..00ae776c2d 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -981,3 +981,11 @@ menu "Scheduling Priority Level Config" default 2 if BT_LE_SYNC_SCHED_PRIO_HIGH_LEVEL default 1 endmenu + +config BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN + bool "Enable Peripheral fast PDU reception during latency" + default n + help + When this option is enabled, the Controller continues receiving PDUs + In the next connection event instead of entering latency + After a data packet is received. diff --git a/components/bt/controller/esp32h2/esp_bt_cfg.h b/components/bt/controller/esp32h2/esp_bt_cfg.h index e79eb742e2..4dbe2f2fe8 100644 --- a/components/bt/controller/esp32h2/esp_bt_cfg.h +++ b/components/bt/controller/esp32h2/esp_bt_cfg.h @@ -209,6 +209,12 @@ extern "C" { #define DEFAULT_BT_LE_CTRL_FAST_CONN_DATA_TX_EN (0) #endif +#if defined(CONFIG_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN) +#define DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN (CONFIG_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN) +#else +#define DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN (0) +#endif + #ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART #define HCI_UART_EN CONFIG_BT_LE_HCI_INTERFACE_USE_UART #else diff --git a/components/bt/include/esp32c6/include/esp_bt.h b/components/bt/include/esp32c6/include/esp_bt.h index 7181be6e43..3ccdeb7cb7 100644 --- a/components/bt/include/esp32c6/include/esp_bt.h +++ b/components/bt/include/esp32c6/include/esp_bt.h @@ -156,7 +156,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type */ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -#define CONFIG_VERSION 0x20251022 +#define CONFIG_VERSION 0x20251104 #define CONFIG_MAGIC 0x5A5AA5A5 /** @@ -235,6 +235,7 @@ typedef struct { uint8_t adv_rsv_cnt; /*!< BLE adv state machine reserve count number */ uint8_t conn_rsv_cnt; /*!< BLE conn state machine reserve count number */ uint8_t priority_level_cfg; /*!< The option for priority level configuration */ + uint8_t slv_fst_rx_lat_en; /*!< The option for enabling slave fast PDU reception during latency. */ uint32_t config_magic; /*!< Magic number for configuration validation */ } esp_bt_controller_config_t; @@ -300,6 +301,7 @@ typedef struct { .adv_rsv_cnt = BLE_LL_ADV_SM_RESERVE_CNT_N, \ .conn_rsv_cnt = BLE_LL_CONN_SM_RESERVE_CNT_N, \ .priority_level_cfg = BT_LL_CTRL_PRIO_LVL_CFG, \ + .slv_fst_rx_lat_en = DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN, \ .config_magic = CONFIG_MAGIC, \ } #elif CONFIG_IDF_TARGET_ESP32C61 @@ -362,6 +364,7 @@ typedef struct { .adv_rsv_cnt = BLE_LL_ADV_SM_RESERVE_CNT_N, \ .conn_rsv_cnt = BLE_LL_CONN_SM_RESERVE_CNT_N, \ .priority_level_cfg = BT_LL_CTRL_PRIO_LVL_CFG, \ + .slv_fst_rx_lat_en = DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN, \ .config_magic = CONFIG_MAGIC, \ } #endif diff --git a/components/bt/include/esp32h2/include/esp_bt.h b/components/bt/include/esp32h2/include/esp_bt.h index b6bb5bfb23..a171b52a6b 100644 --- a/components/bt/include/esp32h2/include/esp_bt.h +++ b/components/bt/include/esp32h2/include/esp_bt.h @@ -161,7 +161,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type */ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -#define CONFIG_VERSION 0x20251022 +#define CONFIG_VERSION 0x20251104 #define CONFIG_MAGIC 0x5A5AA5A5 /** @@ -237,6 +237,7 @@ typedef struct { uint8_t adv_rsv_cnt; /*!< BLE adv state machine reserve count number */ uint8_t conn_rsv_cnt; /*!< BLE conn state machine reserve count number */ uint8_t priority_level_cfg; /*!< The option for priority level configuration */ + uint8_t slv_fst_rx_lat_en; /*!< The option for enabling slave fast PDU reception during latency. */ uint32_t config_magic; /*!< Configuration magic value */ } esp_bt_controller_config_t; @@ -300,6 +301,7 @@ typedef struct { .adv_rsv_cnt = BLE_LL_ADV_SM_RESERVE_CNT_N, \ .conn_rsv_cnt = BLE_LL_CONN_SM_RESERVE_CNT_N, \ .priority_level_cfg = BT_LL_CTRL_PRIO_LVL_CFG, \ + .slv_fst_rx_lat_en = DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN, \ .config_magic = CONFIG_MAGIC, \ } From 3a1a9d88130e5e260c820bc13d1d740136d36975 Mon Sep 17 00:00:00 2001 From: Zhao Wei Liang Date: Fri, 7 Nov 2025 15:13:25 +0800 Subject: [PATCH 011/156] feat(ble): add peripheral fast rx data in latency config on ESP32-C5 (cherry picked from commit 29890c89161ae83f1f7eb9f15579cb590877b928) Co-authored-by: zhaoweiliang --- components/bt/controller/esp32c5/Kconfig.in | 8 ++++++++ components/bt/controller/esp32c5/esp_bt_cfg.h | 6 ++++++ components/bt/include/esp32c5/include/esp_bt.h | 4 +++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/components/bt/controller/esp32c5/Kconfig.in b/components/bt/controller/esp32c5/Kconfig.in index c85bd425c8..84335624f5 100644 --- a/components/bt/controller/esp32c5/Kconfig.in +++ b/components/bt/controller/esp32c5/Kconfig.in @@ -943,3 +943,11 @@ menu "Scheduling Priority Level Config" default 2 if BT_LE_SYNC_SCHED_PRIO_HIGH_LEVEL default 1 endmenu + +config BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN + bool "Enable Peripheral fast PDU reception during latency" + default n + help + When this option is enabled, the Controller continues receiving PDUs + In the next connection event instead of entering latency + After a data packet is received. diff --git a/components/bt/controller/esp32c5/esp_bt_cfg.h b/components/bt/controller/esp32c5/esp_bt_cfg.h index e79eb742e2..4dbe2f2fe8 100644 --- a/components/bt/controller/esp32c5/esp_bt_cfg.h +++ b/components/bt/controller/esp32c5/esp_bt_cfg.h @@ -209,6 +209,12 @@ extern "C" { #define DEFAULT_BT_LE_CTRL_FAST_CONN_DATA_TX_EN (0) #endif +#if defined(CONFIG_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN) +#define DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN (CONFIG_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN) +#else +#define DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN (0) +#endif + #ifdef CONFIG_BT_LE_HCI_INTERFACE_USE_UART #define HCI_UART_EN CONFIG_BT_LE_HCI_INTERFACE_USE_UART #else diff --git a/components/bt/include/esp32c5/include/esp_bt.h b/components/bt/include/esp32c5/include/esp_bt.h index 7132b44c4b..b44c861e72 100644 --- a/components/bt/include/esp32c5/include/esp_bt.h +++ b/components/bt/include/esp32c5/include/esp_bt.h @@ -159,7 +159,7 @@ esp_err_t esp_ble_tx_power_set_enhanced(esp_ble_enhanced_power_type_t power_type */ esp_power_level_t esp_ble_tx_power_get_enhanced(esp_ble_enhanced_power_type_t power_type, uint16_t handle); -#define CONFIG_VERSION 0x20251022 +#define CONFIG_VERSION 0x20251104 #define CONFIG_MAGIC 0x5A5AA5A5 /** @@ -235,6 +235,7 @@ typedef struct { uint8_t adv_rsv_cnt; /*!< BLE adv state machine reserve count number */ uint8_t conn_rsv_cnt; /*!< BLE conn state machine reserve count number */ uint8_t priority_level_cfg; /*!< The option for priority level configuration */ + uint8_t slv_fst_rx_lat_en; /*!< The option for enabling slave fast PDU reception during latency. */ uint32_t config_magic; /*!< Magic number for configuration validation */ } esp_bt_controller_config_t; @@ -297,6 +298,7 @@ typedef struct { .adv_rsv_cnt = BLE_LL_ADV_SM_RESERVE_CNT_N, \ .conn_rsv_cnt = BLE_LL_CONN_SM_RESERVE_CNT_N, \ .priority_level_cfg = BT_LL_CTRL_PRIO_LVL_CFG, \ + .slv_fst_rx_lat_en = DEFAULT_BT_LE_CTRL_SLV_FAST_RX_CONN_DATA_EN, \ .config_magic = CONFIG_MAGIC, \ } From b3b500231fbdf351f1294020bf0336c62ba18ddd Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Thu, 13 Nov 2025 09:53:49 +0100 Subject: [PATCH 012/156] fix(esp_eth): maked esp_eth_test_l2 more robust --- .../esp_eth/test_apps/main/esp_eth_test_l2.c | 33 ++++++++----------- .../esp_eth/test_apps/pytest_esp_eth.py | 7 ++-- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/components/esp_eth/test_apps/main/esp_eth_test_l2.c b/components/esp_eth/test_apps/main/esp_eth_test_l2.c index 4f88c318ba..19d09b81b9 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_l2.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_l2.c @@ -220,6 +220,15 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") TEST_ESP_OK(esp_eth_update_input_path(eth_handle, l2_packet_txrx_test_cb, &s_recv_info)); + TEST_ESP_OK(esp_eth_start(eth_handle)); // start Ethernet driver state machine + + EventBits_t bits = 0; + bits = xEventGroupWaitBits(eth_event_state_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(WAIT_FOR_CONN_TMO_MS)); + TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); + // if DUT is connected in network with switch: even if link is indicated up, it may take some time the switch + // starts switching the associated port (e.g. it runs RSTP at first) + poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); + // --------------------------------------- printf("Enable receive all multicast\n"); // --------------------------------------- @@ -231,18 +240,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") s_recv_info.brdcast_rx_cnt = 0; bool all_multicast = true; TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_ALL_MULTICAST, &all_multicast)); - - TEST_ESP_OK(esp_eth_start(eth_handle)); // start Ethernet driver state machine - - EventBits_t bits = 0; - bits = xEventGroupWaitBits(eth_event_state_group, ETH_CONNECT_BIT, true, true, pdMS_TO_TICKS(WAIT_FOR_CONN_TMO_MS)); - TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT); - // if DUT is connected in network with switch: even if link is indicated up, it may take some time the switch - // starts switching the associated port (e.g. it runs RSTP at first) - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); - bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); @@ -270,11 +270,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") s_recv_info.brdcast_rx_cnt = 0; all_multicast = false; TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_ALL_MULTICAST, &all_multicast)); - // send POKE to indicate that the DUT reconfigured the filter - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); - bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); @@ -297,10 +295,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_ADD_MAC_FILTER, multicast_addr_ip4)); uint8_t multicast_addr_ip6[ETH_ADDR_LEN] = {0x33, 0x33, 0x00, 0x00, 0x00, 0x00}; TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_ADD_MAC_FILTER, multicast_addr_ip6)); - // send POKE to indicate that the DUT reconfigured the filter - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); @@ -319,10 +316,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") s_recv_info.multicast_rx_cnt = 0; s_recv_info.brdcast_rx_cnt = 0; TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_DEL_MAC_FILTER, multicast_addr_ip4)); - // send POKE to indicate that the DUT reconfigured the filter - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); @@ -355,10 +351,9 @@ TEST_CASE("ethernet recv_pkt", "[ethernet_l2]") #else TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_DEL_MAC_FILTER, multicast_addr_ip6)); #endif - // send POKE to indicate that the DUT reconfigured the filter - poke_and_wait(eth_handle, NULL, 0, NULL, eth_event_rx_group); bits = 0; xEventGroupClearBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT); + printf("Filter configured\n"); bits = xEventGroupWaitBits(eth_event_rx_group, ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT, true, true, pdMS_TO_TICKS(1000)); printf("bits = 0x%" PRIu32 "\n", (uint32_t)bits & (ETH_BROADCAST_RECV_BIT | ETH_MULTICAST_RECV_BIT | ETH_UNICAST_RECV_BIT)); diff --git a/components/esp_eth/test_apps/pytest_esp_eth.py b/components/esp_eth/test_apps/pytest_esp_eth.py index b151a1f1f3..a6cac72354 100644 --- a/components/esp_eth/test_apps/pytest_esp_eth.py +++ b/components/esp_eth/test_apps/pytest_esp_eth.py @@ -169,11 +169,10 @@ def ethernet_l2_test(dut: IdfDut) -> None: r'DUT MAC: ([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2})' ) dut_mac = res.group(1).decode('utf-8') + target_if.recv_resp_poke(mac=dut_mac) for _ in range(5): - # wait for POKE msg to be sure the switch already started forwarding the port's traffic - # (there might be slight delay due to the RSTP execution) - # or wait for next POKE msg to be sure the DUT reconfigured the filter - target_if.recv_resp_poke(mac=dut_mac) + # wait to be sure the DUT reconfigured the filter + dut.expect_exact('Filter configured') target_if.send_eth_packet('ff:ff:ff:ff:ff:ff') # broadcast frame target_if.send_eth_packet('01:00:5e:00:00:00') # IPv4 multicast frame target_if.send_eth_packet('33:33:00:00:00:00') # IPv6 multicast frame From 036c8673cd206b35dbaf2d2afe69fc21e61bfd6d Mon Sep 17 00:00:00 2001 From: Jeremy Boynes Date: Tue, 11 Nov 2025 19:15:46 -0800 Subject: [PATCH 013/156] fix(esp_lcd): Issue where M5Stack CoreS3 uses GPIO 35 for MISO and LCD D/C Adopts approach used by M5GFX that enables/diables output during SPI transaction. --- components/esp_lcd/spi/esp_lcd_panel_io_spi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/esp_lcd/spi/esp_lcd_panel_io_spi.c b/components/esp_lcd/spi/esp_lcd_panel_io_spi.c index 13a84ca50f..e276ef9ea3 100644 --- a/components/esp_lcd/spi/esp_lcd_panel_io_spi.c +++ b/components/esp_lcd/spi/esp_lcd_panel_io_spi.c @@ -412,6 +412,9 @@ IRAM_ATTR static void lcd_spi_pre_trans_cb(spi_transaction_t *trans) if (spi_panel_io->dc_gpio_num >= 0) { // set D/C line level if necessary // use ll function to speed up gpio_ll_set_level(&GPIO, spi_panel_io->dc_gpio_num, lcd_trans->flags.dc_gpio_level); + + // ensure the D/C output is enabled + gpio_ll_output_enable(&GPIO, spi_panel_io->dc_gpio_num); } } @@ -419,6 +422,12 @@ static void lcd_spi_post_trans_color_cb(spi_transaction_t *trans) { esp_lcd_panel_io_spi_t *spi_panel_io = trans->user; lcd_spi_trans_descriptor_t *lcd_trans = __containerof(trans, lcd_spi_trans_descriptor_t, base); + + // disable the D/C output as we no longer need it + if (spi_panel_io->dc_gpio_num >= 0) { + gpio_ll_output_disable(&GPIO, spi_panel_io->dc_gpio_num); + } + if (lcd_trans->flags.en_trans_done_cb) { if (spi_panel_io->on_color_trans_done) { spi_panel_io->on_color_trans_done(&spi_panel_io->base, NULL, spi_panel_io->user_ctx); From 54513a220a00fdf45dfe84fe0bda06d4b700d24b Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Tue, 18 Nov 2025 17:11:52 +0800 Subject: [PATCH 014/156] feat(bt): Adds an SPP API parameter to indicate whether to create SPP record --- .../bt/host/bluedroid/api/esp_spp_api.c | 35 +++++++++++++------ .../bluedroid/api/include/api/esp_spp_api.h | 26 +++++++++++++- .../btc/profile/std/include/btc_spp.h | 1 + .../bluedroid/btc/profile/std/spp/btc_spp.c | 15 ++++++-- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/components/bt/host/bluedroid/api/esp_spp_api.c b/components/bt/host/bluedroid/api/esp_spp_api.c index 5c01aeb2e5..18ef661c16 100644 --- a/components/bt/host/bluedroid/api/esp_spp_api.c +++ b/components/bt/host/bluedroid/api/esp_spp_api.c @@ -145,22 +145,34 @@ esp_err_t esp_spp_disconnect(uint32_t handle) esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t local_scn, const char *name) +{ + esp_spp_start_srv_cfg_t cfg = {0}; + + cfg.local_scn = local_scn; + cfg.sec_mask = sec_mask; + cfg.role = role; + cfg.create_spp_record = true; + cfg.name = name; + return esp_spp_start_srv_with_cfg(&cfg); +} + +esp_err_t esp_spp_start_srv_with_cfg(const esp_spp_start_srv_cfg_t *cfg) { btc_msg_t msg; btc_spp_args_t arg; ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED); - if (name == NULL || strlen(name) > ESP_SPP_SERVER_NAME_MAX) { + if (cfg == NULL || cfg->name == NULL || strlen(cfg->name) > ESP_SPP_SERVER_NAME_MAX) { LOG_ERROR("Invalid server name!\n"); return ESP_ERR_INVALID_ARG; } - if (sec_mask != ESP_SPP_SEC_NONE && - sec_mask != ESP_SPP_SEC_AUTHENTICATE && - sec_mask != (ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT) && - sec_mask != ESP_SPP_SEC_IN_16_DIGITS && - sec_mask != (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE) && - sec_mask != (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT)) { + if (cfg->sec_mask != ESP_SPP_SEC_NONE && + cfg->sec_mask != ESP_SPP_SEC_AUTHENTICATE && + cfg->sec_mask != (ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT) && + cfg->sec_mask != ESP_SPP_SEC_IN_16_DIGITS && + cfg->sec_mask != (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE) && + cfg->sec_mask != (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT)) { LOG_WARN("Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHENTICATE," "(ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT)," "ESP_SPP_SEC_IN_16_DIGITS, (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE), or" @@ -171,11 +183,12 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, msg.pid = BTC_PID_SPP; msg.act = BTC_SPP_ACT_START_SRV; - arg.start_srv.sec_mask = sec_mask; - arg.start_srv.role = role; - arg.start_srv.local_scn = local_scn; + arg.start_srv.sec_mask = cfg->sec_mask; + arg.start_srv.role = cfg->role; + arg.start_srv.local_scn = cfg->local_scn; + arg.start_srv.create_spp_record = cfg->create_spp_record; arg.start_srv.max_session = ESP_SPP_MAX_SESSION; - strcpy(arg.start_srv.name, name); + strcpy(arg.start_srv.name, cfg->name); return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } diff --git a/components/bt/host/bluedroid/api/include/api/esp_spp_api.h b/components/bt/host/bluedroid/api/include/api/esp_spp_api.h index 40788667c0..e6cdf2fc69 100644 --- a/components/bt/host/bluedroid/api/include/api/esp_spp_api.h +++ b/components/bt/host/bluedroid/api/include/api/esp_spp_api.h @@ -74,7 +74,7 @@ typedef enum { } esp_spp_mode_t; /** - * @brief SPP configuration parameters + * @brief SPP initialization configuration parameters. */ typedef struct { esp_spp_mode_t mode; /*!< Choose the mode of SPP, ESP_SPP_MODE_CB or ESP_SPP_MODE_VFS. */ @@ -82,6 +82,17 @@ typedef struct { uint16_t tx_buffer_size; /*!< Tx buffer size for a new SPP channel. A smaller setting can save memory, but may incur a decrease in throughput. Only for ESP_SPP_MODE_VFS mode. */ } esp_spp_cfg_t; +/** + * @brief SPP start server configuration parameters. + */ +typedef struct { + uint8_t local_scn; /*!< The specific channel you want to get. If channel is 0, means get any channel. */ + bool create_spp_record; /*!< Specifies whether to create the SPP record */ + esp_spp_sec_t sec_mask; /*!< Security Setting Mask. Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE or ESP_SPP_SEC_AUTHENTICATE only */ + esp_spp_role_t role; /*!< Master or slave. */ + const char *name; /*!< Server's name. */ +} esp_spp_start_srv_cfg_t; + /** * @brief SPP callback function events */ @@ -368,6 +379,19 @@ esp_err_t esp_spp_disconnect(uint32_t handle); */ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t local_scn, const char *name); +/** + * @brief This function is similar to `esp_spp_start_srv`. + * The only difference is that it adds a parameter to specify whether to create the SPP record. + * @note If the SPP record is not created, it is suggested to use it together with the SDP API. + * + * @param[in] cfg: Configuration parameters for starting the server. + * + * @return + * - ESP_OK: success + * - other: failed + */ +esp_err_t esp_spp_start_srv_with_cfg(const esp_spp_start_srv_cfg_t *cfg); + /** * @brief This function stops all SPP servers. * The operation will close all active SPP connection first, then the callback function will be called diff --git a/components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h b/components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h index 5082a135e1..fd349c7de6 100644 --- a/components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h +++ b/components/bt/host/bluedroid/btc/profile/std/include/btc_spp.h @@ -67,6 +67,7 @@ typedef union { esp_spp_sec_t sec_mask; esp_spp_role_t role; UINT8 local_scn; + bool create_spp_record; UINT8 max_session; char name[ESP_SPP_SERVER_NAME_MAX + 1]; } start_srv; diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index bb142531a3..8607e42191 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -50,6 +50,7 @@ typedef struct { bool connected; bool is_server; bool is_writing; + bool create_spp_record; uint8_t serial; uint8_t scn; uint8_t max_session; @@ -143,6 +144,7 @@ static spp_slot_t *spp_malloc_slot(void) (*slot)->rfc_port_handle = 0; (*slot)->fd = -1; (*slot)->connected = false; + (*slot)->create_spp_record = false; (*slot)->is_server = false; (*slot)->mtu = 0; (*slot)->credit_rx = BTA_JV_MAX_CREDIT_NUM; @@ -378,6 +380,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u strcpy(slot_new->service_name, slot->service_name); slot_new->sdp_handle = slot->sdp_handle; slot_new->mtu = p_data->rfc_srv_open.peer_mtu; + slot_new->create_spp_record = slot->create_spp_record; slot_new->rfc_handle = p_data->rfc_srv_open.handle; slot_new->rfc_port_handle = BTA_JvRfcommGetPortHdl(slot_new->rfc_handle); BTA_JvSetPmProfile(p_data->rfc_srv_open.handle, BTA_JV_PM_ALL, BTA_JV_CONN_OPEN); @@ -482,7 +485,14 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d } slot->scn = p_data->scn; - BTA_JvCreateRecordByUser(slot->service_name, slot->scn, (void *)slot->id); + if (slot->create_spp_record) { + BTA_JvCreateRecordByUser(slot->service_name, slot->scn, (void *)slot->id); + } else { + slot->sdp_handle = 0xffff; + BTA_JvRfcommStartServer(slot->security, slot->role, slot->scn, + slot->max_session, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id); + } + osi_mutex_unlock(&spp_local_param.spp_slot_mutex); break; case BTA_JV_CREATE_RECORD_EVT: @@ -748,6 +758,7 @@ static void btc_spp_start_srv(btc_spp_args_t *arg) * make this slot become a listening slot */ slot->is_server = true; + slot->create_spp_record = arg->start_srv.create_spp_record; slot->security = arg->start_srv.sec_mask; slot->role = arg->start_srv.role; slot->scn = arg->start_srv.local_scn; @@ -832,7 +843,7 @@ static void btc_spp_stop_srv(btc_spp_args_t *arg) if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->is_server && spp_local_param.spp_slots[i]->sdp_handle > 0 && spp_local_param.spp_slots[i]->scn == srv_scn_arr[j]) { - if (spp_local_param.spp_slots[i]->sdp_handle > 0) { + if (spp_local_param.spp_slots[i]->sdp_handle > 0 && spp_local_param.spp_slots[i]->create_spp_record) { BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle); } From 14a67afb04e9f9b0742b1deafdeeef943455223c Mon Sep 17 00:00:00 2001 From: yangfeng Date: Mon, 17 Nov 2025 16:52:08 +0800 Subject: [PATCH 015/156] fix(bt/examples): Fixed test_bt_l2cap not finding ESP_SDP_CREATE_RECORD_COMP_EVT --- .../classic_bt/pytest_classic_bt_test.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py b/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py index 4154dce414..74a9e40c5a 100644 --- a/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py +++ b/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py @@ -6,6 +6,7 @@ from typing import Tuple import pexpect import pytest from pytest_embedded_idf.dut import IdfDut + # Case 1: SPP @@ -15,7 +16,8 @@ from pytest_embedded_idf.dut import IdfDut [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "bt_spp_acceptor")}|{os.path.join(os.path.dirname(__file__), "bt_spp_initiator")}', + f'{os.path.join(os.path.dirname(__file__), "bt_spp_acceptor")}|' + f'{os.path.join(os.path.dirname(__file__), "bt_spp_initiator")}', 'esp32|esp32', 'y', 'test', @@ -49,7 +51,8 @@ def test_bt_spp_only(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "bt_spp_vfs_acceptor")}|{os.path.join(os.path.dirname(__file__), "bt_spp_vfs_initiator")}', + f'{os.path.join(os.path.dirname(__file__), "bt_spp_vfs_acceptor")}|' + f'{os.path.join(os.path.dirname(__file__), "bt_spp_vfs_initiator")}', 'esp32|esp32', 'test', ), @@ -77,7 +80,8 @@ def test_bt_spp_vfs(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "a2dp_sink")}|{os.path.join(os.path.dirname(__file__), "a2dp_source")}', + f'{os.path.join(os.path.dirname(__file__), "a2dp_sink")}|' + f'{os.path.join(os.path.dirname(__file__), "a2dp_source")}', 'esp32|esp32', 'test', ), @@ -157,7 +161,8 @@ def test_bt_hid(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "bt_l2cap_server")}|{os.path.join(os.path.dirname(__file__), "bt_l2cap_client")}', + f'{os.path.join(os.path.dirname(__file__), "bt_l2cap_server")}|' + f'{os.path.join(os.path.dirname(__file__), "bt_l2cap_client")}', 'esp32|esp32', 'test', ), @@ -169,8 +174,11 @@ def test_bt_l2cap(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: client = dut[1] server.expect_exact('ESP_BT_L2CAP_INIT_EVT: status:0', timeout=30) - server.expect_exact('ESP_BT_L2CAP_START_EVT: status:0', timeout=30) - server.expect_exact('ESP_SDP_CREATE_RECORD_COMP_EVT: status:0', timeout=30) + server.expect( + r'(?s)(ESP_BT_L2CAP_START_EVT: status:0.*ESP_SDP_CREATE_RECORD_COMP_EVT: status:0|' + r'ESP_SDP_CREATE_RECORD_COMP_EVT: status:0.*ESP_BT_L2CAP_START_EVT: status:0)', + timeout=30, + ) client.expect_exact('ESP_BT_L2CAP_INIT_EVT: status:0', timeout=30) client.expect_exact('ESP_SDP_SEARCH_COMP_EVT: status:0', timeout=30) client.expect_exact('ESP_BT_L2CAP_OPEN_EVT: status:0', timeout=30) From ac8b73bda1ea521a608e55a417ce4e9bbdcce9bc Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Wed, 19 Nov 2025 11:17:46 +0530 Subject: [PATCH 016/156] fix(bootloader): fix signature verification skip in deep sleep scenario For CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP enabled and exit from deep sleep case the secure boot signature verification must be skipped to improve the wakeup performance. Closes https://github.com/espressif/esp-idf/issues/15590 --- .../bootloader_support/src/esp_image_format.c | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 90aa13b491..27d02f9736 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -24,6 +24,7 @@ #include "hal/cache_ll.h" #include "spi_flash_mmap.h" #include "hal/efuse_hal.h" +#include "sdkconfig.h" #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) @@ -141,6 +142,22 @@ static bool is_bootloader(uint32_t offset) ); } +#if BOOTLOADER_BUILD && (SECURE_BOOT_CHECK_SIGNATURE == 1) +#if CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP +static bool skip_verify(esp_image_load_mode_t mode, bool verify_sha) +{ + // Multi level check to ensure that its a legit exit from deep sleep case + return (esp_rom_get_reset_reason(0) == RESET_REASON_CORE_DEEP_SLEEP && + mode == ESP_IMAGE_LOAD_NO_VALIDATE && + !verify_sha) ? true : false; +} +#else + +#define skip_verify(mode, verify_sha) (false) + +#endif +#endif // BOOTLOADER_BUILD && (SECURE_BOOT_CHECK_SIGNATURE == 1) + static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data) { #ifdef BOOTLOADER_BUILD @@ -236,9 +253,9 @@ static esp_err_t image_load(esp_image_load_mode_t mode, const esp_partition_pos_ "only verify signature in bootloader" into the macro so it's tested multiple times. */ #if CONFIG_SECURE_BOOT_V2_ENABLED - ESP_FAULT_ASSERT(!esp_secure_boot_enabled() || memcmp(image_digest, verified_digest, ESP_SECURE_BOOT_DIGEST_LEN) == 0); + ESP_FAULT_ASSERT(!esp_secure_boot_enabled() || skip_verify(mode, verify_sha) || memcmp(image_digest, verified_digest, ESP_SECURE_BOOT_DIGEST_LEN) == 0); #else // Secure Boot V1 on ESP32, only verify signatures for apps not bootloaders - ESP_FAULT_ASSERT(is_bootloader(data->start_addr) || memcmp(image_digest, verified_digest, HASH_LEN) == 0); + ESP_FAULT_ASSERT(is_bootloader(data->start_addr) || skip_verify(mode, verify_sha) || memcmp(image_digest, verified_digest, HASH_LEN) == 0); #endif #endif // SECURE_BOOT_CHECK_SIGNATURE From e3024aa3b52a6d5e3d48b894c83fdd84888020b8 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Thu, 20 Nov 2025 15:42:02 +0800 Subject: [PATCH 017/156] fix(openthread): remove the duplicate macro definition --- components/openthread/include/esp_radio_spinel.h | 4 ---- .../openthread/private_include/esp_openthread_ncp.h | 11 ----------- .../private_include/esp_spinel_ncp_vendor_macro.h | 13 +++++++++++++ .../openthread/src/ncp/esp_openthread_ncp.cpp | 1 + .../openthread/src/spinel/esp_radio_spinel.cpp | 1 + 5 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 components/openthread/private_include/esp_spinel_ncp_vendor_macro.h diff --git a/components/openthread/include/esp_radio_spinel.h b/components/openthread/include/esp_radio_spinel.h index 504eda1f4f..18638b3275 100644 --- a/components/openthread/include/esp_radio_spinel.h +++ b/components/openthread/include/esp_radio_spinel.h @@ -18,10 +18,6 @@ extern "C" { #define ESP_SPINEL_LOG_TAG "ESP_RADIO_SPINEL" -#define SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR (SPINEL_PROP_VENDOR_ESP__BEGIN + 1) /* Vendor command for coordinator.*/ - -#define SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE (SPINEL_PROP_VENDOR_ESP__BEGIN + 2) /* Vendor command for pending mode.*/ - typedef enum { ESP_RADIO_SPINEL_ZIGBEE = 0x0, /* The index of Zigbee.*/ ESP_RADIO_SPINEL_OPENTHREAD = 0x1, /* The index of OpenThread.*/ diff --git a/components/openthread/private_include/esp_openthread_ncp.h b/components/openthread/private_include/esp_openthread_ncp.h index 65053bb56a..45b585cf33 100644 --- a/components/openthread/private_include/esp_openthread_ncp.h +++ b/components/openthread/private_include/esp_openthread_ncp.h @@ -4,19 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include -#if CONFIG_OPENTHREAD_NCP_VENDOR_HOOK - -#define SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR (SPINEL_PROP_VENDOR_ESP__BEGIN + 1) - -#define SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE (SPINEL_PROP_VENDOR_ESP__BEGIN + 2) - -#define SPINEL_PROP_VENDOR_ESP_COEX_EVENT (SPINEL_PROP_VENDOR_ESP__BEGIN + 3) - -#endif - #ifdef __cplusplus extern "C" { #endif diff --git a/components/openthread/private_include/esp_spinel_ncp_vendor_macro.h b/components/openthread/private_include/esp_spinel_ncp_vendor_macro.h new file mode 100644 index 0000000000..3bd9f4fb85 --- /dev/null +++ b/components/openthread/private_include/esp_spinel_ncp_vendor_macro.h @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "spinel.h" + +#define SPINEL_PROP_VENDOR_ESP_SET_COORDINATOR (SPINEL_PROP_VENDOR_ESP__BEGIN + 1) /* Vendor command for coordinator.*/ + +#define SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE (SPINEL_PROP_VENDOR_ESP__BEGIN + 2) /* Vendor command for pending mode.*/ + +#define SPINEL_PROP_VENDOR_ESP_COEX_EVENT (SPINEL_PROP_VENDOR_ESP__BEGIN + 3) diff --git a/components/openthread/src/ncp/esp_openthread_ncp.cpp b/components/openthread/src/ncp/esp_openthread_ncp.cpp index 94c31113de..b6e70eca1f 100644 --- a/components/openthread/src/ncp/esp_openthread_ncp.cpp +++ b/components/openthread/src/ncp/esp_openthread_ncp.cpp @@ -7,6 +7,7 @@ #include "sdkconfig.h" #include "esp_ieee802154.h" #include "esp_openthread_ncp.h" +#include "esp_spinel_ncp_vendor_macro.h" #include "ncp_base.hpp" #if (CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE) diff --git a/components/openthread/src/spinel/esp_radio_spinel.cpp b/components/openthread/src/spinel/esp_radio_spinel.cpp index bbcc8d2bea..8d561d2704 100644 --- a/components/openthread/src/spinel/esp_radio_spinel.cpp +++ b/components/openthread/src/spinel/esp_radio_spinel.cpp @@ -12,6 +12,7 @@ #include "esp_radio_spinel.h" #include "esp_radio_spinel_platform.h" #include "esp_radio_spinel_adapter.hpp" +#include "esp_spinel_ncp_vendor_macro.h" #include "esp_radio_spinel_uart_interface.hpp" #include "spinel_driver.hpp" #include "openthread/link.h" From 97a8ee870fbd1f998917756ad2a95eb69f5cf07f Mon Sep 17 00:00:00 2001 From: "igor.udot" Date: Mon, 24 Nov 2025 10:10:19 +0800 Subject: [PATCH 018/156] ci: pytest-ignore skip using dut id --- tools/ci/idf_pytest/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci/idf_pytest/plugin.py b/tools/ci/idf_pytest/plugin.py index 77a14526cc..c74313ac84 100644 --- a/tools/ci/idf_pytest/plugin.py +++ b/tools/ci/idf_pytest/plugin.py @@ -337,7 +337,7 @@ class IdfPytestEmbedded: res.extend( [ ChildCase( - format_case_id(target, config, case.name + f' {i}', is_qemu=is_qemu), + format_case_id(target, config, case.name, is_qemu=is_qemu), self.UNITY_RESULT_MAPPINGS[case.result], ) for case in _dut.testsuite.testcases From 7d8d166f83c3573a9f7611f6a1a927ef54650fb2 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 28 Oct 2025 18:01:46 +0800 Subject: [PATCH 019/156] ci(parlio): fixed incorrect condition in rx test case --- .../esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c index cc454aa7b4..a5494f1f9f 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c @@ -292,7 +292,7 @@ static bool test_delimiter(parlio_rx_delimiter_handle_t deli, bool free_running_ static uint32_t task_flags = 0; xTaskCreate(sender_task_thread, "sender task", 4096, &task_flags, 5, &sender_task); // Waiting for the data ready on line - while ((task_flags & TEST_TASK_DATA_READY_BIT)) { + while (!(task_flags & TEST_TASK_DATA_READY_BIT)) { vTaskDelay(1); } From ce84d734efb4c934ca47473f1e5cae910e94b6e2 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 22 Jul 2025 14:39:32 +0800 Subject: [PATCH 020/156] feat(gdma_link): support to select final node link type --- .../src/bitscrambler_loopback.c | 4 ++-- components/esp_driver_parlio/src/parlio_tx.c | 2 +- components/esp_driver_uart/src/uhci.c | 4 ++-- .../esp_hw_support/dma/async_memcpy_cp_dma.c | 4 ++-- .../esp_hw_support/dma/async_memcpy_gdma.c | 2 +- components/esp_hw_support/dma/gdma_link.c | 17 +++++++++++++---- .../dma/include/esp_private/gdma_link.h | 16 ++++++++++++---- .../test_apps/dma/main/test_gdma.c | 10 +++++----- components/esp_lcd/i80/esp_lcd_panel_io_i2s.c | 8 ++++---- components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 4 ++-- components/esp_lcd/rgb/esp_lcd_panel_rgb.c | 4 ++-- 11 files changed, 46 insertions(+), 29 deletions(-) diff --git a/components/esp_driver_bitscrambler/src/bitscrambler_loopback.c b/components/esp_driver_bitscrambler/src/bitscrambler_loopback.c index 1fe81e11cb..b69b8e8405 100644 --- a/components/esp_driver_bitscrambler/src/bitscrambler_loopback.c +++ b/components/esp_driver_bitscrambler/src/bitscrambler_loopback.c @@ -237,7 +237,7 @@ esp_err_t bitscrambler_loopback_run(bitscrambler_handle_t bs, void *buffer_in, s .length = length_bytes_in, .flags = { .mark_eof = true, - .mark_final = true, + .mark_final = GDMA_FINAL_LINK_TO_NULL, } }; gdma_link_mount_buffers(bsl->tx_link_list, 0, &in_buf_mount_config, 1, NULL); @@ -247,7 +247,7 @@ esp_err_t bitscrambler_loopback_run(bitscrambler_handle_t bs, void *buffer_in, s .length = length_bytes_out, .flags = { .mark_eof = false, - .mark_final = true, + .mark_final = GDMA_FINAL_LINK_TO_NULL, } }; gdma_link_mount_buffers(bsl->rx_link_list, 0, &out_buf_mount_config, 1, NULL); diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index baf1d295c7..86d6c22afb 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -481,7 +481,7 @@ static void parlio_mount_buffer(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_ .flags = { // if transmission is loop, we don't need to generate the EOF for 1-bit data width, DIG-559 .mark_eof = tx_unit->data_width == 1 ? !t->flags.loop_transmission : true, - .mark_final = !t->flags.loop_transmission, + .mark_final = !t->flags.loop_transmission ? GDMA_FINAL_LINK_TO_NULL : GDMA_FINAL_LINK_TO_DEFAULT, } }; diff --git a/components/esp_driver_uart/src/uhci.c b/components/esp_driver_uart/src/uhci.c index b0a40a6a23..e390d047c9 100644 --- a/components/esp_driver_uart/src/uhci.c +++ b/components/esp_driver_uart/src/uhci.c @@ -269,7 +269,7 @@ static void uhci_do_transmit(uhci_controller_handle_t uhci_ctrl, uhci_transactio .length = trans->buffer_size, .flags = { .mark_eof = true, - .mark_final = true, + .mark_final = GDMA_FINAL_LINK_TO_NULL, } }; @@ -332,7 +332,7 @@ esp_err_t uhci_receive(uhci_controller_handle_t uhci_ctrl, uint8_t *read_buffer, .buffer_alignment = buffer_alignment, .length = uhci_ctrl->rx_dir.buffer_size_per_desc_node[i], .flags = { - .mark_final = false, + .mark_final = GDMA_FINAL_LINK_TO_DEFAULT, } }; ESP_LOGD(TAG, "The DMA node %d has %d byte", i, uhci_ctrl->rx_dir.buffer_size_per_desc_node[i]); diff --git a/components/esp_hw_support/dma/async_memcpy_cp_dma.c b/components/esp_hw_support/dma/async_memcpy_cp_dma.c index add2cec2e5..3e36e6b997 100644 --- a/components/esp_hw_support/dma/async_memcpy_cp_dma.c +++ b/components/esp_hw_support/dma/async_memcpy_cp_dma.c @@ -232,7 +232,7 @@ static esp_err_t mcp_cpdma_memcpy(async_memcpy_context_t *ctx, void *dst, void * .length = n, .flags = { .mark_eof = true, // mark the last item as EOF, so the RX channel can also received an EOF list item - .mark_final = true, // using singly list, so terminate the link here + .mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here } } }; @@ -256,7 +256,7 @@ static esp_err_t mcp_cpdma_memcpy(async_memcpy_context_t *ctx, void *dst, void * .length = n, .flags = { .mark_eof = false, // EOF is set by TX side - .mark_final = true, // using singly list, so terminate the link here + .mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here } } }; diff --git a/components/esp_hw_support/dma/async_memcpy_gdma.c b/components/esp_hw_support/dma/async_memcpy_gdma.c index a6e1047dd4..f53b0aaf48 100644 --- a/components/esp_hw_support/dma/async_memcpy_gdma.c +++ b/components/esp_hw_support/dma/async_memcpy_gdma.c @@ -365,7 +365,7 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s .length = n, .flags = { .mark_eof = true, // mark the last item as EOF, so the RX channel can also received an EOF list item - .mark_final = true, // using singly list, so terminate the link here + .mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here } } }; diff --git a/components/esp_hw_support/dma/gdma_link.c b/components/esp_hw_support/dma/gdma_link.c index 1011abb224..41b29a16e4 100644 --- a/components/esp_hw_support/dma/gdma_link.c +++ b/components/esp_hw_support/dma/gdma_link.c @@ -204,10 +204,19 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i // mark the EOF node lli_nc->dw0.suc_eof = (config->flags.mark_eof == 1) && (i == num_items_need - 1); // mark the final node - if ((config->flags.mark_final == 1) && (i == num_items_need - 1)) { - lli_nc->next = NULL; - } else { - lli_nc->next = (gdma_link_list_item_t *)(list->items + (i + begin_item_idx + 1) % list_item_capacity * item_size); + switch (config->flags.mark_final) { + case GDMA_FINAL_LINK_TO_NULL: + lli_nc->next = NULL; + break; + case GDMA_FINAL_LINK_TO_HEAD: + lli_nc->next = (gdma_link_list_item_t *)(list->items); + break; + case GDMA_FINAL_LINK_TO_START: + lli_nc->next = (gdma_link_list_item_t *)(list->items + begin_item_idx * item_size); + break; + default: + lli_nc->next = (gdma_link_list_item_t *)(list->items + (i + begin_item_idx + 1) % list_item_capacity * item_size); + break; } lli_nc->dw0.owner = GDMA_LLI_OWNER_DMA; buf += max_buffer_mount_length; diff --git a/components/esp_hw_support/dma/include/esp_private/gdma_link.h b/components/esp_hw_support/dma/include/esp_private/gdma_link.h index 6bccb4c802..3e3d4be22c 100644 --- a/components/esp_hw_support/dma/include/esp_private/gdma_link.h +++ b/components/esp_hw_support/dma/include/esp_private/gdma_link.h @@ -56,6 +56,17 @@ esp_err_t gdma_new_link_list(const gdma_link_list_config_t *config, gdma_link_li */ esp_err_t gdma_del_link_list(gdma_link_list_handle_t list); +/** + * @brief Types for the next node of the final item in the DMA link list + * + */ +typedef enum { + GDMA_FINAL_LINK_TO_DEFAULT = 0, /*!< The next node is linked to the default next item in the link list */ + GDMA_FINAL_LINK_TO_NULL = 1, /*!< The next node is linked to the final item in the link list */ + GDMA_FINAL_LINK_TO_HEAD = 2, /*!< The next node is linked to the head item in the link list */ + GDMA_FINAL_LINK_TO_START = 3, /*!< The next node is linked to the start item in the link list */ +} gdma_final_node_link_type_t; + /** * @brief DMA buffer mount configurations */ @@ -68,10 +79,7 @@ typedef struct { Note, an "EOF" descriptor can be interrupted differently by peripheral. But it doesn't mean to terminate a DMA link (use `mark_final` instead). EOF link list item can also trigger an interrupt. */ - uint32_t mark_final: 1; /*!< Whether to terminate the DMA link list at this item. - Note, DMA engine will stop at this item and trigger an interrupt. - If `mark_final` is not set, this list item will point to the next item, and - wrap around to the head item if it's the last one in the list. */ + gdma_final_node_link_type_t mark_final: 2; /*!< The next node of the final item in the link list */ uint32_t bypass_buffer_align_check: 1; /*!< Whether to bypass the buffer alignment check. Only enable it when you know what you are doing. */ } flags; //!< Flags for buffer mount configurations diff --git a/components/esp_hw_support/test_apps/dma/main/test_gdma.c b/components/esp_hw_support/test_apps/dma/main/test_gdma.c index ce97d0a0b4..bb487b2a2b 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_gdma.c +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma.c @@ -278,7 +278,7 @@ static void test_gdma_m2m_transaction(gdma_channel_handle_t tx_chan, gdma_channe #if !SOC_DMA_CAN_ACCESS_FLASH .flags = { .mark_eof = true, - .mark_final = true, // using singly list, so terminate the link here + .mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here } #endif }, @@ -289,7 +289,7 @@ static void test_gdma_m2m_transaction(gdma_channel_handle_t tx_chan, gdma_channe .length = src_string_len, .flags = { .mark_eof = true, - .mark_final = true, // using singly list, so terminate the link here + .mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here } }, #endif @@ -448,7 +448,7 @@ static void test_gdma_m2m_unaligned_buffer_test(uint8_t *dst_data, uint8_t *src_ .length = data_length, .flags = { .mark_eof = true, - .mark_final = true, // using singly list, so terminate the link here + .mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here } } }; @@ -609,7 +609,7 @@ TEST_CASE("GDMA M2M Unaligned RX Buffer Test", "[GDMA][M2M]") .length = COPY_SIZE, .flags = { .mark_eof = true, - .mark_final = true, // using singly list, so terminate the link here + .mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here } }; TEST_ESP_OK(gdma_link_mount_buffers(tx_link_list, 0, &tx_buf_mount_config, 1, NULL)); @@ -619,7 +619,7 @@ TEST_CASE("GDMA M2M Unaligned RX Buffer Test", "[GDMA][M2M]") .buffer_alignment = 32, .length = COPY_SIZE, .flags = { - .mark_final = true, // using singly list, so terminate the link here + .mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here } }; TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL)); diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c index bfd15c0d29..83c6918075 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i2s.c @@ -523,7 +523,7 @@ static esp_err_t panel_io_i80_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons gdma_buffer_mount_config_t mount_config = { .flags = { .mark_eof = true, - .mark_final = true, // singly link list, mark final descriptor + .mark_final = GDMA_FINAL_LINK_TO_NULL, // singly link list, mark final descriptor } }; @@ -599,7 +599,7 @@ static esp_err_t panel_io_i80_tx_color(esp_lcd_panel_io_t *io, int lcd_cmd, cons gdma_buffer_mount_config_t mount_config = { .flags = { .mark_eof = true, - .mark_final = true, // singly link list, mark final descriptor + .mark_final = GDMA_FINAL_LINK_TO_NULL, // singly link list, mark final descriptor } }; @@ -724,7 +724,7 @@ static void i2s_lcd_trigger_quick_trans_done_event(esp_lcd_i80_bus_handle_t bus) .length = 4, .flags = { .mark_eof = true, // mark the "EOF" flag to trigger I2S EOF interrupt - .mark_final = true, // singly link list, mark final descriptor + .mark_final = GDMA_FINAL_LINK_TO_NULL, // singly link list, mark final descriptor } }; gdma_link_mount_buffers(bus->dma_link, 0, &mount_config, 1, NULL); @@ -811,7 +811,7 @@ static IRAM_ATTR void i2s_lcd_default_isr_handler(void *args) .length = trans_desc->data_length, .flags = { .mark_eof = true, - .mark_final = true, // singly link list, mark final descriptor + .mark_final = GDMA_FINAL_LINK_TO_NULL, // singly link list, mark final descriptor } }; gdma_link_mount_buffers(bus->dma_link, 0, &mount_config, 1, NULL); diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index f0ffb1b1a4..1977f6ab0f 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -500,7 +500,7 @@ static esp_err_t panel_io_i80_tx_param(esp_lcd_panel_io_t *io, int lcd_cmd, cons .length = trans_desc->data_length, .flags = { .mark_eof = true, - .mark_final = true, // singly link list, mark final descriptor + .mark_final = GDMA_FINAL_LINK_TO_NULL, // singly link list, mark final descriptor } }; gdma_link_mount_buffers(bus->dma_link, 0, &mount_config, 1, NULL); @@ -821,7 +821,7 @@ IRAM_ATTR static void i80_lcd_default_isr_handler(void *args) .length = trans_desc->data_length, .flags = { .mark_eof = true, - .mark_final = true, // singly link list, mark final descriptor + .mark_final = GDMA_FINAL_LINK_TO_NULL, // singly link list, mark final descriptor } }; gdma_link_mount_buffers(bus->dma_link, 0, &mount_config, 1, NULL); diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index 9fd7e91e31..6d3ed816b4 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -1013,7 +1013,7 @@ static esp_err_t lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *rgb_panel) mount_cfgs[i].buffer = rgb_panel->bounce_buffer[i]; mount_cfgs[i].buffer_alignment = buffer_alignment; mount_cfgs[i].length = rgb_panel->bb_size; - mount_cfgs[i].flags.mark_eof = true; // we use the DMA EOF interrupt to copy the frame buffer (partially) to the bounce buffer + mount_cfgs[i].flags.mark_eof = GDMA_FINAL_LINK_TO_NULL; // we use the DMA EOF interrupt to copy the frame buffer (partially) to the bounce buffer } ESP_RETURN_ON_ERROR(gdma_link_mount_buffers(rgb_panel->dma_bb_link, 0, mount_cfgs, RGB_LCD_PANEL_BOUNCE_BUF_NUM, NULL), TAG, "mount DMA bounce buffers failed"); @@ -1052,7 +1052,7 @@ static esp_err_t lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *rgb_panel) gdma_buffer_mount_config_t mount_cfg = { .length = rgb_panel->fb_size, .flags = { - .mark_final = rgb_panel->flags.stream_mode ? false : true, + .mark_final = rgb_panel->flags.stream_mode ? GDMA_FINAL_LINK_TO_DEFAULT : GDMA_FINAL_LINK_TO_NULL, .mark_eof = true, }, }; From 0b0306a13f39e3dc2fc78f7e5d2a51f6a7ea0766 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 21 Jul 2025 22:07:35 +0800 Subject: [PATCH 021/156] refactor(parlio_rx): use gdma_link for better gdma link management --- components/esp_driver_parlio/src/parlio_rx.c | 166 +++++++++---------- 1 file changed, 74 insertions(+), 92 deletions(-) diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index b413cc21f4..aa6b2da262 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -19,12 +19,6 @@ #define PARLIO_MAX_ALIGNED_DMA_BUF_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED #endif -#if defined(SOC_GDMA_BUS_AHB) && (SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS == SOC_GDMA_BUS_AHB) -typedef dma_descriptor_align4_t parlio_dma_desc_t; -#elif defined(SOC_GDMA_BUS_AXI) && (SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS == SOC_GDMA_BUS_AXI) -typedef dma_descriptor_align8_t parlio_dma_desc_t; -#endif - #define PARLIO_DMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA) /** @@ -32,13 +26,13 @@ typedef dma_descriptor_align8_t parlio_dma_desc_t; */ typedef struct { parlio_rx_delimiter_handle_t delimiter; /*!< Delimiter of this transaction */ - void *payload; /*!< The payload of this transaction, will be mounted to DMA descriptor */ + void *payload; /*!< The payload of this transaction, will be mounted to DMA link list node */ size_t size; /*!< The payload size in byte */ size_t recv_bytes; /*!< The received bytes of this transaction will be reset when all data filled in the infinite transaction */ struct { uint32_t infinite : 1; /*!< Whether this is an infinite transaction */ - uint32_t indirect_mount : 1; /*!< Whether the user payload mount to the descriptor indirectly via an internal DMA buffer */ + uint32_t indirect_mount : 1; /*!< Whether the user payload mount to the link list node indirectly via an internal DMA buffer */ } flags; } parlio_rx_transaction_t; @@ -70,11 +64,12 @@ typedef struct parlio_rx_unit_t { /* DMA Resources */ gdma_channel_handle_t dma_chan; /*!< DMA channel */ size_t max_recv_size; /*!< Maximum receive size for a normal transaction */ - size_t desc_num; /*!< DMA descriptor number */ - size_t desc_size; /*!< DMA descriptors total size */ - parlio_dma_desc_t **dma_descs; /*!< DMA descriptor array pointer */ - parlio_dma_desc_t *curr_desc; /*!< The pointer of the current descriptor */ - void *usr_recv_buf; /*!< The pointe to the user's receiving buffer */ + gdma_link_list_handle_t dma_link; /*!< DMA link list handle */ + uint32_t node_num; /*!< The number of nodes in the DMA link list */ + size_t int_mem_align; /*!< Alignment for internal memory */ + size_t ext_mem_align; /*!< Alignment for external memory */ + uint32_t curr_node_id; /*!< The index of the current node in the DMA link list */ + void *usr_recv_buf; /*!< The point to the user's receiving buffer */ /* Infinite transaction specific */ void *dma_buf; /*!< Additional internal DMA buffer only for infinite transactions */ @@ -122,7 +117,6 @@ static portMUX_TYPE s_rx_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parlio_rx_transaction_t *trans) { - parlio_dma_desc_t **p_desc = rx_unit->dma_descs; /* Update the current transaction to the next one, and declare the delimiter is under using of the rx unit */ memcpy(&rx_unit->curr_trans, trans, sizeof(parlio_rx_transaction_t)); portENTER_CRITICAL_SAFE(&s_rx_spinlock); @@ -131,50 +125,51 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli } portEXIT_CRITICAL_SAFE(&s_rx_spinlock); - uint32_t desc_num = trans->size / PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; - uint32_t remain_num = trans->size % PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; - /* If there are still data remained, need one more descriptor */ - desc_num += remain_num ? 1 : 0; - if (trans->flags.infinite && desc_num < 2) { - /* At least 2 descriptors needed */ - desc_num = 2; + uint32_t required_node_num = trans->size / PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; + uint32_t remain_node_num = trans->size % PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; + /* If there are still data remained, need one more node */ + required_node_num += remain_node_num ? 1 : 0; + if (trans->flags.infinite && required_node_num < 2) { + /* At least 2 nodes needed */ + required_node_num = 2; } + rx_unit->node_num = required_node_num; size_t mount_size = 0; size_t offset = 0; + // TODO: update DMA alignment #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE uint32_t alignment = rx_unit->base.group->dma_align; #else uint32_t alignment = 4; #endif - /* Loop the descriptors to assign the data */ - for (int i = 0; i < desc_num; i++) { - size_t rest_size = trans->size - offset; + gdma_buffer_mount_config_t mount_config[required_node_num]; + /* Loop the nodes to assign the data */ + for (int i = 0; i < required_node_num; i++) { + size_t rest_size = trans->size - offset; if (rest_size >= 2 * PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { - mount_size = PRALIO_RX_MOUNT_SIZE_CALC(trans->size, desc_num, alignment); + mount_size = PARLIO_RX_MOUNT_SIZE_CALC(trans->size, required_node_num, alignment); } else if (rest_size <= PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { - mount_size = (desc_num == 2) && (i == 0) ? PRALIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment) : rest_size; + mount_size = (required_node_num == 2) && (i == 0) ? PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment) : rest_size; } else { mount_size = PRALIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment); } - p_desc[i]->buffer = (void *)((uint8_t *)trans->payload + offset); - p_desc[i]->dw0.size = mount_size; - p_desc[i]->dw0.length = mount_size; - p_desc[i]->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - // Link the descriptor - if (i < desc_num - 1) { - p_desc[i]->next = p_desc[i + 1]; - } else { - /* For infinite transaction, link the descriptor as a ring */ - p_desc[i]->next = trans->flags.infinite ? p_desc[0] : NULL; + mount_config[i].buffer = (void *)((uint8_t *)trans->payload + offset); + mount_config[i].length = mount_size; + mount_config[i].flags.bypass_buffer_align_check = false; + mount_config[i].flags.mark_eof = false; + mount_config[i].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT; + // Link the node + if (i == required_node_num - 1) { + /* For infinite transaction, link the node as a ring */ + mount_config[i].flags.mark_final = !trans->flags.infinite ? GDMA_FINAL_LINK_TO_NULL : GDMA_FINAL_LINK_TO_HEAD; + mount_config[i].flags.mark_eof = true; } offset += mount_size; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - esp_cache_msync(p_desc[i], rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); -#endif } + gdma_link_mount_buffers(rx_unit->dma_link, 0, mount_config, required_node_num, NULL); /* Reset the current DMA node */ - rx_unit->curr_desc = p_desc[0]; + rx_unit->curr_node_id = 0; return offset; } @@ -350,7 +345,7 @@ static bool parlio_rx_default_eof_callback(gdma_channel_handle_t dma_chan, gdma_ } /* Mount the new transaction buffer and start the new transaction */ parlio_rx_mount_transaction_buffer(rx_unit, &next_trans); - gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->dma_descs[0]); + gdma_start(rx_unit->dma_chan, gdma_link_get_head_addr(rx_unit->dma_link)); if (rx_unit->cfg.flags.free_clk) { parlio_ll_rx_start(rx_unit->base.group->hal.regs, true); PARLIO_CLOCK_SRC_ATOMIC() { @@ -381,20 +376,20 @@ static bool parlio_rx_default_desc_done_callback(gdma_channel_handle_t dma_chan, return false; } - /* Get the finished descriptor from the current descriptor */ - parlio_dma_desc_t *finished_desc = rx_unit->curr_desc; + /* Get the finished node from the current node */ + void *finished_buffer = gdma_link_get_buffer(rx_unit->dma_link, rx_unit->curr_node_id); + size_t finished_length = gdma_link_get_length(rx_unit->dma_link, rx_unit->curr_node_id); #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE esp_err_t ret = ESP_OK; - ret |= esp_cache_msync((void *)finished_desc, rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - ret |= esp_cache_msync((void *)(finished_desc->buffer), finished_desc->dw0.size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + ret = esp_cache_msync(finished_buffer, finished_length, ESP_CACHE_MSYNC_FLAG_DIR_M2C); if (ret != ESP_OK) { ESP_EARLY_LOGW(TAG, "failed to sync dma buffer from memory to cache"); } #endif parlio_rx_event_data_t evt_data = { .delimiter = rx_unit->curr_trans.delimiter, - .data = finished_desc->buffer, - .recv_bytes = finished_desc->dw0.length, + .data = finished_buffer, + .recv_bytes = finished_length, }; if (rx_unit->cbs.on_partial_receive) { need_yield |= rx_unit->cbs.on_partial_receive(rx_unit, &evt_data, rx_unit->user_data); @@ -412,49 +407,32 @@ static bool parlio_rx_default_desc_done_callback(gdma_channel_handle_t dma_chan, rx_unit->curr_trans.recv_bytes = 0; } rx_unit->curr_trans.recv_bytes += evt_data.recv_bytes; - /* Move to the next DMA descriptor */ - rx_unit->curr_desc = rx_unit->curr_desc->next; + /* Move to the next DMA node */ + rx_unit->curr_node_id++; + rx_unit->curr_node_id %= rx_unit->node_num; return need_yield; } -static esp_err_t parlio_rx_create_dma_descriptors(parlio_rx_unit_handle_t rx_unit, uint32_t max_recv_size) +static esp_err_t parlio_rx_create_dma_link(parlio_rx_unit_handle_t rx_unit, uint32_t max_recv_size) { ESP_RETURN_ON_FALSE(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid param"); esp_err_t ret = ESP_OK; - uint32_t desc_num = max_recv_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED + 1; - /* set at least 2 descriptors */ - if (desc_num < 2) { - desc_num = 2; - } - rx_unit->desc_num = desc_num; - /* Allocated and link the descriptor nodes */ - rx_unit->dma_descs = heap_caps_calloc(desc_num, sizeof(parlio_dma_desc_t *), MALLOC_CAP_DMA); - ESP_RETURN_ON_FALSE(rx_unit->dma_descs, ESP_ERR_NO_MEM, TAG, "no memory for DMA descriptor array"); - uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); - size_t alignment = MAX(cache_line_size, PARLIO_DMA_DESC_ALIGNMENT); - rx_unit->desc_size = ALIGN_UP(sizeof(parlio_dma_desc_t), alignment); - for (int i = 0; i < desc_num; i++) { - rx_unit->dma_descs[i] = heap_caps_aligned_calloc(alignment, 1, rx_unit->desc_size, PARLIO_DMA_MEM_ALLOC_CAPS); - ESP_GOTO_ON_FALSE(rx_unit->dma_descs[i], ESP_ERR_NO_MEM, err, TAG, "no memory for DMA descriptors"); -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - esp_cache_msync(rx_unit->dma_descs[i], rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); -#endif - } + // create DMA link list + size_t buffer_alignment = MAX(rx_unit->int_mem_align, rx_unit->ext_mem_align); + size_t tot_node_num = esp_dma_calculate_node_count(max_recv_size, buffer_alignment, PARLIO_DMA_DESCRIPTOR_BUFFER_MAX_SIZE); + gdma_link_list_config_t dma_link_config = { + .buffer_alignment = buffer_alignment, + .item_alignment = PARLIO_DMA_DESC_ALIGNMENT, + .num_items = tot_node_num, + }; + + // throw the error to the caller + ESP_RETURN_ON_ERROR(gdma_new_link_list(&dma_link_config, &rx_unit->dma_link), TAG, "create DMA link list failed"); rx_unit->max_recv_size = max_recv_size; - return ret; -err: - for (int i = 0; i < desc_num; i++) { - if (rx_unit->dma_descs[i]) { - free(rx_unit->dma_descs[i]); - rx_unit->dma_descs[i] = NULL; - } - } - free(rx_unit->dma_descs); - rx_unit->dma_descs = NULL; return ret; } @@ -477,6 +455,15 @@ static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit) }; gdma_apply_strategy(rx_unit->dma_chan, &gdma_strategy_conf); + // configure DMA transfer parameters + gdma_transfer_config_t trans_cfg = { + // TODO: add burst size + .max_data_burst_size = 4, // Enable DMA burst transfer for better performance, + .access_ext_mem = true, // support transmit PSRAM buffer + }; + ESP_RETURN_ON_ERROR(gdma_config_transfer(rx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); + ESP_RETURN_ON_ERROR(gdma_get_alignment_constraints(rx_unit->dma_chan, &rx_unit->int_mem_align, &rx_unit->ext_mem_align), TAG, "get alignment constraints failed"); + /* Register callbacks */ gdma_rx_event_callbacks_t cbs = { .on_recv_eof = parlio_rx_default_eof_callback, @@ -575,16 +562,10 @@ static esp_err_t parlio_destroy_rx_unit(parlio_rx_unit_handle_t rx_unit) ESP_RETURN_ON_ERROR(gdma_disconnect(rx_unit->dma_chan), TAG, "disconnect dma channel failed"); ESP_RETURN_ON_ERROR(gdma_del_channel(rx_unit->dma_chan), TAG, "delete dma channel failed"); } - /* Free the DMA descriptors */ - if (rx_unit->dma_descs) { - for (int i = 0; i < rx_unit->desc_num; i++) { - if (rx_unit->dma_descs[i]) { - free(rx_unit->dma_descs[i]); - rx_unit->dma_descs[i] = NULL; - } - } - free(rx_unit->dma_descs); - rx_unit->dma_descs = NULL; + /* Free the DMA link list */ + if (rx_unit->dma_link) { + gdma_del_link_list(rx_unit->dma_link); + rx_unit->dma_link = NULL; } /* Free the internal DMA buffer */ if (rx_unit->dma_buf) { @@ -638,7 +619,6 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un unit->trans_que = xQueueCreateWithCaps(config->trans_queue_depth, sizeof(parlio_rx_transaction_t), PARLIO_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(unit->trans_que, ESP_ERR_NO_MEM, err, TAG, "no memory for transaction queue"); - ESP_GOTO_ON_ERROR(parlio_rx_create_dma_descriptors(unit, config->max_recv_size), err, TAG, "create dma descriptor failed"); /* Register and attach the rx unit to the group */ ESP_GOTO_ON_ERROR(parlio_register_unit_to_group(&unit->base), err, TAG, "failed to register the rx unit to the group"); memcpy(&unit->cfg, config, sizeof(parlio_rx_unit_config_t)); @@ -653,6 +633,8 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un ESP_GOTO_ON_ERROR(parlio_rx_unit_set_gpio(unit, config), err, TAG, "failed to set GPIO"); /* Install DMA service */ ESP_GOTO_ON_ERROR(parlio_rx_unit_init_dma(unit), err, TAG, "install rx DMA failed"); + ESP_GOTO_ON_ERROR(parlio_rx_create_dma_link(unit, config->max_recv_size), err, TAG, "create dma link list failed"); + /* Reset RX module */ PARLIO_RCC_ATOMIC() { parlio_ll_rx_reset_clock(hal->regs); @@ -746,7 +728,7 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu assert(trans.delimiter); parlio_rx_set_delimiter_config(rx_unit, trans.delimiter); parlio_rx_mount_transaction_buffer(rx_unit, &trans); - gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc); + gdma_start(rx_unit->dma_chan, gdma_link_get_head_addr(rx_unit->dma_link)); if (rx_unit->cfg.flags.free_clk) { parlio_ll_rx_start(hal->regs, true); PARLIO_CLOCK_SRC_ATOMIC() { @@ -935,7 +917,7 @@ static esp_err_t parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit, parlio_rx_mount_transaction_buffer(rx_unit, trans); // Take semaphore without block time here, only indicate there are transactions on receiving xSemaphoreTake(rx_unit->trans_sem, 0); - gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc); + gdma_start(rx_unit->dma_chan, gdma_link_get_head_addr(rx_unit->dma_link)); if (rx_unit->cfg.flags.free_clk) { parlio_ll_rx_start(rx_unit->base.group->hal.regs, true); PARLIO_CLOCK_SRC_ATOMIC() { From 34a54e8aee0d020d5b564d797265d3d4cd7589d8 Mon Sep 17 00:00:00 2001 From: Zheng Zhong Date: Mon, 22 Sep 2025 15:53:04 +0800 Subject: [PATCH 022/156] docs: fix some description in security guide docs --- docs/en/security/flash-encryption.rst | 3 +++ .../security-features-enablement-workflows.rst | 10 +++++++--- docs/en/security/security.rst | 2 +- docs/zh_CN/security/flash-encryption.rst | 3 +++ docs/zh_CN/security/secure-boot-v2.rst | 2 +- .../security-features-enablement-workflows.rst | 10 +++++++--- docs/zh_CN/security/security.rst | 2 +- 7 files changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/en/security/flash-encryption.rst b/docs/en/security/flash-encryption.rst index efe90e745c..4c9a954296 100644 --- a/docs/en/security/flash-encryption.rst +++ b/docs/en/security/flash-encryption.rst @@ -510,6 +510,9 @@ If all partitions needs to be updated in encrypted format, run: idf.py encrypted-flash monitor +.. note:: + + The above operations only apply if the `DIS_DOWNLOAD_MANUAL_ENCRYPT` eFuse bit has not been programmed. If this eFuse bit has been programmed, you need to flash the encrypted firmware image instead. .. _flash-enc-release-mode: diff --git a/docs/en/security/security-features-enablement-workflows.rst b/docs/en/security/security-features-enablement-workflows.rst index 51d587cfb1..ecfdfd46d1 100644 --- a/docs/en/security/security-features-enablement-workflows.rst +++ b/docs/en/security/security-features-enablement-workflows.rst @@ -318,6 +318,10 @@ In this case all the eFuses related to Flash Encryption are written with help of espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address 0x10000 --output my-app-enc.bin build/my-app.bin + .. note:: + + If secure boot is also enabled, please perform the secure boot firmware signing first, and then carry out the above encryption operation. + In the above command, the offsets are used for a sample firmware, and the actual offset for your firmware can be obtained by checking the partition table entry or by running `idf.py partition-table`. Please note that not all the binaries need to be encrypted, the encryption applies only to those generated from the partitions which are marked as ``encrypted`` in the partition table definition file. Other binaries are flashed unencrypted, i.e., as a plain output of the build process. The above files can then be flashed to their respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, see the output printed when ``idf.py build`` succeeds. @@ -685,7 +689,7 @@ The details about NVS encryption and related schemes can be found at :doc:`NVS E * CSV file name - In this case, ``sample_singlepage_blob.csv`` is the CSV file which contains the NVS data. Please replace this with the file you wish to choose. - * NVS partition offset - This is the offset at which that NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The offset of your NVS partition can be found by executing ``idf.py partition-table`` in the projtect directory. Please update the sample value of ``0x3000`` in the above-provided command to the correct offset. + * NVS partition size - This is the size at which that NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The size of your NVS partition can be found by executing ``idf.py partition-table`` in the projtect directory. Please update the sample value of ``0x3000`` in the above-provided command to the correct size. 4. Configure the project @@ -734,7 +738,7 @@ In this case we generate NVS Encryption keys on a host. This key is then flashed * CSV file name - In this case `sample_singlepage_blob.csv` is the CSV file which contains the NVS data. Please replace it with the file you wish to choose. - * NVS partition offset - This is the offset at which the NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The offset of your NVS partition can be found by executing ``idf.py partition-table`` in the projtect directory. Please update the sample value of ``0x3000`` in the above-provided command to the correct offset. + * NVS partition size - This is the size at which the NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The size of your NVS partition can be found by executing ``idf.py partition-table`` in the projtect directory. Please update the sample value of ``0x3000`` in the above-provided command to the correct size. 3. Configure the project @@ -745,4 +749,4 @@ In this case we generate NVS Encryption keys on a host. This key is then flashed The NVS partition (``nvs_encr_partition.bin``) and NVS encryption key (``nvs_encr_key.bin``) can then be flashed to their respective offset using ``esptool.py``. To see all of the command line options recommended for ``esptool.py``, check the output print when ``idf.py build`` succeeds. - If Flash Encryption is enabled for the chip, then please encrypt the partition first before flashing. You may refer the flashing related steps of `Flash Encryption workflow `_. + If Flash Encryption is enabled for the chip, then please encrypt the NVS key partition first before flashing. You may refer the flashing related steps of `Flash Encryption workflow `_. diff --git a/docs/en/security/security.rst b/docs/en/security/security.rst index cb3c1a8667..0de2c2cace 100644 --- a/docs/en/security/security.rst +++ b/docs/en/security/security.rst @@ -75,7 +75,7 @@ Please refer to :doc:`flash-encryption` for detailed information about this feat Flash Encryption Best Practices ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* It is recommended to use flash Encryption release mode for the production use-cases. +* It is recommended to use :ref:`flash-enc-release-mode` for the production use-cases. * It is recommended to have a unique flash encryption key per device. * Enable :ref:`secure_boot-guide` as an extra layer of protection, and to prevent an attacker from selectively corrupting any part of the flash before boot. diff --git a/docs/zh_CN/security/flash-encryption.rst b/docs/zh_CN/security/flash-encryption.rst index fb57142778..8c16f0b6d3 100644 --- a/docs/zh_CN/security/flash-encryption.rst +++ b/docs/zh_CN/security/flash-encryption.rst @@ -510,6 +510,9 @@ flash 加密设置 idf.py encrypted-flash monitor +.. note:: + + 上述操作仅适用于 DIS_DOWNLOAD_MANUAL_ENCRYPT eFuse 位未被烧录的情况。如果该 eFuse 位已被烧录,则需要烧录加密后的密文镜像。 .. _flash-enc-release-mode: diff --git a/docs/zh_CN/security/secure-boot-v2.rst b/docs/zh_CN/security/secure-boot-v2.rst index bf21e1897c..bf5fb86412 100644 --- a/docs/zh_CN/security/secure-boot-v2.rst +++ b/docs/zh_CN/security/secure-boot-v2.rst @@ -137,7 +137,7 @@ 5. 引导加载程序验证应用程序镜像的签名块,请参阅 :ref:`verify_signature-block`。如果验证失败,启动过程将中止。 -6. 引导加载程序使用原始镜像数据、相应的签名块以及 eFuse 验证引导加载程序镜像,请参阅 :ref:`verify_image`。如果验证失败,启动过程将中止。如果验证失败,但发现了其他应用程序镜像,引导加载程序将使用步骤 5 到 7 验证另一个镜像。该过程将重复,直至找到有效镜像,或所有镜像验证完毕。 +6. 引导加载程序使用原始镜像数据、相应的签名块以及 eFuse 验证应用程序镜像,请参阅 :ref:`verify_image`。如果验证失败,启动过程将中止。如果验证失败,但发现了其他应用程序镜像,引导加载程序将使用步骤 5 到 7 验证另一个镜像。该过程将重复,直至找到有效镜像,或所有镜像验证完毕。 7. 引导加载程序执行经验证的应用程序镜像。 diff --git a/docs/zh_CN/security/security-features-enablement-workflows.rst b/docs/zh_CN/security/security-features-enablement-workflows.rst index d8e5e7dc01..0312b5517e 100644 --- a/docs/zh_CN/security/security-features-enablement-workflows.rst +++ b/docs/zh_CN/security/security-features-enablement-workflows.rst @@ -318,6 +318,10 @@ espsecure.py encrypt_flash_data {IDF_TARGET_FLASH_ENC_ARGS} --keyfile my_flash_encryption_key.bin --address 0x10000 --output my-app-enc.bin build/my-app.bin + .. note:: + + 如同时开启了 secure boot,请先 secure boot 签名固件后再做上述加密操作。 + 上述命令中的偏移量仅适用于示例固件,请通过检查分区表条目或运行 `idf.py partition-table` 来获取你固件的实际偏移量。请注意,不需要加密所有二进制文件,只需加密在分区表定义文件中带有 ``encrypted`` 标记的文件,其他二进制文件只作为构建过程的普通输出进行烧录。 使用 ``esptool.py`` 可以将上述文件烧写到各自的偏移地址。要查看所有推荐的 ``esptool.py`` 命令行选项,请查阅 ``idf.py build`` 构建成功后打印的输出。 @@ -685,7 +689,7 @@ Secure Boot v2 指南 * CSV 文件名 - 此命令中,``sample_singlepage_blob.csv`` 是指包含 NVS 数据的 CSV 文件,请将其替换为所选择的文件。 - * NVS 分区偏移量 - 这是 {IDF_TARGET_NAME} flash 中存储 NVS 分区的偏移地址。通过在项目目录下执行 ``idf.py partition-table`` 命令,可以找到 NVS 分区偏移地址。请将上述命令中的示例值 ``0x3000`` 调整为正确的偏移量。 + * NVS 分区大小 - 这是 {IDF_TARGET_NAME} flash 中存储 NVS 分区的大小。通过在项目目录下执行 ``idf.py partition-table`` 命令,可以找到 NVS 分区大小。请将上述命令中的示例值 ``0x3000`` 调整为正确的大小。 4. 配置项目 @@ -734,7 +738,7 @@ Secure Boot v2 指南 * CSV 文件名 - 上述命名中的 `sample_singlepage_blob.csv` 是指包含 NVS 数据的 CSV 文件,请将其替换为所选文件。 - * NVS 分区偏移量 - 这是 NVS 分区在 {IDF_TARGET_NAME} 的 flash 中存储时的偏移地址。在项目目录中执行 ``idf.py partition-table`` 命令,可以找到 NVS 分区的偏移量。请将上述命令中的示例值 ``0x3000`` 替换为正确的偏移量。 + * NVS 分区大小 - 这是 NVS 分区在 {IDF_TARGET_NAME} 的 flash 中存储时的偏移大小。在项目目录中执行 ``idf.py partition-table`` 命令,可以找到 NVS 分区的大小。请将上述命令中的示例值 ``0x3000`` 替换为正确的大小。 3. 配置项目 @@ -745,4 +749,4 @@ Secure Boot v2 指南 使用 ``esptool.py`` 命令,将 NVS 分区 (``nvs_encr_partition.bin``) 和 NVS 加密密钥 (``nvs_encr_key.bin``) 烧录到各自的偏移地址。通过 ``idf.py build`` 成功后打印的输出,可查看所有推荐的 ``esptool.py`` 命令行选项。 - 若芯片启用了 flash 加密,请在烧录之前先加密分区。详情请参阅 `flash 加密工作流程 `_ 中与烧录相关的步骤。 + 若芯片启用了 flash 加密,请在烧录之前先加密 NVS 加密秘钥分区。详情请参阅 `flash 加密工作流程 `_ 中与烧录相关的步骤。 diff --git a/docs/zh_CN/security/security.rst b/docs/zh_CN/security/security.rst index 9f1f171dbe..19b3d504d6 100644 --- a/docs/zh_CN/security/security.rst +++ b/docs/zh_CN/security/security.rst @@ -75,7 +75,7 @@ flash 加密功能可以加密外部 flash 中的内容,从而保护存储在 flash 加密最佳实践 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* 建议在生产环境中使用 flash 加密的量产模式。 +* 建议在生产环境中使用 flash 加密的 :ref:`flash-enc-release-mode`。 * 建议为每个设备生成唯一的 flash 加密密钥。 * 启用 :ref:`secure_boot-guide` 作为额外保护层,防止 flash 在启动前遭受恶意攻击。 From 57b5376c65893ffb74473dfdaa3816b45a2bfef9 Mon Sep 17 00:00:00 2001 From: Zheng Zhong Date: Mon, 22 Sep 2025 09:59:54 +0000 Subject: [PATCH 023/156] fix : apply the suggestion from doc team --- docs/en/security/flash-encryption.rst | 2 +- docs/en/security/security-features-enablement-workflows.rst | 2 +- docs/zh_CN/security/flash-encryption.rst | 2 +- .../zh_CN/security/security-features-enablement-workflows.rst | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/en/security/flash-encryption.rst b/docs/en/security/flash-encryption.rst index 4c9a954296..e7cd221d06 100644 --- a/docs/en/security/flash-encryption.rst +++ b/docs/en/security/flash-encryption.rst @@ -512,7 +512,7 @@ If all partitions needs to be updated in encrypted format, run: .. note:: - The above operations only apply if the `DIS_DOWNLOAD_MANUAL_ENCRYPT` eFuse bit has not been programmed. If this eFuse bit has been programmed, you need to flash the encrypted firmware image instead. + The above operations are only applicable when the ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` eFuse bit has not been programmed. If this eFuse bit has been programmed, you must flash the pre-encrypted ciphertext image instead. .. _flash-enc-release-mode: diff --git a/docs/en/security/security-features-enablement-workflows.rst b/docs/en/security/security-features-enablement-workflows.rst index ecfdfd46d1..97df6ff24b 100644 --- a/docs/en/security/security-features-enablement-workflows.rst +++ b/docs/en/security/security-features-enablement-workflows.rst @@ -320,7 +320,7 @@ In this case all the eFuses related to Flash Encryption are written with help of .. note:: - If secure boot is also enabled, please perform the secure boot firmware signing first, and then carry out the above encryption operation. + If secure boot is enabled, perform secure boot signing of the firmware before carrying out the above encryption operation. In the above command, the offsets are used for a sample firmware, and the actual offset for your firmware can be obtained by checking the partition table entry or by running `idf.py partition-table`. Please note that not all the binaries need to be encrypted, the encryption applies only to those generated from the partitions which are marked as ``encrypted`` in the partition table definition file. Other binaries are flashed unencrypted, i.e., as a plain output of the build process. diff --git a/docs/zh_CN/security/flash-encryption.rst b/docs/zh_CN/security/flash-encryption.rst index 8c16f0b6d3..57f68eaba5 100644 --- a/docs/zh_CN/security/flash-encryption.rst +++ b/docs/zh_CN/security/flash-encryption.rst @@ -512,7 +512,7 @@ flash 加密设置 .. note:: - 上述操作仅适用于 DIS_DOWNLOAD_MANUAL_ENCRYPT eFuse 位未被烧录的情况。如果该 eFuse 位已被烧录,则需要烧录加密后的密文镜像。 + 上述操作仅适用于 ``DIS_DOWNLOAD_MANUAL_ENCRYPT`` eFuse 位未被烧录的情况。如果该 eFuse 位已被烧录,则需要烧录加密后的密文镜像。 .. _flash-enc-release-mode: diff --git a/docs/zh_CN/security/security-features-enablement-workflows.rst b/docs/zh_CN/security/security-features-enablement-workflows.rst index 0312b5517e..71a98b9e16 100644 --- a/docs/zh_CN/security/security-features-enablement-workflows.rst +++ b/docs/zh_CN/security/security-features-enablement-workflows.rst @@ -320,7 +320,7 @@ .. note:: - 如同时开启了 secure boot,请先 secure boot 签名固件后再做上述加密操作。 + 如果同时启用了安全启动功能,请先对固件进行安全启动签名,再执行上述加密操作。 上述命令中的偏移量仅适用于示例固件,请通过检查分区表条目或运行 `idf.py partition-table` 来获取你固件的实际偏移量。请注意,不需要加密所有二进制文件,只需加密在分区表定义文件中带有 ``encrypted`` 标记的文件,其他二进制文件只作为构建过程的普通输出进行烧录。 @@ -749,4 +749,4 @@ Secure Boot v2 指南 使用 ``esptool.py`` 命令,将 NVS 分区 (``nvs_encr_partition.bin``) 和 NVS 加密密钥 (``nvs_encr_key.bin``) 烧录到各自的偏移地址。通过 ``idf.py build`` 成功后打印的输出,可查看所有推荐的 ``esptool.py`` 命令行选项。 - 若芯片启用了 flash 加密,请在烧录之前先加密 NVS 加密秘钥分区。详情请参阅 `flash 加密工作流程 `_ 中与烧录相关的步骤。 + 若芯片启用了 flash 加密,请在烧录前先对 NVS 加密密钥分区进行加密。详情请参阅 `flash 加密工作流程 `_ 中与烧录相关的步骤。 From 79bb3ff3c69228879a35ccf3423f1dd4a37dd46d Mon Sep 17 00:00:00 2001 From: Zhang Shuxian Date: Thu, 27 Nov 2025 11:12:45 +0800 Subject: [PATCH 024/156] docs: implement comments --- docs/en/security/security-features-enablement-workflows.rst | 4 ++-- .../zh_CN/security/security-features-enablement-workflows.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/en/security/security-features-enablement-workflows.rst b/docs/en/security/security-features-enablement-workflows.rst index 97df6ff24b..92c605a47a 100644 --- a/docs/en/security/security-features-enablement-workflows.rst +++ b/docs/en/security/security-features-enablement-workflows.rst @@ -689,7 +689,7 @@ The details about NVS encryption and related schemes can be found at :doc:`NVS E * CSV file name - In this case, ``sample_singlepage_blob.csv`` is the CSV file which contains the NVS data. Please replace this with the file you wish to choose. - * NVS partition size - This is the size at which that NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The size of your NVS partition can be found by executing ``idf.py partition-table`` in the projtect directory. Please update the sample value of ``0x3000`` in the above-provided command to the correct size. + * NVS partition size - This is the size of the NVS partition in bytes. Please update the sample value of ``0x3000`` in the above-provided command to the correct size of your NVS partition. 4. Configure the project @@ -738,7 +738,7 @@ In this case we generate NVS Encryption keys on a host. This key is then flashed * CSV file name - In this case `sample_singlepage_blob.csv` is the CSV file which contains the NVS data. Please replace it with the file you wish to choose. - * NVS partition size - This is the size at which the NVS partition shall be stored in the flash of {IDF_TARGET_NAME}. The size of your NVS partition can be found by executing ``idf.py partition-table`` in the projtect directory. Please update the sample value of ``0x3000`` in the above-provided command to the correct size. + * NVS partition size - This is the size of the NVS partition in bytes. Please update the sample value of ``0x3000`` in the above-provided command to the correct size of your NVS partition. 3. Configure the project diff --git a/docs/zh_CN/security/security-features-enablement-workflows.rst b/docs/zh_CN/security/security-features-enablement-workflows.rst index 71a98b9e16..8350178191 100644 --- a/docs/zh_CN/security/security-features-enablement-workflows.rst +++ b/docs/zh_CN/security/security-features-enablement-workflows.rst @@ -689,7 +689,7 @@ Secure Boot v2 指南 * CSV 文件名 - 此命令中,``sample_singlepage_blob.csv`` 是指包含 NVS 数据的 CSV 文件,请将其替换为所选择的文件。 - * NVS 分区大小 - 这是 {IDF_TARGET_NAME} flash 中存储 NVS 分区的大小。通过在项目目录下执行 ``idf.py partition-table`` 命令,可以找到 NVS 分区大小。请将上述命令中的示例值 ``0x3000`` 调整为正确的大小。 + * NVS 分区大小 - 这是 NVS 分区的大小(以字节为单位)。请将上述命令中的示例值 ``0x3000`` 更新为你实际 NVS 分区的正确大小。 4. 配置项目 @@ -738,7 +738,7 @@ Secure Boot v2 指南 * CSV 文件名 - 上述命名中的 `sample_singlepage_blob.csv` 是指包含 NVS 数据的 CSV 文件,请将其替换为所选文件。 - * NVS 分区大小 - 这是 NVS 分区在 {IDF_TARGET_NAME} 的 flash 中存储时的偏移大小。在项目目录中执行 ``idf.py partition-table`` 命令,可以找到 NVS 分区的大小。请将上述命令中的示例值 ``0x3000`` 替换为正确的大小。 + * NVS 分区大小 - 这是 NVS 分区的大小(以字节为单位)。请将上述命令中的示例值 ``0x3000`` 更新为你实际 NVS 分区的正确大小。 3. 配置项目 From 2d47ed3c68748a7b07ef14b350fc0fafd87e9998 Mon Sep 17 00:00:00 2001 From: Marek Fiala Date: Wed, 19 Nov 2025 15:53:25 +0100 Subject: [PATCH 025/156] refactor(tools): test_idf_tools.py ruff changes --- tools/test_idf_tools/test_idf_tools.py | 150 +++++++++++-------------- 1 file changed, 65 insertions(+), 85 deletions(-) diff --git a/tools/test_idf_tools/test_idf_tools.py b/tools/test_idf_tools/test_idf_tools.py index 2df939cf6a..239a2e1739 100755 --- a/tools/test_idf_tools/test_idf_tools.py +++ b/tools/test_idf_tools/test_idf_tools.py @@ -116,7 +116,7 @@ XTENSA_ELF_ARCHIVE_PATTERN = ( class TestUsageBase(unittest.TestCase): @classmethod def setUpClass(cls): - with open(os.path.join(os.getenv('IDF_PATH'), 'tools/tools.json'), 'r') as json_file: + with open(os.path.join(os.getenv('IDF_PATH'), 'tools/tools.json')) as json_file: tools_dict = json.load(json_file) cls.tools_dict = tools_dict @@ -142,7 +142,7 @@ class TestUsageBase(unittest.TestCase): cls.temp_tools_dir = tempfile.mkdtemp(prefix='idf_tools_tmp') - print('Using IDF_TOOLS_PATH={}'.format(cls.temp_tools_dir)) + print(f'Using IDF_TOOLS_PATH={cls.temp_tools_dir}') os.environ['IDF_TOOLS_PATH'] = cls.temp_tools_dir cls.idf_env_json = os.path.join(cls.temp_tools_dir, 'idf-env.json') @@ -163,13 +163,13 @@ class TestUsageBase(unittest.TestCase): def assert_tool_installed(self, output, tool, tool_version, tool_archive_name=None): if tool_archive_name is None: tool_archive_name = tool - self.assertIn('Installing %s@' % tool + tool_version, output) + self.assertIn(f'Installing {tool}@{tool_version}', output) self.assertRegex(output, re.compile(rf'Downloading \S+{tool_archive_name}')) def assert_tool_not_installed(self, output, tool, tool_version, tool_archive_name=None): if tool_archive_name is None: tool_archive_name = tool - self.assertNotIn('Installing %s@' % tool + tool_version, output) + self.assertNotIn(f'Installing {tool}@{tool_version}', output) self.assertNotRegex(output, re.compile(rf'Downloading \S+{tool_archive_name}')) def run_idf_tools_with_action(self, action): @@ -278,8 +278,8 @@ class TestUsage(TestUsageBase): 'export IDF_DEACTIVATE_FILE_PATH=', output, 'No IDF_DEACTIVATE_FILE_PATH exported into environment' ) deactivate_file = re.findall(r'(?:IDF_DEACTIVATE_FILE_PATH=")(.*)(?:")', output)[0] - self.assertTrue(os.path.isfile(deactivate_file), 'File {} was not found. '.format(deactivate_file)) - self.assertNotEqual(os.stat(self.idf_env_json).st_size, 0, 'File {} is empty. '.format(deactivate_file)) + self.assertTrue(os.path.isfile(deactivate_file), f'File {deactivate_file} was not found. ') + self.assertNotEqual(os.stat(self.idf_env_json).st_size, 0, f'File {deactivate_file} is empty. ') def test_export_recommended_version(self): always_install_and_recommended_tools = [] @@ -369,14 +369,14 @@ class TestUsage(TestUsageBase): class TestUsageUnix(TestUsage): def test_usage_basic(self): output = self.run_idf_tools_with_action(['list']) - self.assertIn('* %s:' % ESP32ULP, output) - self.assertIn('- %s (recommended)' % ESP32ULP_VERSION, output) - self.assertIn('* %s:' % OPENOCD, output) - self.assertIn('- %s (recommended)' % OPENOCD_VERSION, output) - self.assertIn('* %s:' % RISCV_ELF, output) - self.assertIn('- %s (recommended)' % RISCV_ELF_VERSION, output) - self.assertIn('* %s:' % XTENSA_ELF, output) - self.assertIn('- %s (recommended)' % XTENSA_ELF_VERSION, output) + self.assertIn(f'* {ESP32ULP}:', output) + self.assertIn(f'- {ESP32ULP_VERSION} (recommended)', output) + self.assertIn(f'* {OPENOCD}:', output) + self.assertIn(f'- {OPENOCD_VERSION} (recommended)', output) + self.assertIn(f'* {RISCV_ELF}:', output) + self.assertIn(f'- {RISCV_ELF_VERSION} (recommended)', output) + self.assertIn(f'* {XTENSA_ELF}:', output) + self.assertIn(f'- {XTENSA_ELF_VERSION} (recommended)', output) required_tools_installed = 7 output = self.run_idf_tools_with_action(['install']) @@ -403,23 +403,19 @@ class TestUsageUnix(TestUsage): self.assertIn('version installed in tools directory: ' + tool_version, output) output = self.run_idf_tools_with_action(['export']) - self.assertIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf/bin' % (self.temp_tools_dir, ESP32ULP_VERSION), output) + self.assertIn(f'{self.temp_tools_dir}/tools/esp32ulp-elf/{ESP32ULP_VERSION}/esp32ulp-elf/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/xtensa-esp-elf/{XTENSA_ELF_VERSION}/xtensa-esp-elf/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/openocd-esp32/{OPENOCD_VERSION}/openocd-esp32/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/riscv32-esp-elf/{RISCV_ELF_VERSION}/riscv32-esp-elf/bin', output) self.assertIn( - '%s/tools/xtensa-esp-elf/%s/xtensa-esp-elf/bin' % (self.temp_tools_dir, XTENSA_ELF_VERSION), output - ) - self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % (self.temp_tools_dir, OPENOCD_VERSION), output) - self.assertIn( - '%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % (self.temp_tools_dir, RISCV_ELF_VERSION), output - ) - self.assertIn( - '%s/tools/xtensa-esp-elf-gdb/%s/xtensa-esp-elf-gdb/bin' % (self.temp_tools_dir, XTENSA_ESP_GDB_VERSION), + f'{self.temp_tools_dir}/tools/xtensa-esp-elf-gdb/{XTENSA_ESP_GDB_VERSION}/xtensa-esp-elf-gdb/bin', output, ) self.assertIn( - '%s/tools/riscv32-esp-elf-gdb/%s/riscv32-esp-elf-gdb/bin' % (self.temp_tools_dir, RISCV_ESP_GDB_VERSION), + f'{self.temp_tools_dir}/tools/riscv32-esp-elf-gdb/{RISCV_ESP_GDB_VERSION}/riscv32-esp-elf-gdb/bin', output, ) - self.assertIn('%s/tools/esp-rom-elfs/%s/' % (self.temp_tools_dir, ESP_ROM_ELFS_VERSION), output) + self.assertIn(f'{self.temp_tools_dir}/tools/esp-rom-elfs/{ESP_ROM_ELFS_VERSION}/', output) output = self.run_idf_tools_with_action(['list', '--outdated']) self.assertEqual('', output) @@ -470,23 +466,19 @@ class TestUsageUnix(TestUsage): self.assertIn('version installed in tools directory: ' + tool_version, output) output = self.run_idf_tools_with_action(['export']) - self.assertIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf/bin' % (self.temp_tools_dir, ESP32ULP_VERSION), output) + self.assertIn(f'{self.temp_tools_dir}/tools/esp32ulp-elf/{ESP32ULP_VERSION}/esp32ulp-elf/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/xtensa-esp-elf/{XTENSA_ELF_VERSION}/xtensa-esp-elf/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/openocd-esp32/{OPENOCD_VERSION}/openocd-esp32/bin', output) self.assertIn( - '%s/tools/xtensa-esp-elf/%s/xtensa-esp-elf/bin' % (self.temp_tools_dir, XTENSA_ELF_VERSION), output - ) - self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % (self.temp_tools_dir, OPENOCD_VERSION), output) - self.assertIn( - '%s/tools/xtensa-esp-elf-gdb/%s/xtensa-esp-elf-gdb/bin' % (self.temp_tools_dir, XTENSA_ESP_GDB_VERSION), + f'{self.temp_tools_dir}/tools/xtensa-esp-elf-gdb/{XTENSA_ESP_GDB_VERSION}/xtensa-esp-elf-gdb/bin', output, ) + self.assertNotIn(f'{self.temp_tools_dir}/tools/riscv32-esp-elf/{RISCV_ELF_VERSION}/riscv32-esp-elf/bin', output) self.assertNotIn( - '%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % (self.temp_tools_dir, RISCV_ELF_VERSION), output - ) - self.assertNotIn( - '%s/tools/riscv32-esp-elf-gdb/%s/riscv32-esp-elf-gdb/bin' % (self.temp_tools_dir, RISCV_ESP_GDB_VERSION), + f'{self.temp_tools_dir}/tools/riscv32-esp-elf-gdb/{RISCV_ESP_GDB_VERSION}/riscv32-esp-elf-gdb/bin', output, ) - self.assertIn('%s/tools/esp-rom-elfs/%s/' % (self.temp_tools_dir, ESP_ROM_ELFS_VERSION), output) + self.assertIn(f'{self.temp_tools_dir}/tools/esp-rom-elfs/{ESP_ROM_ELFS_VERSION}/', output) def test_tools_for_esp32c3(self): required_tools_installed = 4 @@ -506,19 +498,15 @@ class TestUsageUnix(TestUsage): self.assertIn('version installed in tools directory: ' + tool_version, output) output = self.run_idf_tools_with_action(['export']) - self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % (self.temp_tools_dir, OPENOCD_VERSION), output) - self.assertIn( - '%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % (self.temp_tools_dir, RISCV_ELF_VERSION), output - ) - self.assertNotIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf/bin' % (self.temp_tools_dir, ESP32ULP_VERSION), output) + self.assertIn(f'{self.temp_tools_dir}/tools/openocd-esp32/{OPENOCD_VERSION}/openocd-esp32/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/riscv32-esp-elf/{RISCV_ELF_VERSION}/riscv32-esp-elf/bin', output) + self.assertNotIn(f'{self.temp_tools_dir}/tools/esp32ulp-elf/{ESP32ULP_VERSION}/esp32ulp-elf/bin', output) + self.assertNotIn(f'{self.temp_tools_dir}/tools/xtensa-esp-elf/{XTENSA_ELF_VERSION}/xtensa-esp-elf/bin', output) self.assertNotIn( - '%s/tools/xtensa-esp-elf/%s/xtensa-esp-elf/bin' % (self.temp_tools_dir, XTENSA_ELF_VERSION), output - ) - self.assertNotIn( - '%s/tools/xtensa-esp-elf-gdb/%s/xtensa-esp-elf-gdb/bin' % (self.temp_tools_dir, XTENSA_ESP_GDB_VERSION), + f'{self.temp_tools_dir}/tools/xtensa-esp-elf-gdb/{XTENSA_ESP_GDB_VERSION}/xtensa-esp-elf-gdb/bin', output, ) - self.assertIn('%s/tools/esp-rom-elfs/%s/' % (self.temp_tools_dir, ESP_ROM_ELFS_VERSION), output) + self.assertIn(f'{self.temp_tools_dir}/tools/esp-rom-elfs/{ESP_ROM_ELFS_VERSION}/', output) def test_tools_for_esp32s2(self): required_tools_installed = 6 @@ -538,23 +526,19 @@ class TestUsageUnix(TestUsage): self.assertIn('version installed in tools directory: ' + tool_version, output) output = self.run_idf_tools_with_action(['export']) + self.assertIn(f'{self.temp_tools_dir}/tools/xtensa-esp-elf/{XTENSA_ELF_VERSION}/xtensa-esp-elf/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/openocd-esp32/{OPENOCD_VERSION}/openocd-esp32/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/esp32ulp-elf/{ESP32ULP_VERSION}/esp32ulp-elf/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/riscv32-esp-elf/{RISCV_ELF_VERSION}/riscv32-esp-elf/bin', output) self.assertIn( - '%s/tools/xtensa-esp-elf/%s/xtensa-esp-elf/bin' % (self.temp_tools_dir, XTENSA_ELF_VERSION), output - ) - self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % (self.temp_tools_dir, OPENOCD_VERSION), output) - self.assertIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf/bin' % (self.temp_tools_dir, ESP32ULP_VERSION), output) - self.assertIn( - '%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % (self.temp_tools_dir, RISCV_ELF_VERSION), output - ) - self.assertIn( - '%s/tools/xtensa-esp-elf-gdb/%s/xtensa-esp-elf-gdb/bin' % (self.temp_tools_dir, XTENSA_ESP_GDB_VERSION), + f'{self.temp_tools_dir}/tools/xtensa-esp-elf-gdb/{XTENSA_ESP_GDB_VERSION}/xtensa-esp-elf-gdb/bin', output, ) self.assertNotIn( - '%s/tools/riscv32-esp-elf-gdb/%s/riscv32-esp-elf-gdb/bin' % (self.temp_tools_dir, RISCV_ESP_GDB_VERSION), + f'{self.temp_tools_dir}/tools/riscv32-esp-elf-gdb/{RISCV_ESP_GDB_VERSION}/riscv32-esp-elf-gdb/bin', output, ) - self.assertIn('%s/tools/esp-rom-elfs/%s/' % (self.temp_tools_dir, ESP_ROM_ELFS_VERSION), output) + self.assertIn(f'{self.temp_tools_dir}/tools/esp-rom-elfs/{ESP_ROM_ELFS_VERSION}/', output) def test_tools_for_esp32s3(self): required_tools_installed = 6 @@ -580,23 +564,19 @@ class TestUsageUnix(TestUsage): self.assertIn('version installed in tools directory: ' + tool_version, output) output = self.run_idf_tools_with_action(['export']) - self.assertIn('%s/tools/openocd-esp32/%s/openocd-esp32/bin' % (self.temp_tools_dir, OPENOCD_VERSION), output) + self.assertIn(f'{self.temp_tools_dir}/tools/openocd-esp32/{OPENOCD_VERSION}/openocd-esp32/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/xtensa-esp-elf/{XTENSA_ELF_VERSION}/xtensa-esp-elf/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/esp32ulp-elf/{ESP32ULP_VERSION}/esp32ulp-elf/bin', output) + self.assertIn(f'{self.temp_tools_dir}/tools/riscv32-esp-elf/{RISCV_ELF_VERSION}/riscv32-esp-elf/bin', output) self.assertIn( - '%s/tools/xtensa-esp-elf/%s/xtensa-esp-elf/bin' % (self.temp_tools_dir, XTENSA_ELF_VERSION), output - ) - self.assertIn('%s/tools/esp32ulp-elf/%s/esp32ulp-elf/bin' % (self.temp_tools_dir, ESP32ULP_VERSION), output) - self.assertIn( - '%s/tools/riscv32-esp-elf/%s/riscv32-esp-elf/bin' % (self.temp_tools_dir, RISCV_ELF_VERSION), output - ) - self.assertIn( - '%s/tools/xtensa-esp-elf-gdb/%s/xtensa-esp-elf-gdb/bin' % (self.temp_tools_dir, XTENSA_ESP_GDB_VERSION), + f'{self.temp_tools_dir}/tools/xtensa-esp-elf-gdb/{XTENSA_ESP_GDB_VERSION}/xtensa-esp-elf-gdb/bin', output, ) self.assertNotIn( - '%s/tools/riscv32-esp-elf-gdb/%s/riscv32-esp-elf-gdb/bin' % (self.temp_tools_dir, RISCV_ESP_GDB_VERSION), + f'{self.temp_tools_dir}/tools/riscv32-esp-elf-gdb/{RISCV_ESP_GDB_VERSION}/riscv32-esp-elf-gdb/bin', output, ) - self.assertIn('%s/tools/esp-rom-elfs/%s/' % (self.temp_tools_dir, ESP_ROM_ELFS_VERSION), output) + self.assertIn(f'{self.temp_tools_dir}/tools/esp-rom-elfs/{ESP_ROM_ELFS_VERSION}/', output) def test_tools_for_esp32p4(self): required_tools_installed = 4 @@ -664,14 +644,14 @@ class TestUsageUnix(TestUsage): class TestUsageWin(TestUsage): def test_usage_basic_win(self): output = self.run_idf_tools_with_action(['list']) - self.assertIn('* %s:' % ESP32ULP, output) - self.assertIn('- %s (recommended)' % ESP32ULP_VERSION, output) - self.assertIn('* %s:' % OPENOCD, output) - self.assertIn('- %s (recommended)' % OPENOCD_VERSION, output) - self.assertIn('* %s:' % RISCV_ELF, output) - self.assertIn('- %s (recommended)' % RISCV_ELF_VERSION, output) - self.assertIn('* %s:' % XTENSA_ELF, output) - self.assertIn('- %s (recommended)' % XTENSA_ELF_VERSION, output) + self.assertIn(f'* {ESP32ULP}:', output) + self.assertIn(f'- {ESP32ULP_VERSION} (recommended)', output) + self.assertIn(f'* {OPENOCD}:', output) + self.assertIn(f'- {OPENOCD_VERSION} (recommended)', output) + self.assertIn(f'* {RISCV_ELF}:', output) + self.assertIn(f'- {RISCV_ELF_VERSION} (recommended)', output) + self.assertIn(f'* {XTENSA_ELF}:', output) + self.assertIn(f'- {XTENSA_ELF_VERSION} (recommended)', output) required_tools_installed = 12 output = self.run_idf_tools_with_action(['install']) @@ -1175,16 +1155,16 @@ class TestMaintainer(unittest.TestCase): def test_json_rewrite(self): idf_tools.main(['rewrite']) - with open(self.tools_old, 'r') as f: + with open(self.tools_old) as f: json_old = f.read() - with open(self.tools_new, 'r') as f: + with open(self.tools_new) as f: json_new = f.read() self.assertEqual(json_old, json_new, "Please check 'tools/tools.new.json' to find a cause!") def add_version_get_expected_json(self, addition_file, replace=False): - with open(self.tools_old, 'r') as f: + with open(self.tools_old) as f: expected_json = json.load(f) - with open(addition_file, 'r') as f: + with open(addition_file) as f: addition_json = json.load(f) for tool in expected_json['tools']: if tool['name'] == self.test_tool_name: @@ -1197,7 +1177,7 @@ class TestMaintainer(unittest.TestCase): def test_add_version_artifact_addition(self): filenames = [] - with open('add_version/artifact_input.json', 'r') as f: + with open('add_version/artifact_input.json') as f: add_tools_info = json.load(f) for tool in add_tools_info: filenames.append(tool['filename']) @@ -1218,7 +1198,7 @@ class TestMaintainer(unittest.TestCase): + filenames ) expected_json = self.add_version_get_expected_json('add_version/artifact_expected_addition.json') - with open(self.tools_new, 'r') as f1: + with open(self.tools_new) as f1: self.assertEqual(json.load(f1), expected_json, "Please check 'tools/tools.new.json' to find a cause!") def test_add_version_checksum_addition(self): @@ -1236,7 +1216,7 @@ class TestMaintainer(unittest.TestCase): ] ) expected_json = self.add_version_get_expected_json('add_version/checksum_expected_addition.json') - with open(self.tools_new, 'r') as f1: + with open(self.tools_new) as f1: self.assertEqual(json.load(f1), expected_json, "Please check 'tools/tools.new.json' to find a cause!") def test_add_version_checksum_with_override(self): @@ -1255,7 +1235,7 @@ class TestMaintainer(unittest.TestCase): ] ) expected_json = self.add_version_get_expected_json('add_version/checksum_expected_override.json', True) - with open(self.tools_new, 'r') as f1: + with open(self.tools_new) as f1: self.assertEqual(json.load(f1), expected_json, "Please check 'tools/tools.new.json' to find a cause!") @@ -1299,7 +1279,7 @@ class TestSystemDependencies(TestUsageBase): '\nINFO: System dependencies have been modified for TestSystemDependencies. ' 'Other tests may not work correctly' ) - super(TestSystemDependencies, cls).tearDownClass() + super().tearDownClass() def test_commands_when_nodeps(self): # Prerequisites From 69873c01ab17d9b70989e2999653ddd47cb35bb0 Mon Sep 17 00:00:00 2001 From: Marek Fiala Date: Wed, 19 Nov 2025 15:54:26 +0100 Subject: [PATCH 026/156] feat(tools): Updated ccache 4.11.2 -> 4.12.1 Closes https://github.com/espressif/esp-idf/issues/17756 --- tools/test_idf_tools/test_idf_tools.py | 12 ++++++------ tools/tools.json | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/test_idf_tools/test_idf_tools.py b/tools/test_idf_tools/test_idf_tools.py index 239a2e1739..6fd848a9ce 100755 --- a/tools/test_idf_tools/test_idf_tools.py +++ b/tools/test_idf_tools/test_idf_tools.py @@ -719,7 +719,7 @@ class TestUsageWin(TestUsage): self.assertIn(os.path.join(self.temp_tools_dir, 'tools', NINJA, NINJA_VERSION), output) self.assertIn(os.path.join(self.temp_tools_dir, 'tools', IDF_EXE, IDF_EXE_VERSION), output) self.assertIn( - os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.11.2-windows-x86_64'), output + os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.12.1-windows-x86_64'), output ) self.assertIn( os.path.join(self.temp_tools_dir, 'tools', DFU_UTIL, DFU_UTIL_VERSION, 'dfu-util-0.11-win64'), output @@ -823,7 +823,7 @@ class TestUsageWin(TestUsage): self.assertIn(os.path.join(self.temp_tools_dir, 'tools', NINJA, NINJA_VERSION), output) self.assertIn(os.path.join(self.temp_tools_dir, 'tools', IDF_EXE, IDF_EXE_VERSION), output) self.assertIn( - os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.11.2-windows-x86_64'), output + os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.12.1-windows-x86_64'), output ) self.assertNotIn( os.path.join(self.temp_tools_dir, 'tools', DFU_UTIL, DFU_UTIL_VERSION, 'dfu-util-0.11-win64'), output @@ -895,7 +895,7 @@ class TestUsageWin(TestUsage): self.assertIn(os.path.join(self.temp_tools_dir, 'tools', NINJA, NINJA_VERSION), output) self.assertIn(os.path.join(self.temp_tools_dir, 'tools', IDF_EXE, IDF_EXE_VERSION), output) self.assertIn( - os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.11.2-windows-x86_64'), output + os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.12.1-windows-x86_64'), output ) self.assertNotIn( os.path.join(self.temp_tools_dir, 'tools', DFU_UTIL, DFU_UTIL_VERSION, 'dfu-util-0.11-win64'), output @@ -973,7 +973,7 @@ class TestUsageWin(TestUsage): self.assertIn(os.path.join(self.temp_tools_dir, 'tools', NINJA, NINJA_VERSION), output) self.assertIn(os.path.join(self.temp_tools_dir, 'tools', IDF_EXE, IDF_EXE_VERSION), output) self.assertIn( - os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.11.2-windows-x86_64'), output + os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.12.1-windows-x86_64'), output ) self.assertIn( os.path.join(self.temp_tools_dir, 'tools', DFU_UTIL, DFU_UTIL_VERSION, 'dfu-util-0.11-win64'), output @@ -1053,7 +1053,7 @@ class TestUsageWin(TestUsage): self.assertIn(os.path.join(self.temp_tools_dir, 'tools', NINJA, NINJA_VERSION), output) self.assertIn(os.path.join(self.temp_tools_dir, 'tools', IDF_EXE, IDF_EXE_VERSION), output) self.assertIn( - os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.11.2-windows-x86_64'), output + os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.12.1-windows-x86_64'), output ) self.assertIn( os.path.join(self.temp_tools_dir, 'tools', DFU_UTIL, DFU_UTIL_VERSION, 'dfu-util-0.11-win64'), output @@ -1103,7 +1103,7 @@ class TestUsageWin(TestUsage): self.assertIn(os.path.join(self.temp_tools_dir, 'tools', NINJA, NINJA_VERSION), output) self.assertIn(os.path.join(self.temp_tools_dir, 'tools', IDF_EXE, IDF_EXE_VERSION), output) self.assertIn( - os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.11.2-windows-x86_64'), output + os.path.join(self.temp_tools_dir, 'tools', CCACHE, CCACHE_VERSION, 'ccache-4.12.1-windows-x86_64'), output ) self.assertNotIn( os.path.join(self.temp_tools_dir, 'tools', XTENSA_ELF, XTENSA_ELF_VERSION, XTENSA_ELF, 'bin'), output diff --git a/tools/tools.json b/tools/tools.json index cf94ce86e9..5f82060b24 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -826,7 +826,7 @@ "description": "Ccache (compiler cache)", "export_paths": [ [ - "ccache-4.11.2-windows-x86_64" + "ccache-4.12.1-windows-x86_64" ] ], "export_vars": { @@ -854,12 +854,12 @@ "version_regex": "ccache version ([0-9.]+)", "versions": [ { - "name": "4.11.2", + "name": "4.12.1", "status": "recommended", "win64": { - "sha256": "1f39f3ad5aae3fe915e99ad1302633bc8f6718e58fa7c0de2b0ba7e080f0f08c", - "size": 1642225, - "url": "https://github.com/ccache/ccache/releases/download/v4.11.2/ccache-4.11.2-windows-x86_64.zip" + "sha256": "98aea520d66905b8ba7a8e648a4cc0ca941d5e119d441f1e879a4a9045bf18f6", + "size": 1710234, + "url": "https://github.com/ccache/ccache/releases/download/v4.12.1/ccache-4.12.1-windows-x86_64.zip" } } ] From 047ea940bffbe1e756dcc9c8ab965a0036654ab0 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Thu, 24 Jul 2025 14:06:59 +0800 Subject: [PATCH 027/156] refactor(parlio_rx): refactor to support unaligned user payload buffer Closes https://github.com/espressif/esp-idf/issues/17581 --- .../include/driver/parlio_rx.h | 1 + components/esp_driver_parlio/linker.lf | 12 ++ components/esp_driver_parlio/src/parlio_rx.c | 146 +++++++++++------- components/esp_driver_parlio/src/parlio_tx.c | 2 +- .../test_apps/parlio/main/test_parlio_rx.c | 4 +- components/esp_hw_support/dma/esp_dma_utils.c | 87 ++++++----- components/esp_hw_support/dma/gdma_link.c | 32 ++-- .../dma/include/esp_private/gdma_link.h | 8 +- components/esp_lcd/rgb/esp_lcd_panel_rgb.c | 2 +- 9 files changed, 179 insertions(+), 115 deletions(-) diff --git a/components/esp_driver_parlio/include/driver/parlio_rx.h b/components/esp_driver_parlio/include/driver/parlio_rx.h index 9774d871b4..bb0ac5c0d0 100644 --- a/components/esp_driver_parlio/include/driver/parlio_rx.h +++ b/components/esp_driver_parlio/include/driver/parlio_rx.h @@ -22,6 +22,7 @@ extern "C" { typedef struct { size_t trans_queue_depth; /*!< Depth of internal transaction queue */ size_t max_recv_size; /*!< Maximum receive size in one transaction, in bytes. This decides the number of DMA nodes will be used for each transaction */ + size_t dma_burst_size; /*!< DMA burst size, in bytes */ size_t data_width; /*!< Parallel IO data width, can set to 1/2/4/8/..., but can't be greater than PARLIO_RX_UNIT_MAX_DATA_WIDTH */ parlio_clock_source_t clk_src; /*!< Parallel IO clock source */ uint32_t ext_clk_freq_hz; /*!< The external source clock frequency. Only be valid when select PARLIO_CLK_SRC_EXTERNAL as clock source */ diff --git a/components/esp_driver_parlio/linker.lf b/components/esp_driver_parlio/linker.lf index 76b5b7f0cf..3c61d44c7f 100644 --- a/components/esp_driver_parlio/linker.lf +++ b/components/esp_driver_parlio/linker.lf @@ -25,3 +25,15 @@ entries: if SOC_PARLIO_TX_SUPPORT_LOOP_TRANSMISSION = y: gdma_link: gdma_link_get_buffer (noflash) + if PARLIO_RX_ISR_HANDLER_IN_IRAM = y: + gdma_link: gdma_link_mount_buffers (noflash) + gdma_link: gdma_link_get_buffer (noflash) + gdma_link: gdma_link_get_length (noflash) + esp_dma_utils: esp_dma_split_rx_buffer_to_cache_aligned (noflash) + esp_dma_utils: esp_dma_merge_aligned_rx_buffers (noflash) + +[mapping:parlio_driver_soc_periph] +archive: libsoc.a +entries: + if PARLIO_RX_ISR_HANDLER_IN_IRAM = y: + parlio_periph: parlio_periph_signals (noflash) diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index aa6b2da262..cce214885e 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -26,10 +26,11 @@ */ typedef struct { parlio_rx_delimiter_handle_t delimiter; /*!< Delimiter of this transaction */ - void *payload; /*!< The payload of this transaction, will be mounted to DMA link list node */ - size_t size; /*!< The payload size in byte */ + dma_buffer_split_array_t aligned_payload; /*!< The aligned payload of this transaction, will be mounted to DMA link list node */ + size_t tot_trans_size; /*!< The total size of the transaction */ size_t recv_bytes; /*!< The received bytes of this transaction will be reset when all data filled in the infinite transaction */ + size_t alignment; /*!< The alignment of the payload buffer */ struct { uint32_t infinite : 1; /*!< Whether this is an infinite transaction */ uint32_t indirect_mount : 1; /*!< Whether the user payload mount to the link list node indirectly via an internal DMA buffer */ @@ -64,14 +65,17 @@ typedef struct parlio_rx_unit_t { /* DMA Resources */ gdma_channel_handle_t dma_chan; /*!< DMA channel */ size_t max_recv_size; /*!< Maximum receive size for a normal transaction */ + size_t dma_burst_size; /*!< DMA burst size, in bytes */ gdma_link_list_handle_t dma_link; /*!< DMA link list handle */ uint32_t node_num; /*!< The number of nodes in the DMA link list */ - size_t int_mem_align; /*!< Alignment for internal memory */ - size_t ext_mem_align; /*!< Alignment for external memory */ + size_t dma_mem_align; /*!< Alignment for DMA memory */ uint32_t curr_node_id; /*!< The index of the current node in the DMA link list */ void *usr_recv_buf; /*!< The point to the user's receiving buffer */ /* Infinite transaction specific */ void *dma_buf; /*!< Additional internal DMA buffer only for infinite transactions */ + /* Unaligned DMA buffer management */ + uint8_t *stash_buf[2]; /*!< The ping-pong stash buffer for unaligned DMA buffer */ + uint8_t stash_buf_idx; /*!< The index of the current stash buffer */ /* Callback */ parlio_rx_event_callbacks_t cbs; /*!< The group of callback function pointers */ @@ -111,7 +115,8 @@ typedef struct parlio_rx_delimiter_t { } flags; } parlio_rx_delimiter_t; -#define PRALIO_RX_MOUNT_SIZE_CALC(total_size, div, align) ((((total_size) / (align)) / (div)) * (align)) +#define PARLIO_RX_MOUNT_SIZE_CALC(total_size, div, align) ((((total_size) / (align)) / (div)) * (align)) +#define PARLIO_RX_CHECK_ISR(condition, err) if (!(condition)) { return err; } static portMUX_TYPE s_rx_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; @@ -125,48 +130,62 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli } portEXIT_CRITICAL_SAFE(&s_rx_spinlock); - uint32_t required_node_num = trans->size / PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; - uint32_t remain_node_num = trans->size % PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; + /* Calculate the number of nodes needed for the transaction */ + uint32_t body_node_num = trans->aligned_payload.buf.body.length / PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; + uint32_t body_remain_size = trans->aligned_payload.buf.body.length % PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; /* If there are still data remained, need one more node */ - required_node_num += remain_node_num ? 1 : 0; + body_node_num += body_remain_size ? 1 : 0; + + uint32_t head_node_num = trans->aligned_payload.buf.head.length ? 1 : 0; + uint32_t tail_node_num = trans->aligned_payload.buf.tail.length ? 1 : 0; + uint32_t required_node_num = body_node_num + head_node_num + tail_node_num; + if (trans->flags.infinite && required_node_num < 2) { /* At least 2 nodes needed */ required_node_num = 2; } rx_unit->node_num = required_node_num; + + gdma_buffer_mount_config_t mount_config[required_node_num] = {}; + /* Mount head buffer */ + if (head_node_num) { + mount_config[0].buffer = trans->aligned_payload.buf.head.aligned_buffer; + mount_config[0].buffer_alignment = trans->alignment; + mount_config[0].length = trans->aligned_payload.buf.head.length; + mount_config[0].flags.bypass_buffer_align_check = false; + mount_config[0].flags.mark_eof = false; + mount_config[0].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT; + } + /* Mount body buffer */ size_t mount_size = 0; size_t offset = 0; - // TODO: update DMA alignment -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - uint32_t alignment = rx_unit->base.group->dma_align; -#else - uint32_t alignment = 4; -#endif - - gdma_buffer_mount_config_t mount_config[required_node_num]; - /* Loop the nodes to assign the data */ - for (int i = 0; i < required_node_num; i++) { - size_t rest_size = trans->size - offset; + for (int i = head_node_num; i < required_node_num - tail_node_num; i++) { + size_t rest_size = trans->aligned_payload.buf.body.length - offset; if (rest_size >= 2 * PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { - mount_size = PARLIO_RX_MOUNT_SIZE_CALC(trans->size, required_node_num, alignment); + mount_size = PARLIO_RX_MOUNT_SIZE_CALC(trans->aligned_payload.buf.body.length, body_node_num, trans->alignment); } else if (rest_size <= PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { - mount_size = (required_node_num == 2) && (i == 0) ? PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment) : rest_size; + mount_size = (required_node_num == 2) && (i == 0) ? PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, trans->alignment) : rest_size; } else { - mount_size = PRALIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment); + mount_size = PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, trans->alignment); } - mount_config[i].buffer = (void *)((uint8_t *)trans->payload + offset); + mount_config[i].buffer = (void *)((uint8_t *)trans->aligned_payload.buf.body.aligned_buffer + offset); + mount_config[i].buffer_alignment = trans->alignment; mount_config[i].length = mount_size; mount_config[i].flags.bypass_buffer_align_check = false; mount_config[i].flags.mark_eof = false; mount_config[i].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT; - // Link the node - if (i == required_node_num - 1) { - /* For infinite transaction, link the node as a ring */ - mount_config[i].flags.mark_final = !trans->flags.infinite ? GDMA_FINAL_LINK_TO_NULL : GDMA_FINAL_LINK_TO_HEAD; - mount_config[i].flags.mark_eof = true; - } offset += mount_size; } + /* Mount tail buffer */ + if (tail_node_num) { + mount_config[required_node_num - 1].buffer = trans->aligned_payload.buf.tail.aligned_buffer; + mount_config[required_node_num - 1].buffer_alignment = trans->alignment; + mount_config[required_node_num - 1].length = trans->aligned_payload.buf.tail.length; + mount_config[required_node_num - 1].flags.bypass_buffer_align_check = false; + } + /* For infinite transaction, link the node as a ring */ + mount_config[required_node_num - 1].flags.mark_final = !trans->flags.infinite ? GDMA_FINAL_LINK_TO_NULL : GDMA_FINAL_LINK_TO_HEAD; + mount_config[required_node_num - 1].flags.mark_eof = true; gdma_link_mount_buffers(rx_unit->dma_link, 0, mount_config, required_node_num, NULL); /* Reset the current DMA node */ rx_unit->curr_node_id = 0; @@ -319,6 +338,7 @@ static bool parlio_rx_default_eof_callback(gdma_channel_handle_t dma_chan, gdma_ need_yield |= rx_unit->cbs.on_timeout(rx_unit, &evt_data, rx_unit->user_data); } } else { + esp_dma_merge_aligned_rx_buffers(&rx_unit->curr_trans.aligned_payload); /* If received a normal EOF, it's a receive done event on parlio RX */ if (rx_unit->cbs.on_receive_done) { evt_data.data = rx_unit->usr_recv_buf; @@ -403,7 +423,7 @@ static bool parlio_rx_default_desc_done_callback(gdma_channel_handle_t dma_chan, portEXIT_CRITICAL_ISR(&s_rx_spinlock); } /* Update received bytes */ - if (rx_unit->curr_trans.recv_bytes >= rx_unit->curr_trans.size) { + if (rx_unit->curr_trans.recv_bytes >= rx_unit->curr_trans.tot_trans_size) { rx_unit->curr_trans.recv_bytes = 0; } rx_unit->curr_trans.recv_bytes += evt_data.recv_bytes; @@ -419,24 +439,21 @@ static esp_err_t parlio_rx_create_dma_link(parlio_rx_unit_handle_t rx_unit, uint ESP_RETURN_ON_FALSE(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid param"); esp_err_t ret = ESP_OK; - // create DMA link list - size_t buffer_alignment = MAX(rx_unit->int_mem_align, rx_unit->ext_mem_align); - size_t tot_node_num = esp_dma_calculate_node_count(max_recv_size, buffer_alignment, PARLIO_DMA_DESCRIPTOR_BUFFER_MAX_SIZE); + // calculated the total node number, add 2 for the aligned stash buffer + size_t tot_node_num = esp_dma_calculate_node_count(max_recv_size, rx_unit->dma_mem_align, PARLIO_DMA_DESCRIPTOR_BUFFER_MAX_SIZE) + 2; gdma_link_list_config_t dma_link_config = { - .buffer_alignment = buffer_alignment, - .item_alignment = PARLIO_DMA_DESC_ALIGNMENT, .num_items = tot_node_num, + .item_alignment = PARLIO_DMA_DESC_ALIGNMENT, }; - // throw the error to the caller + // create DMA link list, throw the error to the caller if failed ESP_RETURN_ON_ERROR(gdma_new_link_list(&dma_link_config, &rx_unit->dma_link), TAG, "create DMA link list failed"); rx_unit->max_recv_size = max_recv_size; - return ret; } -static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit) +static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit, size_t dma_burst_size) { /* Allocate and connect the GDMA channel */ gdma_channel_alloc_config_t dma_chan_config = { @@ -456,13 +473,12 @@ static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit) gdma_apply_strategy(rx_unit->dma_chan, &gdma_strategy_conf); // configure DMA transfer parameters + rx_unit->dma_burst_size = dma_burst_size ? dma_burst_size : 16; gdma_transfer_config_t trans_cfg = { - // TODO: add burst size - .max_data_burst_size = 4, // Enable DMA burst transfer for better performance, - .access_ext_mem = true, // support transmit PSRAM buffer + .max_data_burst_size = rx_unit->dma_burst_size, // Enable DMA burst transfer for better performance, }; ESP_RETURN_ON_ERROR(gdma_config_transfer(rx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); - ESP_RETURN_ON_ERROR(gdma_get_alignment_constraints(rx_unit->dma_chan, &rx_unit->int_mem_align, &rx_unit->ext_mem_align), TAG, "get alignment constraints failed"); + ESP_RETURN_ON_ERROR(gdma_get_alignment_constraints(rx_unit->dma_chan, &rx_unit->dma_mem_align, NULL), TAG, "get alignment constraints failed"); /* Register callbacks */ gdma_rx_event_callbacks_t cbs = { @@ -571,6 +587,13 @@ static esp_err_t parlio_destroy_rx_unit(parlio_rx_unit_handle_t rx_unit) if (rx_unit->dma_buf) { free(rx_unit->dma_buf); } + /* Free the stash buffer */ + for (uint8_t i = 0; i < 2; i++) { + if (rx_unit->stash_buf[i]) { + free(rx_unit->stash_buf[i]); + rx_unit->stash_buf[i] = NULL; + } + } /* Unregister the RX unit from the PARLIO group */ if (rx_unit->base.group) { parlio_unregister_unit_from_group(&rx_unit->base); @@ -632,9 +655,14 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un /* Initialize GPIO */ ESP_GOTO_ON_ERROR(parlio_rx_unit_set_gpio(unit, config), err, TAG, "failed to set GPIO"); /* Install DMA service */ - ESP_GOTO_ON_ERROR(parlio_rx_unit_init_dma(unit), err, TAG, "install rx DMA failed"); + ESP_GOTO_ON_ERROR(parlio_rx_unit_init_dma(unit, config->dma_burst_size), err, TAG, "install rx DMA failed"); ESP_GOTO_ON_ERROR(parlio_rx_create_dma_link(unit, config->max_recv_size), err, TAG, "create dma link list failed"); + for (uint8_t i = 0; i < 2; i++) { + unit->stash_buf[i] = heap_caps_aligned_calloc(unit->dma_mem_align, 2, unit->dma_mem_align, PARLIO_MEM_ALLOC_CAPS | MALLOC_CAP_DMA); + ESP_GOTO_ON_FALSE(unit->stash_buf[i], ESP_ERR_NO_MEM, err, TAG, "no memory for stash buffer"); + } + /* Reset RX module */ PARLIO_RCC_ATOMIC() { parlio_ll_rx_reset_clock(hal->regs); @@ -719,7 +747,16 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu xSemaphoreGive(rx_unit->trans_sem); } else if (xQueueReceive(rx_unit->trans_que, &trans, 0) == pdTRUE) { // The semaphore always supposed to be taken successfully - assert(xSemaphoreTake(rx_unit->trans_sem, 0) == pdTRUE); + BaseType_t res = xSemaphoreTake(rx_unit->trans_sem, 0); + (void)res; + assert(res == pdTRUE); + + if (trans.flags.indirect_mount && trans.flags.infinite && rx_unit->dma_buf == NULL) { + rx_unit->dma_buf = heap_caps_aligned_calloc(rx_unit->dma_mem_align, 1, trans.aligned_payload.buf.body.length, PARLIO_DMA_MEM_ALLOC_CAPS); + ESP_GOTO_ON_FALSE(rx_unit->dma_buf, ESP_ERR_NO_MEM, err, TAG, "No memory for the internal DMA buffer"); + trans.aligned_payload.buf.body.aligned_buffer = rx_unit->dma_buf; + trans.aligned_payload.buf.body.recovery_address = rx_unit->dma_buf; + } if (rx_unit->cfg.flags.free_clk) { PARLIO_CLOCK_SRC_ATOMIC() { parlio_ll_rx_enable_clock(hal->regs, false); @@ -940,13 +977,11 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit, ESP_RETURN_ON_FALSE(rx_unit && payload && recv_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(recv_cfg->delimiter, ESP_ERR_INVALID_ARG, TAG, "no delimiter specified"); ESP_RETURN_ON_FALSE(payload_size <= rx_unit->max_recv_size, ESP_ERR_INVALID_ARG, TAG, "trans length too large"); - uint32_t alignment = rx_unit->base.group->dma_align; -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - ESP_RETURN_ON_FALSE(payload_size % alignment == 0, ESP_ERR_INVALID_ARG, TAG, "The payload size should align with %"PRIu32, alignment); + size_t alignment = rx_unit->dma_mem_align; if (recv_cfg->flags.partial_rx_en) { ESP_RETURN_ON_FALSE(payload_size >= 2 * alignment, ESP_ERR_INVALID_ARG, TAG, "The payload size should greater than %"PRIu32, 2 * alignment); } -#endif + #if CONFIG_PARLIO_RX_ISR_CACHE_SAFE ESP_RETURN_ON_FALSE(esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM"); #else @@ -967,8 +1002,8 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit, rx_units[rx_unit->base.unit_id]. data_sigs[recv_cfg->delimiter->valid_sig_line_id]; } - void *p_buffer = payload; + dma_buffer_split_array_t dma_buf_array = {0}; /* Create the internal DMA buffer for the infinite transaction if indirect_mount is set */ if (recv_cfg->flags.partial_rx_en && recv_cfg->flags.indirect_mount) { ESP_RETURN_ON_FALSE(!rx_unit->dma_buf, ESP_ERR_INVALID_STATE, TAG, "infinite transaction is using the internal DMA buffer"); @@ -976,14 +1011,21 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit, rx_unit->dma_buf = heap_caps_aligned_calloc(alignment, 1, payload_size, PARLIO_DMA_MEM_ALLOC_CAPS); ESP_RETURN_ON_FALSE(rx_unit->dma_buf, ESP_ERR_NO_MEM, TAG, "No memory for the internal DMA buffer"); /* Use the internal DMA buffer so that the user buffer can always be available */ - p_buffer = rx_unit->dma_buf; + dma_buf_array.buf.body.aligned_buffer = rx_unit->dma_buf; + dma_buf_array.buf.body.recovery_address = rx_unit->dma_buf; + dma_buf_array.buf.body.length = payload_size; + } else { + ESP_RETURN_ON_ERROR(esp_dma_split_rx_buffer_to_cache_aligned(payload, payload_size, &dma_buf_array, &rx_unit->stash_buf[rx_unit->stash_buf_idx]), + TAG, "failed to split the unaligned DMA buffer"); + rx_unit->stash_buf_idx = !rx_unit->stash_buf_idx; } /* Create the transaction */ parlio_rx_transaction_t transaction = { .delimiter = recv_cfg->delimiter, - .payload = p_buffer, - .size = payload_size, + .aligned_payload = dma_buf_array, + .tot_trans_size = payload_size, + .alignment = alignment, .recv_bytes = 0, .flags.infinite = recv_cfg->flags.partial_rx_en, .flags.indirect_mount = recv_cfg->flags.indirect_mount, diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index 86d6c22afb..329fcdfcd5 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -481,7 +481,7 @@ static void parlio_mount_buffer(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_ .flags = { // if transmission is loop, we don't need to generate the EOF for 1-bit data width, DIG-559 .mark_eof = tx_unit->data_width == 1 ? !t->flags.loop_transmission : true, - .mark_final = !t->flags.loop_transmission ? GDMA_FINAL_LINK_TO_NULL : GDMA_FINAL_LINK_TO_DEFAULT, + .mark_final = t->flags.loop_transmission ? GDMA_FINAL_LINK_TO_START : GDMA_FINAL_LINK_TO_NULL, } }; diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c index a5494f1f9f..e9cddeb20f 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c @@ -477,7 +477,7 @@ TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]") TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, payload, TEST_PAYLOAD_SIZE, &recv_config)); TEST_ESP_OK(parlio_rx_unit_wait_all_done(rx_unit, 5000)); TEST_ESP_OK(parlio_rx_soft_delimiter_start_stop(rx_unit, deli, false)); - TEST_ASSERT_EQUAL_UINT32(2, test_data.partial_recv_cnt); + TEST_ASSERT_GREATER_OR_EQUAL_UINT32(2, test_data.partial_recv_cnt); TEST_ASSERT_EQUAL_UINT32(1, test_data.recv_done_cnt); memset(&test_data, 0, sizeof(test_data_t)); @@ -489,7 +489,7 @@ TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]") } TEST_ESP_OK(parlio_rx_unit_wait_all_done(rx_unit, 5000)); TEST_ESP_OK(parlio_rx_soft_delimiter_start_stop(rx_unit, deli, false)); - TEST_ASSERT_EQUAL_UINT32(10, test_data.partial_recv_cnt); + TEST_ASSERT_GREATER_OR_EQUAL_UINT32(10, test_data.partial_recv_cnt); TEST_ASSERT_EQUAL_UINT32(5, test_data.recv_done_cnt); memset(&test_data, 0, sizeof(test_data_t)); diff --git a/components/esp_hw_support/dma/esp_dma_utils.c b/components/esp_hw_support/dma/esp_dma_utils.c index ad97b84e7e..a820291bcd 100644 --- a/components/esp_hw_support/dma/esp_dma_utils.c +++ b/components/esp_hw_support/dma/esp_dma_utils.c @@ -29,7 +29,7 @@ esp_err_t esp_dma_split_rx_buffer_to_cache_aligned(void *rx_buffer, size_t buffe { esp_err_t ret = ESP_OK; uint8_t* stash_buffer = NULL; - ESP_RETURN_ON_FALSE(rx_buffer && buffer_len && align_buf_array, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE_ISR(rx_buffer && buffer_len && align_buf_array, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); // read the cache line size of internal and external memory, we also use this information to check if a given memory is behind the cache size_t int_mem_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); @@ -41,80 +41,83 @@ esp_err_t esp_dma_split_rx_buffer_to_cache_aligned(void *rx_buffer, size_t buffe } else if (esp_ptr_internal(rx_buffer)) { split_line_size = int_mem_cache_line_size; } - ESP_LOGV(TAG, "split_line_size:%zu", split_line_size); + bool align_required = split_line_size > 0; + ESP_EARLY_LOGV(TAG, "split_line_size:%zu", split_line_size); - // allocate the stash buffer from internal RAM - // Note, the split_line_size can be 0, in this case, the stash_buffer is also NULL, which is fine - stash_buffer = heap_caps_calloc(2, split_line_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - ESP_RETURN_ON_FALSE(!(split_line_size && !stash_buffer), ESP_ERR_NO_MEM, TAG, "no mem for stash buffer"); + if (*ret_stash_buffer == NULL) { + // If the stash buffer is not offered by the caller, allocate the stash buffer from internal RAM + // Note, the split_line_size can be 0, in this case, the stash_buffer is also NULL, which is fine + stash_buffer = heap_caps_calloc(2, split_line_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_RETURN_ON_FALSE_ISR(!(split_line_size && !stash_buffer), ESP_ERR_NO_MEM, TAG, "no mem for stash buffer"); + } else { + // If the stash buffer is offered by the caller, check if it is aligned + ESP_RETURN_ON_FALSE_ISR(split_line_size == 0 || (uintptr_t)(*ret_stash_buffer) % split_line_size == 0, + ESP_ERR_INVALID_ARG, TAG, "the offered stash buffer is not aligned"); + // If the stash buffer is offered by the caller, use it + stash_buffer = *ret_stash_buffer; + } // clear align_array to avoid garbage data memset(align_buf_array, 0, sizeof(dma_buffer_split_array_t)); bool need_cache_sync[3] = {false}; - // if split_line_size is non-zero, split the buffer into head, body and tail - if (split_line_size > 0) { + // if align_required, split the buffer into head, body and tail + if (align_required) { // calculate head_overflow_len size_t head_overflow_len = (uintptr_t)rx_buffer % split_line_size; head_overflow_len = head_overflow_len ? split_line_size - head_overflow_len : 0; - ESP_LOGV(TAG, "head_addr:%p head_overflow_len:%zu", rx_buffer, head_overflow_len); + ESP_EARLY_LOGV(TAG, "head_addr:%p head_overflow_len:%zu", rx_buffer, head_overflow_len); // calculate tail_overflow_len size_t tail_overflow_len = ((uintptr_t)rx_buffer + buffer_len) % split_line_size; - ESP_LOGV(TAG, "tail_addr:%p tail_overflow_len:%zu", rx_buffer + buffer_len - tail_overflow_len, tail_overflow_len); - - uint8_t extra_buf_count = 0; - uint8_t* input_buffer = (uint8_t*)rx_buffer; - align_buf_array->buf.head.recovery_address = input_buffer; - align_buf_array->buf.head.aligned_buffer = stash_buffer + split_line_size * extra_buf_count++; - align_buf_array->buf.head.length = head_overflow_len; - need_cache_sync[0] = int_mem_cache_line_size > 0; - align_buf_array->buf.body.recovery_address = input_buffer + head_overflow_len; - align_buf_array->buf.body.aligned_buffer = input_buffer + head_overflow_len; - align_buf_array->buf.body.length = buffer_len - head_overflow_len - tail_overflow_len; - need_cache_sync[1] = true; - align_buf_array->buf.tail.recovery_address = input_buffer + buffer_len - tail_overflow_len; - align_buf_array->buf.tail.aligned_buffer = stash_buffer + split_line_size * extra_buf_count++; - align_buf_array->buf.tail.length = tail_overflow_len; - need_cache_sync[2] = int_mem_cache_line_size > 0; + ESP_EARLY_LOGV(TAG, "tail_addr:%p tail_overflow_len:%zu", rx_buffer + buffer_len - tail_overflow_len, tail_overflow_len); // special handling when input_buffer length is no more than buffer alignment - if (head_overflow_len >= buffer_len || tail_overflow_len >= buffer_len) { - align_buf_array->buf.head.length = buffer_len ; - align_buf_array->buf.body.length = 0 ; - align_buf_array->buf.tail.length = 0 ; + bool is_small_buf = head_overflow_len >= buffer_len || tail_overflow_len >= buffer_len; + uint8_t extra_buf_count = 0; + uint8_t* input_buffer = (uint8_t*)rx_buffer; + if (head_overflow_len || is_small_buf) { + align_buf_array->buf.head.recovery_address = input_buffer; + align_buf_array->buf.head.aligned_buffer = stash_buffer + split_line_size * extra_buf_count++; + align_buf_array->buf.head.length = is_small_buf ? buffer_len : head_overflow_len; + need_cache_sync[0] = int_mem_cache_line_size > 0; + } + int body_len = (int)buffer_len - (int)head_overflow_len - (int)tail_overflow_len; + if (body_len > 0) { + align_buf_array->buf.body.recovery_address = input_buffer + head_overflow_len; + align_buf_array->buf.body.aligned_buffer = input_buffer + head_overflow_len; + align_buf_array->buf.body.length = body_len; + need_cache_sync[1] = true; + } + if (tail_overflow_len && !is_small_buf) { + align_buf_array->buf.tail.recovery_address = input_buffer + buffer_len - tail_overflow_len; + align_buf_array->buf.tail.aligned_buffer = stash_buffer + split_line_size * extra_buf_count++; + align_buf_array->buf.tail.length = tail_overflow_len; + need_cache_sync[2] = int_mem_cache_line_size > 0; } } else { align_buf_array->buf.body.aligned_buffer = rx_buffer; align_buf_array->buf.body.recovery_address = rx_buffer; align_buf_array->buf.body.length = buffer_len; - need_cache_sync[1] = false; - } - - for (int i = 0; i < 3; i++) { - if (align_buf_array->aligned_buffer[i].length == 0) { - align_buf_array->aligned_buffer[i].aligned_buffer = NULL; - align_buf_array->aligned_buffer[i].recovery_address = NULL; - need_cache_sync[i] = false; - } } // invalidate the aligned buffer if necessary for (int i = 0; i < 3; i++) { - if (need_cache_sync[i]) { - size_t sync_size = align_buf_array->aligned_buffer[i].length; + size_t sync_size = align_buf_array->aligned_buffer[i].length; + if (need_cache_sync[i] && sync_size > 0) { if (sync_size < split_line_size) { // If the buffer is smaller than the cache line size, we need to sync the whole buffer sync_size = split_line_size; } esp_err_t res = esp_cache_msync(align_buf_array->aligned_buffer[i].aligned_buffer, sync_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); - ESP_GOTO_ON_ERROR(res, err, TAG, "failed to do cache sync"); + ESP_GOTO_ON_ERROR_ISR(res, err, TAG, "failed to do cache sync"); } } *ret_stash_buffer = stash_buffer; return ESP_OK; err: - if (stash_buffer) { + // Only free the stash buffer if it is not offered by the caller + if (stash_buffer && *ret_stash_buffer == NULL) { free(stash_buffer); } return ret; diff --git a/components/esp_hw_support/dma/gdma_link.c b/components/esp_hw_support/dma/gdma_link.c index 41b29a16e4..0caf76db92 100644 --- a/components/esp_hw_support/dma/gdma_link.c +++ b/components/esp_hw_support/dma/gdma_link.c @@ -203,20 +203,24 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i lli_nc->dw0.size = lli_nc->dw0.length; // mark the EOF node lli_nc->dw0.suc_eof = (config->flags.mark_eof == 1) && (i == num_items_need - 1); - // mark the final node - switch (config->flags.mark_final) { - case GDMA_FINAL_LINK_TO_NULL: - lli_nc->next = NULL; - break; - case GDMA_FINAL_LINK_TO_HEAD: - lli_nc->next = (gdma_link_list_item_t *)(list->items); - break; - case GDMA_FINAL_LINK_TO_START: - lli_nc->next = (gdma_link_list_item_t *)(list->items + begin_item_idx * item_size); - break; - default: - lli_nc->next = (gdma_link_list_item_t *)(list->items + (i + begin_item_idx + 1) % list_item_capacity * item_size); - break; + if (i == num_items_need - 1) { + // mark the final node + switch (config->flags.mark_final) { + case GDMA_FINAL_LINK_TO_NULL: + lli_nc->next = NULL; + break; + case GDMA_FINAL_LINK_TO_HEAD: + lli_nc->next = (gdma_link_list_item_t *)(list->items); + break; + case GDMA_FINAL_LINK_TO_START: + lli_nc->next = (gdma_link_list_item_t *)(list->items + start_item_index * item_size); + break; + default: + lli_nc->next = (gdma_link_list_item_t *)(list->items + (i + begin_item_idx + 1) % list_item_capacity * item_size); + break; + } + } else { + lli_nc->next = (gdma_link_list_item_t *)(list->items + (i + begin_item_idx + 1) % list_item_capacity * item_size); } lli_nc->dw0.owner = GDMA_LLI_OWNER_DMA; buf += max_buffer_mount_length; diff --git a/components/esp_hw_support/dma/include/esp_private/gdma_link.h b/components/esp_hw_support/dma/include/esp_private/gdma_link.h index 3e3d4be22c..37d9964a3a 100644 --- a/components/esp_hw_support/dma/include/esp_private/gdma_link.h +++ b/components/esp_hw_support/dma/include/esp_private/gdma_link.h @@ -62,7 +62,7 @@ esp_err_t gdma_del_link_list(gdma_link_list_handle_t list); */ typedef enum { GDMA_FINAL_LINK_TO_DEFAULT = 0, /*!< The next node is linked to the default next item in the link list */ - GDMA_FINAL_LINK_TO_NULL = 1, /*!< The next node is linked to the final item in the link list */ + GDMA_FINAL_LINK_TO_NULL = 1, /*!< No next node is linked */ GDMA_FINAL_LINK_TO_HEAD = 2, /*!< The next node is linked to the head item in the link list */ GDMA_FINAL_LINK_TO_START = 3, /*!< The next node is linked to the start item in the link list */ } gdma_final_node_link_type_t; @@ -77,9 +77,11 @@ typedef struct { struct gdma_buffer_mount_flags { uint32_t mark_eof: 1; /*!< Whether to mark the list item as the "EOF" item. Note, an "EOF" descriptor can be interrupted differently by peripheral. - But it doesn't mean to terminate a DMA link (use `mark_final` instead). + But it doesn't mean to terminate a DMA link (set `mark_final` to GDMA_FINAL_LINK_TO_NULL instead). EOF link list item can also trigger an interrupt. */ - gdma_final_node_link_type_t mark_final: 2; /*!< The next node of the final item in the link list */ + gdma_final_node_link_type_t mark_final: 2; /*!< Specify the next item of the final item of this mount. + For the other items that not the final one, it will be linked to the next item automatically and this field takes no effect. + Note, the final item here does not mean the last item in the link list. It is `start_item_index + num_items - 1` */ uint32_t bypass_buffer_align_check: 1; /*!< Whether to bypass the buffer alignment check. Only enable it when you know what you are doing. */ } flags; //!< Flags for buffer mount configurations diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index 6d3ed816b4..616e68bb6b 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -1013,7 +1013,7 @@ static esp_err_t lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *rgb_panel) mount_cfgs[i].buffer = rgb_panel->bounce_buffer[i]; mount_cfgs[i].buffer_alignment = buffer_alignment; mount_cfgs[i].length = rgb_panel->bb_size; - mount_cfgs[i].flags.mark_eof = GDMA_FINAL_LINK_TO_NULL; // we use the DMA EOF interrupt to copy the frame buffer (partially) to the bounce buffer + mount_cfgs[i].flags.mark_eof = true; // we use the DMA EOF interrupt to copy the frame buffer (partially) to the bounce buffer } ESP_RETURN_ON_ERROR(gdma_link_mount_buffers(rgb_panel->dma_bb_link, 0, mount_cfgs, RGB_LCD_PANEL_BOUNCE_BUF_NUM, NULL), TAG, "mount DMA bounce buffers failed"); From 10de0f399dda3e63da4bc4f651368f13c40b39ea Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 3 Nov 2025 12:44:08 +0800 Subject: [PATCH 028/156] fix(i2s): fixed divide-by-zero coverity issue --- components/esp_driver_i2s/i2s_common.c | 3 +++ components/esp_driver_i2s/i2s_pdm.c | 12 ++++++++++-- components/esp_driver_i2s/i2s_std.c | 5 ++++- components/esp_driver_i2s/i2s_tdm.c | 5 ++++- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 820e3d1065..b54402cb50 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -417,6 +417,9 @@ uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uin uint32_t bytes_per_sample = (data_bit_width + 7) / 8; #endif // CONFIG_IDF_TARGET_ESP32 uint32_t bytes_per_frame = bytes_per_sample * active_chan; + if (bytes_per_frame == 0) { + return 0; + } uint32_t bufsize = dma_frame_num * bytes_per_frame; #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE /* bufsize need to align with cache line size */ diff --git a/components/esp_driver_i2s/i2s_pdm.c b/components/esp_driver_i2s/i2s_pdm.c index 760c2838fc..280518418c 100644 --- a/components/esp_driver_i2s/i2s_pdm.c +++ b/components/esp_driver_i2s/i2s_pdm.c @@ -95,11 +95,14 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx #endif portEXIT_CRITICAL(&g_i2s.spinlock); + uint64_t tmp_div = (uint64_t)ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator; + ESP_RETURN_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, TAG, "invalid mclk division result"); + /* Update the mode info: clock configuration */ memcpy(&(pdm_tx_cfg->clk_cfg), clk_cfg, sizeof(i2s_pdm_tx_clk_config_t)); handle->clk_src = clk_cfg->clk_src; handle->sclk_hz = clk_info.sclk; - handle->origin_mclk_hz = ((uint64_t)clk_info.sclk * ret_mclk_div.denominator) / (ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator); + handle->origin_mclk_hz = ((uint64_t)clk_info.sclk * ret_mclk_div.denominator) / tmp_div; handle->curr_mclk_hz = handle->origin_mclk_hz; ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %"PRIu32" %"PRIu32"/%"PRIu32" [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz", @@ -119,6 +122,7 @@ static esp_err_t i2s_pdm_tx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_ handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2; uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num); + ESP_RETURN_ON_FALSE(buf_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid data_bit_width"); /* The DMA buffer need to re-allocate if the buffer size changed */ if (handle->dma.buf_size != buf_size) { ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor"); @@ -422,11 +426,14 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx } portEXIT_CRITICAL(&g_i2s.spinlock); + uint64_t tmp_div = (uint64_t)ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator; + ESP_RETURN_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, TAG, "invalid mclk division result"); + /* Update the mode info: clock configuration */ memcpy(&(pdm_rx_cfg->clk_cfg), clk_cfg, sizeof(i2s_pdm_rx_clk_config_t)); handle->clk_src = clk_cfg->clk_src; handle->sclk_hz = clk_info.sclk; - handle->origin_mclk_hz = ((uint64_t)clk_info.sclk * ret_mclk_div.denominator) / (ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator); + handle->origin_mclk_hz = ((uint64_t)clk_info.sclk * ret_mclk_div.denominator) / tmp_div; handle->curr_mclk_hz = handle->origin_mclk_hz; ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %"PRIu32" %"PRIu32"/%"PRIu32" [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz", clk_info.sclk, ret_mclk_div.integer, ret_mclk_div.numerator, ret_mclk_div.denominator, handle->origin_mclk_hz, clk_info.bclk_div, clk_info.bclk); @@ -445,6 +452,7 @@ static esp_err_t i2s_pdm_rx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_ handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2; uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num); + ESP_RETURN_ON_FALSE(buf_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid data_bit_width"); /* The DMA buffer need to re-allocate if the buffer size changed */ if (handle->dma.buf_size != buf_size) { ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor"); diff --git a/components/esp_driver_i2s/i2s_std.c b/components/esp_driver_i2s/i2s_std.c index 701b6df4ee..297001eeb4 100644 --- a/components/esp_driver_i2s/i2s_std.c +++ b/components/esp_driver_i2s/i2s_std.c @@ -96,12 +96,14 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c } } portEXIT_CRITICAL(&g_i2s.spinlock); + uint64_t tmp_div = (uint64_t)ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator; + ESP_RETURN_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, TAG, "invalid mclk division result"); /* Update the mode info: clock configuration */ memcpy(&(std_cfg->clk_cfg), clk_cfg, sizeof(i2s_std_clk_config_t)); handle->clk_src = clk_cfg->clk_src; handle->sclk_hz = clk_info.sclk; - handle->origin_mclk_hz = ((uint64_t)clk_info.sclk * ret_mclk_div.denominator) / (ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator); + handle->origin_mclk_hz = ((uint64_t)clk_info.sclk * ret_mclk_div.denominator) / tmp_div; handle->curr_mclk_hz = handle->origin_mclk_hz; ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %"PRIu32" %"PRIu32"/%"PRIu32" [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz", @@ -117,6 +119,7 @@ static esp_err_t i2s_std_set_slot(i2s_chan_handle_t handle, const i2s_std_slot_c handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2; uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num); + ESP_RETURN_ON_FALSE(buf_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid data_bit_width"); /* The DMA buffer need to re-allocate if the buffer size changed */ if (handle->dma.buf_size != buf_size) { ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor"); diff --git a/components/esp_driver_i2s/i2s_tdm.c b/components/esp_driver_i2s/i2s_tdm.c index 1b81620494..6c5bad5e55 100644 --- a/components/esp_driver_i2s/i2s_tdm.c +++ b/components/esp_driver_i2s/i2s_tdm.c @@ -93,12 +93,14 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c } } portEXIT_CRITICAL(&g_i2s.spinlock); + uint64_t tmp_div = (uint64_t)ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator; + ESP_RETURN_ON_FALSE(tmp_div != 0 && ret_mclk_div.denominator != 0, ESP_ERR_INVALID_ARG, TAG, "invalid mclk division result"); /* Update the mode info: clock configuration */ memcpy(&(tdm_cfg->clk_cfg), clk_cfg, sizeof(i2s_tdm_clk_config_t)); handle->clk_src = clk_cfg->clk_src; handle->sclk_hz = clk_info.sclk; - handle->origin_mclk_hz = ((uint64_t)clk_info.sclk * ret_mclk_div.denominator) / (ret_mclk_div.integer * ret_mclk_div.denominator + ret_mclk_div.numerator); + handle->origin_mclk_hz = ((uint64_t)clk_info.sclk * ret_mclk_div.denominator) / tmp_div; handle->curr_mclk_hz = handle->origin_mclk_hz; ESP_LOGD(TAG, "Clock division info: [sclk] %"PRIu32" Hz [mdiv] %"PRIu32" %"PRIu32"/%"PRIu32" [mclk] %"PRIu32" Hz [bdiv] %d [bclk] %"PRIu32" Hz", @@ -121,6 +123,7 @@ static esp_err_t i2s_tdm_set_slot(i2s_chan_handle_t handle, const i2s_tdm_slot_c "total slots(%"PRIu32") * slot_bit_width(%"PRIu32") exceeds the maximum %d", handle->total_slot, slot_bits, (int)I2S_LL_SLOT_FRAME_BIT_MAX); uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num); + ESP_RETURN_ON_FALSE(buf_size != 0, ESP_ERR_INVALID_ARG, TAG, "invalid data_bit_width"); /* The DMA buffer need to re-allocate if the buffer size changed */ if (handle->dma.buf_size != buf_size) { ESP_RETURN_ON_ERROR(i2s_free_dma_desc(handle), TAG, "failed to free the old dma descriptor"); From 80e4bbb7500b0279663cae303b92681a005ad1a8 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Thu, 6 Nov 2025 11:34:32 +0800 Subject: [PATCH 029/156] fix(touch): make the gpio init symmetric Closes https://github.com/espressif/esp-idf/issues/17806 --- .../esp_driver_touch_sens/common/touch_sens_common.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/esp_driver_touch_sens/common/touch_sens_common.c b/components/esp_driver_touch_sens/common/touch_sens_common.c index 1b0d726f72..e9feeb46d0 100644 --- a/components/esp_driver_touch_sens/common/touch_sens_common.c +++ b/components/esp_driver_touch_sens/common/touch_sens_common.c @@ -49,6 +49,14 @@ static void touch_channel_pin_init(int id) gpio_config_as_analog(pin); } +static void touch_channel_pin_deinit(int id) +{ + gpio_num_t pin = touch_sensor_channel_io_map[id]; + assert(pin >= 0); + esp_gpio_revoke(BIT64(pin)); + gpio_reset_pin(pin); +} + static void s_touch_free_resource(touch_sensor_handle_t sens_handle) { if (!sens_handle) { @@ -211,6 +219,7 @@ esp_err_t touch_sensor_del_channel(touch_channel_handle_t chan_handle) TOUCH_ENTER_CRITICAL(TOUCH_PERIPH_LOCK); sens_handle->chan_mask &= ~(1UL << chan_handle->id); TOUCH_EXIT_CRITICAL(TOUCH_PERIPH_LOCK); + touch_channel_pin_deinit(chan_handle->id); free(g_touch->ch[ch_offset]); g_touch->ch[ch_offset] = NULL; From 06c5d728c6eaf8a142adca9e1a5a687c938b6473 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 7 Nov 2025 11:14:09 +0800 Subject: [PATCH 030/156] docs(pm): updated i2s pm lock type in DFS Related https://github.com/espressif/esp-idf/issues/14707 --- .../esp_driver_touch_sens/common/touch_sens_common.c | 4 +++- docs/en/api-reference/system/power_management.rst | 11 +++++++---- docs/zh_CN/api-reference/system/power_management.rst | 11 +++++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/components/esp_driver_touch_sens/common/touch_sens_common.c b/components/esp_driver_touch_sens/common/touch_sens_common.c index e9feeb46d0..39c12615c4 100644 --- a/components/esp_driver_touch_sens/common/touch_sens_common.c +++ b/components/esp_driver_touch_sens/common/touch_sens_common.c @@ -43,6 +43,8 @@ static void touch_channel_pin_init(int id) { gpio_num_t pin = touch_sensor_channel_io_map[id]; assert(pin >= 0); + /* Touch pad will output the sawtooth wave on the pin, + so it needs to be reserved, in case of conflict with other output signals */ if (esp_gpio_reserve(BIT64(pin)) & BIT64(pin)) { ESP_LOGW(TAG, "The GPIO%d is conflict with other module", (int)pin); } @@ -53,7 +55,7 @@ static void touch_channel_pin_deinit(int id) { gpio_num_t pin = touch_sensor_channel_io_map[id]; assert(pin >= 0); - esp_gpio_revoke(BIT64(pin)); + /* esp_gpio_revoke is called in gpio_reset_pin */ gpio_reset_pin(pin); } diff --git a/docs/en/api-reference/system/power_management.rst b/docs/en/api-reference/system/power_management.rst index e953ee0280..bddee9ad42 100644 --- a/docs/en/api-reference/system/power_management.rst +++ b/docs/en/api-reference/system/power_management.rst @@ -102,10 +102,13 @@ Peripheral clock sources such as ``REF_TICK``, ``XTAL``, ``RC_FAST`` (i.e., ``RT Currently, the following peripheral drivers are aware of DFS and use the ``ESP_PM_APB_FREQ_MAX`` lock for the duration of the transaction: -- SPI master -- I2C -- I2S (If the APLL clock is used, then it will use the ``ESP_PM_NO_LIGHT_SLEEP`` lock) -- SDMMC +.. list:: + + - SPI master + - I2C + :SOC_I2S_HW_VERSION_1 or not SOC_I2S_SUPPORTS_APLL: - I2S + :not SOC_I2S_HW_VERSION_1 and SOC_I2S_SUPPORTS_APLL: - I2S (if the APLL clock is used, then it will use the ``ESP_PM_NO_LIGHT_SLEEP`` lock) + - SDMMC The following drivers hold the ``ESP_PM_APB_FREQ_MAX`` lock while the driver is enabled: diff --git a/docs/zh_CN/api-reference/system/power_management.rst b/docs/zh_CN/api-reference/system/power_management.rst index 11fdde8cbb..dd568616a9 100644 --- a/docs/zh_CN/api-reference/system/power_management.rst +++ b/docs/zh_CN/api-reference/system/power_management.rst @@ -102,10 +102,13 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求, 目前以下外设驱动程序可感知动态调频,并在调频期间使用 ``ESP_PM_APB_FREQ_MAX`` 锁: -- SPI master -- I2C -- I2S(如果 APLL 锁在使用中,I2S 则会启用 ``ESP_PM_NO_LIGHT_SLEEP`` 锁) -- SDMMC +.. list:: + + - SPI master + - I2C + :SOC_I2S_HW_VERSION_1 or not SOC_I2S_SUPPORTS_APLL: - I2S + :not SOC_I2S_HW_VERSION_1 and SOC_I2S_SUPPORTS_APLL: - I2S(如果 APLL 锁在使用中,I2S 则会启用 ``ESP_PM_NO_LIGHT_SLEEP`` 锁) + - SDMMC 启用以下驱动程序时,将占用 ``ESP_PM_APB_FREQ_MAX`` 锁: From da6508fa10cc2109a9aea2ac2913d041f517ce48 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Wed, 5 Nov 2025 14:36:38 +0800 Subject: [PATCH 031/156] feat(parlio_rx): support to force trigger eof --- .../include/esp_private/parlio_rx_private.h | 30 ++++ components/esp_driver_parlio/src/parlio_rx.c | 55 +++++- .../test_apps/parlio/main/test_parlio_rx.c | 170 ++++++++++++++++-- 3 files changed, 240 insertions(+), 15 deletions(-) create mode 100644 components/esp_driver_parlio/include/esp_private/parlio_rx_private.h diff --git a/components/esp_driver_parlio/include/esp_private/parlio_rx_private.h b/components/esp_driver_parlio/include/esp_private/parlio_rx_private.h new file mode 100644 index 0000000000..657237642b --- /dev/null +++ b/components/esp_driver_parlio/include/esp_private/parlio_rx_private.h @@ -0,0 +1,30 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "driver/parlio_rx.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Force to trigger the EOF interrupt + * @note This function is a workaround for the case that level delimiter needs to receive more than 64KB data in one transaction. + * + * @param rx_unit Parallel IO RX unit that created by `parlio_new_rx_unit` + * @param need_yield Pointer to a status flag to record whether a task switch is needed if this API is being called in an ISR + * @return + * - ESP_OK: Force to trigger the EOF interrupt successfully + * - ESP_ERR_INVALID_ARG: Invalid argument like NULL pointer + * - ESP_ERR_INVALID_STATE: Tx unit is in using, can't be called when pair tx unit is in using + */ +esp_err_t parlio_rx_unit_force_trigger_eof(parlio_rx_unit_handle_t rx_unit, bool *need_yield); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index cce214885e..a8ec151316 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -419,7 +419,9 @@ static bool parlio_rx_default_desc_done_callback(gdma_channel_handle_t dma_chan, memcpy(rx_unit->usr_recv_buf + rx_unit->curr_trans.recv_bytes, evt_data.data, evt_data.recv_bytes); } else { portENTER_CRITICAL_ISR(&s_rx_spinlock); - rx_unit->curr_trans.delimiter->under_using = false; + if (rx_unit->curr_trans.delimiter) { + rx_unit->curr_trans.delimiter->under_using = false; + } portEXIT_CRITICAL_ISR(&s_rx_spinlock); } /* Update received bytes */ @@ -479,6 +481,10 @@ static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit, size_t }; ESP_RETURN_ON_ERROR(gdma_config_transfer(rx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); ESP_RETURN_ON_ERROR(gdma_get_alignment_constraints(rx_unit->dma_chan, &rx_unit->dma_mem_align, NULL), TAG, "get alignment constraints failed"); +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + rx_unit->dma_mem_align = rx_unit->dma_mem_align > cache_line_size ? rx_unit->dma_mem_align : cache_line_size; +#endif /* Register callbacks */ gdma_rx_event_callbacks_t cbs = { @@ -1077,3 +1083,50 @@ err: xSemaphoreGive(rx_unit->mutex); return ret; } + +esp_err_t parlio_rx_unit_force_trigger_eof(parlio_rx_unit_handle_t rx_unit, bool *need_yield) +{ + ESP_RETURN_ON_FALSE_ISR(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + int uint_id = rx_unit->base.unit_id; + parlio_unit_base_handle_t pair_tx_unit = rx_unit->base.group->tx_units[uint_id]; + /* This function will reset the whole parlio module, + If the pair tx unit is in using, + the reset operation will affect the TX unit and lead to unknown behavior */ + ESP_RETURN_ON_FALSE_ISR(!pair_tx_unit, ESP_ERR_INVALID_STATE, TAG, "can't be called when pair tx unit is in using"); + + /* Stop and reset the DMA channel first */ + ESP_RETURN_ON_ERROR_ISR(gdma_stop(rx_unit->dma_chan), TAG, "stop DMA channel failed"); + ESP_RETURN_ON_ERROR_ISR(gdma_reset(rx_unit->dma_chan), TAG, "reset DMA channel failed"); + + parlio_hal_context_t *hal = &rx_unit->base.group->hal; + /* Save the current register values */ + parl_io_dev_t save_curr_regs = *(parl_io_dev_t *)hal->regs; + /* Reset the hardware FSM of the parlio module */ + PARLIO_RCC_ATOMIC() { + parlio_ll_reset_register(rx_unit->base.group->group_id); + } + /* Switch to the default clock source to ensure the register values can be written back successfully */ + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_set_clock_source(hal->regs, PARLIO_CLK_SRC_DEFAULT); + } + /* Restore the register values and clock source*/ + memcpy(hal->regs, &save_curr_regs, sizeof(parl_io_dev_t)); + parlio_ll_rx_update_config(hal->regs); + PARLIO_CLOCK_SRC_ATOMIC() { + parlio_ll_rx_set_clock_source(hal->regs, rx_unit->clk_src); + } + + /* Force to trigger the EOF interrupt */ + gdma_event_data_t event_data = { + .flags.normal_eof = 1 + }; + bool _need_yield = false; + _need_yield |= parlio_rx_default_desc_done_callback(rx_unit->dma_chan, &event_data, rx_unit); + _need_yield |= parlio_rx_default_eof_callback(rx_unit->dma_chan, &event_data, rx_unit); + if (need_yield) { + *need_yield |= _need_yield; + } + + return ESP_OK; +} diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c index e9cddeb20f..b77bb8b403 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +25,7 @@ #include "soc/parlio_periph.h" #include "esp_attr.h" #include "test_board.h" +#include "esp_private/parlio_rx_private.h" #define TEST_SPI_HOST SPI2_HOST #define TEST_I2S_PORT I2S_NUM_0 @@ -57,6 +58,10 @@ #define TEST_TASK_DATA_READY_BIT 0x01 #define TEST_TASK_FINISHED_BIT 0x02 +#define TEST_TASK_RECV_READY_BIT 0x04 +#define TEST_TASK_LARGE_TRANS_BIT 0x08 + +#define TEST_TASK_LARGE_TRANS_SIZE 155584 // Use an unaligned size to ensure the reliability typedef struct { uint32_t partial_recv_cnt; @@ -177,8 +182,6 @@ static void pulse_delimiter_sender_task_i2s(void *args) } } -#if CONFIG_IDF_TARGET_ESP32C6 // TODO: IDF-9806 fix the bit shift issue in other target - static void cs_high(spi_transaction_t *trans) { gpio_set_level(TEST_VALID_GPIO, 1); @@ -194,6 +197,7 @@ static void cs_low(spi_transaction_t *trans) static void level_delimiter_sender_task_spi(void *args) { uint32_t *task_flags = (uint32_t *)args; + bool is_large_trans = *task_flags & TEST_TASK_LARGE_TRANS_BIT; spi_device_handle_t dev_handle; spi_bus_config_t bus_cfg = { @@ -210,11 +214,11 @@ static void level_delimiter_sender_task_spi(void *args) .clock_speed_hz = TEST_SPI_CLK_FREQ, .mode = 0, .duty_cycle_pos = 128, - .spics_io_num = TEST_VALID_GPIO, + .spics_io_num = is_large_trans ? -1 : TEST_VALID_GPIO, .queue_size = 5, .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_POSITIVE_CS, - .pre_cb = cs_high, - .post_cb = cs_low, + .pre_cb = is_large_trans ? NULL : cs_high, + .post_cb = is_large_trans ? NULL : cs_low, }; //Initialize the SPI bus and add device TEST_ESP_OK(spi_bus_initialize(TEST_SPI_HOST, &bus_cfg, SPI_DMA_CH_AUTO)); @@ -240,8 +244,14 @@ static void level_delimiter_sender_task_spi(void *args) parlio_periph_signals.groups[0].rx_units[0].data_sigs[0]); // Prepare the data the be transmitted - uint8_t *data = (uint8_t *)calloc(1, TEST_EOF_DATA_LEN); - for (int i = 0; i < TEST_EOF_DATA_LEN; i += 4) { + uint8_t *data = NULL; + size_t data_size = TEST_EOF_DATA_LEN; + if (*task_flags & TEST_TASK_LARGE_TRANS_BIT) { + data_size = 1024; + } + data = (uint8_t *)calloc(1, data_size); + TEST_ASSERT_NOT_NULL(data); + for (int i = 0; i < data_size; i += 4) { data[i] = 0x12; data[i + 1] = 0x34; data[i + 2] = 0x56; @@ -249,17 +259,31 @@ static void level_delimiter_sender_task_spi(void *args) } spi_transaction_t t = { .cmd = 0, - .length = TEST_EOF_DATA_LEN * 8, + .length = data_size * 8, .flags = 0, .tx_buffer = data, .user = NULL, }; // Transmit data every 1ms, until the main test thread finished receiving - while (!((*task_flags) & TEST_TASK_FINISHED_BIT)) { - TEST_ESP_OK(spi_device_transmit(dev_handle, &t)); - vTaskDelay(pdMS_TO_TICKS(1)); - *task_flags |= TEST_TASK_DATA_READY_BIT; + if (is_large_trans) { + while (!((*task_flags) & TEST_TASK_FINISHED_BIT)) { + if (!((*task_flags) & TEST_TASK_RECV_READY_BIT)) { + gpio_set_level(TEST_VALID_GPIO, 1); + for (int i = 0; i < 80; i++) { + TEST_ESP_OK(spi_device_transmit(dev_handle, &t)); + } + gpio_set_level(TEST_VALID_GPIO, 0); + *task_flags |= TEST_TASK_DATA_READY_BIT; + } + vTaskDelay(pdMS_TO_TICKS(2)); + } + } else { + while (!((*task_flags) & TEST_TASK_FINISHED_BIT)) { + TEST_ESP_OK(spi_device_transmit(dev_handle, &t)); + vTaskDelay(pdMS_TO_TICKS(2)); + *task_flags |= TEST_TASK_DATA_READY_BIT; + } } // Remove the SPI device and free the bus @@ -275,7 +299,6 @@ static void level_delimiter_sender_task_spi(void *args) vTaskDelay(portMAX_DELAY); } } -#endif static bool test_delimiter(parlio_rx_delimiter_handle_t deli, bool free_running_clk, void (*sender_task_thread)(void *args)) { @@ -592,3 +615,122 @@ TEST_CASE("parallel_rx_unit_receive_timeout_test", "[parlio_rx]") TEST_ESP_OK(gpio_reset_pin(TEST_VALID_GPIO)); free(payload); } + +typedef struct { + uint32_t partial_recv_cnt; + uint32_t recv_done_cnt; + uint32_t timeout_cnt; + uint32_t isr_send_cnt; + uint32_t isr_send_success_cnt; + parlio_rx_unit_handle_t rx_unit; + parlio_rx_delimiter_handle_t delimiter; + uint8_t *isr_payload; + size_t isr_payload_size; + bool enable_isr_send; +} test_isr_data_t; + +/** + * @brief This ISR is to indicate the SPI transaction finished + */ +static void test_gpio_neg_edge_intr(void *arg) +{ + parlio_rx_unit_handle_t rx_unit = (parlio_rx_unit_handle_t)arg; + bool need_yield = false; + parlio_rx_unit_force_trigger_eof(rx_unit, &need_yield); + if (need_yield) { + portYIELD_FROM_ISR(); + } +} + +TEST_CASE("parallel_rx_unit_force_trigger_eof_test", "[parlio_rx]") +{ + parlio_rx_unit_handle_t rx_unit = NULL; + + parlio_rx_unit_config_t config = TEST_DEFAULT_UNIT_CONFIG(PARLIO_CLK_SRC_EXTERNAL, 1000000); + config.flags.free_clk = 0; + config.max_recv_size = TEST_TASK_LARGE_TRANS_SIZE; + TEST_ESP_OK(parlio_new_rx_unit(&config, &rx_unit)); + + parlio_rx_level_delimiter_config_t lvl_deli_cfg = { + .valid_sig_line_id = TEST_VALID_SIG, + .sample_edge = PARLIO_SAMPLE_EDGE_POS, + .bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB, + /* Normally the EOF won't be triggered for the level delimiter that eof_data_len larger than 64KB */ + .eof_data_len = TEST_TASK_LARGE_TRANS_SIZE, + .timeout_ticks = 0, + .flags = { + .active_low_en = 0, + }, + }; + parlio_rx_delimiter_handle_t deli = NULL; + TEST_ESP_OK(parlio_new_rx_level_delimiter(&lvl_deli_cfg, &deli)); + + parlio_rx_event_callbacks_t cbs = { + .on_receive_done = test_parlio_rx_done_callback, + }; + test_data_t test_data = { + .partial_recv_cnt = 0, + .recv_done_cnt = 0, + }; + TEST_ESP_OK(parlio_rx_unit_register_event_callbacks(rx_unit, &cbs, &test_data)); + TEST_ESP_OK(parlio_rx_unit_enable(rx_unit, true)); + + TaskHandle_t sender_task; + /* The flag to transport finish information between main test thread and the sender thread + * Set it as static to make sure it'll be valid in another thread */ + static uint32_t task_flags = TEST_TASK_LARGE_TRANS_BIT; + xTaskCreate(level_delimiter_sender_task_spi, "sender task", 4096, &task_flags, 5, &sender_task); + + parlio_receive_config_t recv_config = { + .delimiter = deli, + .flags.partial_rx_en = false, + }; + uint8_t *recv_buff = NULL; + uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); + alignment = alignment < 4 ? 4 : alignment; + size_t buff_size = ALIGN_UP(TEST_TASK_LARGE_TRANS_SIZE, alignment); + recv_buff = heap_caps_aligned_calloc(alignment, 1, buff_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS); + TEST_ASSERT_NOT_NULL(recv_buff); + + gpio_set_intr_type(TEST_VALID_GPIO, GPIO_INTR_NEGEDGE); + gpio_install_isr_service(0); + gpio_isr_handler_add(TEST_VALID_GPIO, test_gpio_neg_edge_intr, rx_unit); + gpio_intr_enable(TEST_VALID_GPIO); + + uint32_t recv_cnt = 3; + for (int i = 0; i < recv_cnt; i++) { + TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, recv_buff, buff_size, &recv_config)); + printf("[%d] recv ready\n", i); + task_flags |= TEST_TASK_RECV_READY_BIT; + while (!task_flags & TEST_TASK_DATA_READY_BIT) { + vTaskDelay(1); + } + task_flags &= ~TEST_TASK_DATA_READY_BIT; + printf("[%d] send done\n", i); + TEST_ESP_OK(parlio_rx_unit_wait_all_done(rx_unit, 10000)); + task_flags &= ~TEST_TASK_RECV_READY_BIT; + printf("[%d] recv done\n", i); + } + // Indicate the test finished, no need to send data + task_flags |= TEST_TASK_FINISHED_BIT; + + bool is_success = true; + is_success &= test_data.recv_done_cnt == recv_cnt; + + gpio_intr_disable(TEST_VALID_GPIO); + gpio_isr_handler_remove(TEST_VALID_GPIO); + gpio_uninstall_isr_service(); + // Waiting for the sender task quit + while (task_flags) { + vTaskDelay(1); + } + // Delete the sender task + vTaskDelete(sender_task); + free(recv_buff); + + TEST_ESP_OK(parlio_rx_unit_disable(rx_unit)); + TEST_ESP_OK(parlio_del_rx_delimiter(deli)); + TEST_ESP_OK(parlio_del_rx_unit(rx_unit)); + + TEST_ASSERT(is_success); +} From 523a43f2813f3b430a682d1565e444370436ce0a Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 7 Nov 2025 18:16:03 +0800 Subject: [PATCH 032/156] feat(parlio_rx): support to receive data into external ram --- components/esp_driver_parlio/src/parlio_rx.c | 17 +++++--- .../test_apps/parlio/main/test_parlio_rx.c | 43 ++++++++++++++++++- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index a8ec151316..3b023287ce 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -164,7 +164,7 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli if (rest_size >= 2 * PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { mount_size = PARLIO_RX_MOUNT_SIZE_CALC(trans->aligned_payload.buf.body.length, body_node_num, trans->alignment); } else if (rest_size <= PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { - mount_size = (required_node_num == 2) && (i == 0) ? PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, trans->alignment) : rest_size; + mount_size = (required_node_num - tail_node_num == 2) && (i == 0) ? PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, trans->alignment) : rest_size; } else { mount_size = PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, trans->alignment); } @@ -401,7 +401,15 @@ static bool parlio_rx_default_desc_done_callback(gdma_channel_handle_t dma_chan, size_t finished_length = gdma_link_get_length(rx_unit->dma_link, rx_unit->curr_node_id); #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE esp_err_t ret = ESP_OK; - ret = esp_cache_msync(finished_buffer, finished_length, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + size_t sync_size = finished_length; + /* The sych length should be the cache line size for the un-aligned head and tail part */ + for (int i = 0; i < 2; i++) { + if (finished_buffer == rx_unit->stash_buf[i]) { + sync_size = rx_unit->dma_mem_align; + break; + } + } + ret = esp_cache_msync(finished_buffer, sync_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C); if (ret != ESP_OK) { ESP_EARLY_LOGW(TAG, "failed to sync dma buffer from memory to cache"); } @@ -988,11 +996,6 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit, ESP_RETURN_ON_FALSE(payload_size >= 2 * alignment, ESP_ERR_INVALID_ARG, TAG, "The payload size should greater than %"PRIu32, 2 * alignment); } -#if CONFIG_PARLIO_RX_ISR_CACHE_SAFE - ESP_RETURN_ON_FALSE(esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM"); -#else - ESP_RETURN_ON_FALSE(recv_cfg->flags.indirect_mount || esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM"); -#endif if (recv_cfg->delimiter->eof_data_len) { ESP_RETURN_ON_FALSE(payload_size >= recv_cfg->delimiter->eof_data_len, ESP_ERR_INVALID_ARG, TAG, "payload size should be greater than eof_data_len"); diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c index b77bb8b403..11324074ea 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c @@ -548,6 +548,47 @@ TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]") free(payload); }; +TEST_CASE("parallel_rx_unit_receive_external_memory_test", "[parlio_rx]") +{ + parlio_rx_unit_handle_t rx_unit = NULL; + parlio_rx_delimiter_handle_t deli = NULL; + size_t payload_size = 1000; + + parlio_rx_unit_config_t config = TEST_DEFAULT_UNIT_CONFIG(PARLIO_CLK_SRC_DEFAULT, 1000000); + config.flags.free_clk = 1; + TEST_ESP_OK(parlio_new_rx_unit(&config, &rx_unit)); + + parlio_rx_soft_delimiter_config_t sft_deli_cfg = { + .sample_edge = PARLIO_SAMPLE_EDGE_POS, + .eof_data_len = payload_size, + .timeout_ticks = 0, + }; + TEST_ESP_OK(parlio_new_rx_soft_delimiter(&sft_deli_cfg, &deli)); + + TEST_ESP_OK(parlio_rx_unit_enable(rx_unit, true)); + + parlio_receive_config_t recv_config = { + .delimiter = deli, + .flags.partial_rx_en = false, + }; + + /* Do not specify alignment, check if the driver can work correctly */ + uint8_t *payload = heap_caps_calloc_prefer(1, payload_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM, TEST_PARLIO_DMA_MEM_ALLOC_CAPS); + printf("payload addr: %p size: %u\n", payload, payload_size); + TEST_ASSERT(payload); + + printf("Testing the external memory receive functionality...\n"); + TEST_ESP_OK(parlio_rx_soft_delimiter_start_stop(rx_unit, deli, true)); + TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, payload, payload_size, &recv_config)); + TEST_ESP_OK(parlio_rx_unit_wait_all_done(rx_unit, 5000)); + TEST_ESP_OK(parlio_rx_soft_delimiter_start_stop(rx_unit, deli, false)); + + TEST_ESP_OK(parlio_rx_unit_disable(rx_unit)); + TEST_ESP_OK(parlio_del_rx_delimiter(deli)); + TEST_ESP_OK(parlio_del_rx_unit(rx_unit)); + free(payload); +} + TEST_CASE("parallel_rx_unit_receive_timeout_test", "[parlio_rx]") { printf("init a gpio to simulate valid signal\r\n"); @@ -689,7 +730,7 @@ TEST_CASE("parallel_rx_unit_force_trigger_eof_test", "[parlio_rx]") uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); alignment = alignment < 4 ? 4 : alignment; size_t buff_size = ALIGN_UP(TEST_TASK_LARGE_TRANS_SIZE, alignment); - recv_buff = heap_caps_aligned_calloc(alignment, 1, buff_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS); + recv_buff = heap_caps_aligned_calloc(alignment, 1, buff_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); TEST_ASSERT_NOT_NULL(recv_buff); gpio_set_intr_type(TEST_VALID_GPIO, GPIO_INTR_NEGEDGE); From 695507d0ea3649158de218495499e6df055efbdb Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Mon, 10 Nov 2025 10:37:49 +0800 Subject: [PATCH 033/156] fix(parlio_rx): fixed incorrect dma buffer length calculation --- components/esp_driver_parlio/src/parlio_rx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index 3b023287ce..4c6b36adef 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -159,10 +159,10 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli /* Mount body buffer */ size_t mount_size = 0; size_t offset = 0; + size_t rest_size = trans->aligned_payload.buf.body.length; for (int i = head_node_num; i < required_node_num - tail_node_num; i++) { - size_t rest_size = trans->aligned_payload.buf.body.length - offset; if (rest_size >= 2 * PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { - mount_size = PARLIO_RX_MOUNT_SIZE_CALC(trans->aligned_payload.buf.body.length, body_node_num, trans->alignment); + mount_size = PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; } else if (rest_size <= PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { mount_size = (required_node_num - tail_node_num == 2) && (i == 0) ? PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, trans->alignment) : rest_size; } else { @@ -175,6 +175,7 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli mount_config[i].flags.mark_eof = false; mount_config[i].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT; offset += mount_size; + rest_size -= mount_size; } /* Mount tail buffer */ if (tail_node_num) { From 64f528c4341b60ea6b257206a6b9c5ea4ab7e3bc Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Mon, 10 Nov 2025 17:58:24 +0800 Subject: [PATCH 034/156] test(parlio): fix sleep test issue --- .../include/esp_private/parlio_rx_private.h | 16 ++++++++--- .../{parlio_private.h => parlio_tx_private.h} | 0 components/esp_driver_parlio/src/parlio_rx.c | 27 ++++++++++++------- .../test_apps/parlio/main/test_parlio_rx.c | 6 +++-- .../test_apps/parlio/main/test_parlio_sleep.c | 2 +- .../esp_lcd/parl/esp_lcd_panel_io_parl.c | 2 +- 6 files changed, 36 insertions(+), 17 deletions(-) rename components/esp_driver_parlio/include/esp_private/{parlio_private.h => parlio_tx_private.h} (100%) diff --git a/components/esp_driver_parlio/include/esp_private/parlio_rx_private.h b/components/esp_driver_parlio/include/esp_private/parlio_rx_private.h index 657237642b..9e74c61368 100644 --- a/components/esp_driver_parlio/include/esp_private/parlio_rx_private.h +++ b/components/esp_driver_parlio/include/esp_private/parlio_rx_private.h @@ -13,17 +13,27 @@ extern "C" { #endif /** - * @brief Force to trigger the EOF interrupt + * @brief Trigger the fake EOF interrupt * @note This function is a workaround for the case that level delimiter needs to receive more than 64KB data in one transaction. + * The hardware can't generate the EOF interrupt when the data length is greater than 64KB due to the limitation of the hardware, + * so this function is used to trigger the fake EOF interrupt. + * @note This function will reset the whole parlio module, + * If the pair tx unit is in using, + * the reset operation will affect the TX unit and lead to unknown behavior + * @usage If the application needs to receive more than 64KB data in one transaction, you can follow the steps below: + * 1. Create a level delimiter with a length greater than 64KB + * 2. Register the interrupt of the end edge on the valid GPIO + * 3. Call this function to trigger the fake EOF interrupt in the GPIO interrupt handler + * 4. Receive the transaction that is greater than 64KB * * @param rx_unit Parallel IO RX unit that created by `parlio_new_rx_unit` * @param need_yield Pointer to a status flag to record whether a task switch is needed if this API is being called in an ISR * @return - * - ESP_OK: Force to trigger the EOF interrupt successfully + * - ESP_OK: Trigger the fake EOF interrupt successfully * - ESP_ERR_INVALID_ARG: Invalid argument like NULL pointer * - ESP_ERR_INVALID_STATE: Tx unit is in using, can't be called when pair tx unit is in using */ -esp_err_t parlio_rx_unit_force_trigger_eof(parlio_rx_unit_handle_t rx_unit, bool *need_yield); +esp_err_t parlio_rx_unit_trigger_fake_eof(parlio_rx_unit_handle_t rx_unit, bool *need_yield); #ifdef __cplusplus } diff --git a/components/esp_driver_parlio/include/esp_private/parlio_private.h b/components/esp_driver_parlio/include/esp_private/parlio_tx_private.h similarity index 100% rename from components/esp_driver_parlio/include/esp_private/parlio_private.h rename to components/esp_driver_parlio/include/esp_private/parlio_tx_private.h diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index 4c6b36adef..3dcd2f1554 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -68,7 +68,8 @@ typedef struct parlio_rx_unit_t { size_t dma_burst_size; /*!< DMA burst size, in bytes */ gdma_link_list_handle_t dma_link; /*!< DMA link list handle */ uint32_t node_num; /*!< The number of nodes in the DMA link list */ - size_t dma_mem_align; /*!< Alignment for DMA memory */ + size_t int_mem_align; /*!< Alignment for internal memory */ + size_t ext_mem_align; /*!< Alignment for external memory */ uint32_t curr_node_id; /*!< The index of the current node in the DMA link list */ void *usr_recv_buf; /*!< The point to the user's receiving buffer */ /* Infinite transaction specific */ @@ -164,7 +165,7 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli if (rest_size >= 2 * PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { mount_size = PARLIO_MAX_ALIGNED_DMA_BUF_SIZE; } else if (rest_size <= PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) { - mount_size = (required_node_num - tail_node_num == 2) && (i == 0) ? PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, trans->alignment) : rest_size; + mount_size = ((required_node_num - tail_node_num) == 2) && (i == 0) ? PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, trans->alignment) : rest_size; } else { mount_size = PARLIO_RX_MOUNT_SIZE_CALC(rest_size, 2, trans->alignment); } @@ -406,7 +407,7 @@ static bool parlio_rx_default_desc_done_callback(gdma_channel_handle_t dma_chan, /* The sych length should be the cache line size for the un-aligned head and tail part */ for (int i = 0; i < 2; i++) { if (finished_buffer == rx_unit->stash_buf[i]) { - sync_size = rx_unit->dma_mem_align; + sync_size = rx_unit->int_mem_align; break; } } @@ -451,7 +452,7 @@ static esp_err_t parlio_rx_create_dma_link(parlio_rx_unit_handle_t rx_unit, uint esp_err_t ret = ESP_OK; // calculated the total node number, add 2 for the aligned stash buffer - size_t tot_node_num = esp_dma_calculate_node_count(max_recv_size, rx_unit->dma_mem_align, PARLIO_DMA_DESCRIPTOR_BUFFER_MAX_SIZE) + 2; + size_t tot_node_num = esp_dma_calculate_node_count(max_recv_size, rx_unit->int_mem_align, PARLIO_DMA_DESCRIPTOR_BUFFER_MAX_SIZE) + 2; gdma_link_list_config_t dma_link_config = { .num_items = tot_node_num, .item_alignment = PARLIO_DMA_DESC_ALIGNMENT, @@ -487,13 +488,16 @@ static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit, size_t rx_unit->dma_burst_size = dma_burst_size ? dma_burst_size : 16; gdma_transfer_config_t trans_cfg = { .max_data_burst_size = rx_unit->dma_burst_size, // Enable DMA burst transfer for better performance, + .access_ext_mem = true, }; ESP_RETURN_ON_ERROR(gdma_config_transfer(rx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); - ESP_RETURN_ON_ERROR(gdma_get_alignment_constraints(rx_unit->dma_chan, &rx_unit->dma_mem_align, NULL), TAG, "get alignment constraints failed"); + ESP_RETURN_ON_ERROR(gdma_get_alignment_constraints(rx_unit->dma_chan, &rx_unit->int_mem_align, &rx_unit->ext_mem_align), TAG, "get alignment constraints failed"); #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); - rx_unit->dma_mem_align = rx_unit->dma_mem_align > cache_line_size ? rx_unit->dma_mem_align : cache_line_size; + rx_unit->int_mem_align = rx_unit->int_mem_align > cache_line_size ? rx_unit->int_mem_align : cache_line_size; #endif + uint32_t ext_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA); + rx_unit->ext_mem_align = rx_unit->ext_mem_align > ext_cache_line_size ? rx_unit->ext_mem_align : ext_cache_line_size; /* Register callbacks */ gdma_rx_event_callbacks_t cbs = { @@ -674,7 +678,8 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un ESP_GOTO_ON_ERROR(parlio_rx_create_dma_link(unit, config->max_recv_size), err, TAG, "create dma link list failed"); for (uint8_t i = 0; i < 2; i++) { - unit->stash_buf[i] = heap_caps_aligned_calloc(unit->dma_mem_align, 2, unit->dma_mem_align, PARLIO_MEM_ALLOC_CAPS | MALLOC_CAP_DMA); + uint32_t max_alignment = unit->int_mem_align > unit->ext_mem_align ? unit->int_mem_align : unit->ext_mem_align; + unit->stash_buf[i] = heap_caps_aligned_calloc(max_alignment, 2, max_alignment, PARLIO_MEM_ALLOC_CAPS | MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(unit->stash_buf[i], ESP_ERR_NO_MEM, err, TAG, "no memory for stash buffer"); } @@ -767,7 +772,7 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu assert(res == pdTRUE); if (trans.flags.indirect_mount && trans.flags.infinite && rx_unit->dma_buf == NULL) { - rx_unit->dma_buf = heap_caps_aligned_calloc(rx_unit->dma_mem_align, 1, trans.aligned_payload.buf.body.length, PARLIO_DMA_MEM_ALLOC_CAPS); + rx_unit->dma_buf = heap_caps_aligned_calloc(rx_unit->int_mem_align, 1, trans.aligned_payload.buf.body.length, PARLIO_DMA_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(rx_unit->dma_buf, ESP_ERR_NO_MEM, err, TAG, "No memory for the internal DMA buffer"); trans.aligned_payload.buf.body.aligned_buffer = rx_unit->dma_buf; trans.aligned_payload.buf.body.recovery_address = rx_unit->dma_buf; @@ -992,7 +997,7 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit, ESP_RETURN_ON_FALSE(rx_unit && payload && recv_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(recv_cfg->delimiter, ESP_ERR_INVALID_ARG, TAG, "no delimiter specified"); ESP_RETURN_ON_FALSE(payload_size <= rx_unit->max_recv_size, ESP_ERR_INVALID_ARG, TAG, "trans length too large"); - size_t alignment = rx_unit->dma_mem_align; + size_t alignment = rx_unit->int_mem_align; if (recv_cfg->flags.partial_rx_en) { ESP_RETURN_ON_FALSE(payload_size >= 2 * alignment, ESP_ERR_INVALID_ARG, TAG, "The payload size should greater than %"PRIu32, 2 * alignment); } @@ -1088,7 +1093,7 @@ err: return ret; } -esp_err_t parlio_rx_unit_force_trigger_eof(parlio_rx_unit_handle_t rx_unit, bool *need_yield) +esp_err_t parlio_rx_unit_trigger_fake_eof(parlio_rx_unit_handle_t rx_unit, bool *need_yield) { ESP_RETURN_ON_FALSE_ISR(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); @@ -1104,6 +1109,7 @@ esp_err_t parlio_rx_unit_force_trigger_eof(parlio_rx_unit_handle_t rx_unit, bool ESP_RETURN_ON_ERROR_ISR(gdma_reset(rx_unit->dma_chan), TAG, "reset DMA channel failed"); parlio_hal_context_t *hal = &rx_unit->base.group->hal; + portENTER_CRITICAL_SAFE(&s_rx_spinlock); /* Save the current register values */ parl_io_dev_t save_curr_regs = *(parl_io_dev_t *)hal->regs; /* Reset the hardware FSM of the parlio module */ @@ -1114,6 +1120,7 @@ esp_err_t parlio_rx_unit_force_trigger_eof(parlio_rx_unit_handle_t rx_unit, bool PARLIO_CLOCK_SRC_ATOMIC() { parlio_ll_rx_set_clock_source(hal->regs, PARLIO_CLK_SRC_DEFAULT); } + portEXIT_CRITICAL_SAFE(&s_rx_spinlock); /* Restore the register values and clock source*/ memcpy(hal->regs, &save_curr_regs, sizeof(parl_io_dev_t)); parlio_ll_rx_update_config(hal->regs); diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c index 11324074ea..138637e62f 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_rx.c @@ -548,6 +548,7 @@ TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]") free(payload); }; +#if SOC_PSRAM_DMA_CAPABLE TEST_CASE("parallel_rx_unit_receive_external_memory_test", "[parlio_rx]") { parlio_rx_unit_handle_t rx_unit = NULL; @@ -588,6 +589,7 @@ TEST_CASE("parallel_rx_unit_receive_external_memory_test", "[parlio_rx]") TEST_ESP_OK(parlio_del_rx_unit(rx_unit)); free(payload); } +#endif // SOC_PSRAM_DMA_CAPABLE TEST_CASE("parallel_rx_unit_receive_timeout_test", "[parlio_rx]") { @@ -677,7 +679,7 @@ static void test_gpio_neg_edge_intr(void *arg) { parlio_rx_unit_handle_t rx_unit = (parlio_rx_unit_handle_t)arg; bool need_yield = false; - parlio_rx_unit_force_trigger_eof(rx_unit, &need_yield); + parlio_rx_unit_trigger_fake_eof(rx_unit, &need_yield); if (need_yield) { portYIELD_FROM_ISR(); } @@ -730,7 +732,7 @@ TEST_CASE("parallel_rx_unit_force_trigger_eof_test", "[parlio_rx]") uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); alignment = alignment < 4 ? 4 : alignment; size_t buff_size = ALIGN_UP(TEST_TASK_LARGE_TRANS_SIZE, alignment); - recv_buff = heap_caps_aligned_calloc(alignment, 1, buff_size, MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); + recv_buff = heap_caps_aligned_calloc(alignment, 1, buff_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS); TEST_ASSERT_NOT_NULL(recv_buff); gpio_set_intr_type(TEST_VALID_GPIO, GPIO_INTR_NEGEDGE); diff --git a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c index 8fc99cd40a..e035b48bea 100644 --- a/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c +++ b/components/esp_driver_parlio/test_apps/parlio/main/test_parlio_sleep.c @@ -94,7 +94,7 @@ static void test_parlio_sleep_retention(bool allow_pd) parlio_rx_level_delimiter_config_t lvl_deli_cfg = { .valid_sig_line_id = PARLIO_RX_UNIT_MAX_DATA_WIDTH - 1, - .sample_edge = PARLIO_SAMPLE_EDGE_POS, + .sample_edge = PARLIO_SAMPLE_EDGE_NEG, // opposite to tx unit in case of timing issue .bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB, .eof_data_len = TEST_PAYLOAD_SIZE, .timeout_ticks = 0, diff --git a/components/esp_lcd/parl/esp_lcd_panel_io_parl.c b/components/esp_lcd/parl/esp_lcd_panel_io_parl.c index 1d96b03518..efdba5926a 100644 --- a/components/esp_lcd/parl/esp_lcd_panel_io_parl.c +++ b/components/esp_lcd/parl/esp_lcd_panel_io_parl.c @@ -33,7 +33,7 @@ #include "driver/parlio_tx.h" #include "driver/parlio_types.h" #include "esp_private/gpio.h" -#include "esp_private/parlio_private.h" +#include "esp_private/parlio_tx_private.h" #include "esp_lcd_panel_io_interface.h" #include "esp_lcd_panel_io.h" #include "esp_lcd_common.h" From b8f60d7a1749a830511a5d6b33e9cf63ab200736 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Tue, 25 Nov 2025 12:15:34 +0800 Subject: [PATCH 035/156] fix(i2s): fix the auto port failure when use simplex on ESP32 --- components/esp_driver_i2s/i2s_common.c | 36 +++++++++ components/esp_driver_i2s/i2s_private.h | 14 ++++ components/esp_driver_i2s/i2s_std.c | 31 ++++++-- components/esp_driver_i2s/i2s_tdm.c | 2 + .../test_apps/i2s/main/test_i2s.c | 73 ++++++++++++++++++- 5 files changed, 150 insertions(+), 6 deletions(-) diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index b54402cb50..b1da9d1cae 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -371,6 +371,40 @@ err: return ret; } +#if SOC_I2S_HW_VERSION_1 +esp_err_t i2s_channel_change_port(i2s_chan_handle_t handle, int id) +{ + I2S_NULL_POINTER_CHECK(TAG, handle); + ESP_RETURN_ON_FALSE(id >= 0 && id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid I2S port id"); + if (id == handle->controller->id) { + return ESP_OK; + } + i2s_controller_t *i2s_obj = i2s_acquire_controller_obj(id); + if (!i2s_obj || !i2s_take_available_channel(i2s_obj, handle->dir)) { + return ESP_ERR_NOT_FOUND; + } + i2s_controller_t *old_i2s_obj = handle->controller; + portENTER_CRITICAL(&g_i2s.spinlock); + if (handle->dir == I2S_DIR_TX) { + i2s_obj->tx_chan = handle; + i2s_obj->chan_occupancy |= I2S_DIR_TX; + old_i2s_obj->tx_chan = NULL; + old_i2s_obj->full_duplex = false; + old_i2s_obj->chan_occupancy &= ~I2S_DIR_TX; + } else { + i2s_obj->rx_chan = handle; + i2s_obj->chan_occupancy |= I2S_DIR_RX; + old_i2s_obj->rx_chan = NULL; + old_i2s_obj->full_duplex = false; + old_i2s_obj->chan_occupancy &= ~I2S_DIR_RX; + } + handle->controller = i2s_obj; + portEXIT_CRITICAL(&g_i2s.spinlock); + + return ESP_OK; +} +#endif + #ifndef __cplusplus /* To make sure the i2s_event_callbacks_t is same size as i2s_event_callbacks_internal_t */ _Static_assert(sizeof(i2s_event_callbacks_t) == sizeof(i2s_event_callbacks_internal_t), "Invalid size of i2s_event_callbacks_t structure"); @@ -1001,6 +1035,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_TX, chan_cfg->dma_desc_num), err, TAG, "register I2S tx channel failed"); i2s_obj->tx_chan->role = chan_cfg->role; + i2s_obj->tx_chan->is_port_auto = id == I2S_NUM_AUTO; i2s_obj->tx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; i2s_obj->tx_chan->dma.auto_clear_after_cb = chan_cfg->auto_clear_after_cb; i2s_obj->tx_chan->dma.auto_clear_before_cb = chan_cfg->auto_clear_before_cb; @@ -1016,6 +1051,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t * ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_RX, chan_cfg->dma_desc_num), err, TAG, "register I2S rx channel failed"); i2s_obj->rx_chan->role = chan_cfg->role; + i2s_obj->rx_chan->is_port_auto = id == I2S_NUM_AUTO; i2s_obj->rx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED; i2s_obj->rx_chan->dma.desc_num = chan_cfg->dma_desc_num; i2s_obj->rx_chan->dma.frame_num = chan_cfg->dma_frame_num; diff --git a/components/esp_driver_i2s/i2s_private.h b/components/esp_driver_i2s/i2s_private.h index b734f650d8..fdd697fcf8 100644 --- a/components/esp_driver_i2s/i2s_private.h +++ b/components/esp_driver_i2s/i2s_private.h @@ -160,6 +160,7 @@ struct i2s_channel_obj_t { int intr_prio_flags;/*!< i2s interrupt priority flags */ void *mode_info; /*!< Slot, clock and gpio information of each mode */ struct { + bool is_port_auto: 1; /*!< Whether the port is auto-assigned */ bool is_etm_start: 1; /*!< Whether start by etm tasks */ bool is_etm_stop: 1; /*!< Whether stop by etm tasks */ bool is_raw_pdm: 1; /*!< Flag of whether send/receive PDM in raw data, i.e., no PCM2PDM/PDM2PCM filter enabled */ @@ -340,6 +341,19 @@ void i2s_output_gpio_reserve(i2s_chan_handle_t handle, int gpio_num); */ void i2s_output_gpio_revoke(i2s_chan_handle_t handle, uint64_t gpio_mask); +#if SOC_I2S_HW_VERSION_1 +/** + * @brief Change the port of the I2S channel + * + * @param handle I2S channel handle + * @param id I2S port id + * @return + * - ESP_OK Change port success + * - ESP_ERR_NOT_FOUND No available I2S port found + */ +esp_err_t i2s_channel_change_port(i2s_chan_handle_t handle, int id); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_driver_i2s/i2s_std.c b/components/esp_driver_i2s/i2s_std.c index 297001eeb4..9f8ce6abce 100644 --- a/components/esp_driver_i2s/i2s_std.c +++ b/components/esp_driver_i2s/i2s_std.c @@ -251,13 +251,34 @@ static esp_err_t s_i2s_channel_try_to_constitude_std_duplex(i2s_chan_handle_t ha if (memcmp(another_handle->mode_info, &curr_cfg, sizeof(i2s_std_config_t)) == 0) { handle->controller->full_duplex = true; ESP_LOGD(TAG, "Constitude full-duplex on port %d", handle->controller->id); - } + } else { #if SOC_I2S_HW_VERSION_1 - else { - ESP_LOGE(TAG, "Can't set different channel configurations on a same port"); - return ESP_ERR_INVALID_ARG; - } + bool port_changed = false; + if (handle->is_port_auto) { + ESP_LOGD(TAG, "TX & RX on I2S%d are simplex", handle->controller->id); + for (int i = 0; i < SOC_I2S_NUM; i++) { + if (i == handle->controller->id) { + continue; + } + ESP_LOGD(TAG, "Trying to move %s channel from port %d to %d", + handle->dir == I2S_DIR_TX ? "TX" : "RX", handle->controller->id, i); + if (i2s_channel_change_port(handle, i) == ESP_OK) { + ESP_LOGD(TAG, "Move success!"); + port_changed = true; + break; + } else { + ESP_LOGD(TAG, "Move failed..."); + } + } + } + if (!port_changed) { + ESP_LOGE(TAG, "Can't set different channel configurations on a same port"); + return ESP_ERR_INVALID_ARG; + } +#else + ESP_LOGD(TAG, "TX & RX on I2S%d are simplex", handle->controller->id); #endif + } } /* Switch to the slave role if needed */ if (handle->controller->full_duplex && diff --git a/components/esp_driver_i2s/i2s_tdm.c b/components/esp_driver_i2s/i2s_tdm.c index 6c5bad5e55..b6ce716a2e 100644 --- a/components/esp_driver_i2s/i2s_tdm.c +++ b/components/esp_driver_i2s/i2s_tdm.c @@ -255,6 +255,8 @@ static void s_i2s_channel_try_to_constitude_tdm_duplex(i2s_chan_handle_t handle, if (memcmp(another_handle->mode_info, &curr_cfg, sizeof(i2s_tdm_config_t)) == 0) { handle->controller->full_duplex = true; ESP_LOGD(TAG, "Constitude full-duplex on port %d", handle->controller->id); + } else { + ESP_LOGD(TAG, "TX & RX on I2S%d are simplex", handle->controller->id); } } /* Switch to the slave role if needed */ diff --git a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c index e8ede206bb..eb44a62e7f 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_i2s.c @@ -238,6 +238,8 @@ TEST_CASE("I2S_basic_channel_allocation_reconfig_deleting_test", "[i2s]") } static volatile bool task_run_flag; +static volatile bool read_task_success = true; +static volatile bool write_task_success = true; #define TEST_I2S_DATA 0x78 @@ -270,6 +272,7 @@ static void i2s_read_task(void *args) ret = i2s_channel_read(rx_handle, recv_buf, 2000, &recv_size, 300); if (ret == ESP_ERR_TIMEOUT) { printf("Read timeout count: %"PRIu32"\n", cnt++); + read_task_success = false; } } @@ -291,6 +294,7 @@ static void i2s_write_task(void *args) ret = i2s_channel_write(tx_handle, send_buf, 2000, &send_size, 300); if (ret == ESP_ERR_TIMEOUT) { printf("Write timeout count: %"PRIu32"\n", cnt++); + write_task_success = false; } } @@ -431,6 +435,7 @@ TEST_CASE("I2S_lazy_duplex_test", "[i2s]") }, }, }; + /* Part 1: test common lazy duplex mode */ TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, NULL)); TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); TEST_ESP_OK(i2s_channel_enable(tx_handle)); @@ -451,7 +456,7 @@ TEST_CASE("I2S_lazy_duplex_test", "[i2s]") xTaskCreate(i2s_read_check_task, "i2s_read_check_task", 4096, rx_handle, 5, NULL); printf("RX started\n"); - /* Wait 3 seconds to see if any failures occur */ + /* Wait 1 seconds to see if any failures occur */ vTaskDelay(pdMS_TO_TICKS(1000)); printf("Finished\n"); @@ -467,6 +472,72 @@ TEST_CASE("I2S_lazy_duplex_test", "[i2s]") /* Delete the channels */ TEST_ESP_OK(i2s_del_channel(tx_handle)); TEST_ESP_OK(i2s_del_channel(rx_handle)); + + /* Part 2: Test no lazy duplex mode with port auto assignment */ + chan_cfg.id = I2S_NUM_AUTO; + TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle)); + TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, NULL)); + TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg)); + + /* Change the config to not constitute full-duplex */ + std_cfg.gpio_cfg.mclk = I2S_GPIO_UNUSED; + std_cfg.gpio_cfg.bclk = I2S_GPIO_UNUSED; + std_cfg.gpio_cfg.ws = I2S_GPIO_UNUSED; + std_cfg.gpio_cfg.dout = I2S_GPIO_UNUSED; + std_cfg.gpio_cfg.din = I2S_GPIO_UNUSED; +#if CONFIG_IDF_TARGET_ESP32S2 + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, i2s_channel_init_std_mode(tx_handle, &std_cfg)); + /* Delete the channels */ + TEST_ESP_OK(i2s_del_channel(tx_handle)); + TEST_ESP_OK(i2s_del_channel(rx_handle)); + return; +#else + TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg)); +#endif + +#if CONFIG_IDF_TARGET_ESP32 + /* On ESP32, if failed to constitute full-duplex with `I2S_NUM_AUTO`, + the channel will be re-assigned to the next availableport */ + i2s_chan_info_t chan_info; + TEST_ESP_OK(i2s_channel_get_info(rx_handle, &chan_info)); + TEST_ASSERT(chan_info.id == I2S_NUM_0); + TEST_ESP_OK(i2s_channel_get_info(tx_handle, &chan_info)); + TEST_ASSERT(chan_info.id == I2S_NUM_1); +#endif + + TEST_ESP_OK(i2s_channel_enable(tx_handle)); + TEST_ESP_OK(i2s_channel_enable(rx_handle)); + + task_run_flag = true; + read_task_success = true; + write_task_success = true; + /* writing task to keep writing */ + xTaskCreate(i2s_write_task, "i2s_write_task", 4096, tx_handle, 5, NULL); + printf("TX started\n"); + vTaskDelay(pdMS_TO_TICKS(1000)); + /* reading task to keep reading */ + xTaskCreate(i2s_read_task, "i2s_read_task", 4096, rx_handle, 5, NULL); + printf("RX started\n"); + + /* Wait 1 seconds to see if any failures occur */ + vTaskDelay(pdMS_TO_TICKS(1000)); + printf("Finished\n"); + + /* Stop those three tasks */ + task_run_flag = false; + + /* Wait for the three thread deleted */ + vTaskDelay(pdMS_TO_TICKS(1000)); + + /* Disable the channels, they will keep waiting until the current reading / writing finished */ + TEST_ESP_OK(i2s_channel_disable(tx_handle)); + TEST_ESP_OK(i2s_channel_disable(rx_handle)); + /* Delete the channels */ + TEST_ESP_OK(i2s_del_channel(tx_handle)); + TEST_ESP_OK(i2s_del_channel(rx_handle)); + /* Check if the reading and writing tasks are successful */ + TEST_ASSERT(read_task_success); + TEST_ASSERT(write_task_success); } static bool whether_contains_exapected_data(uint16_t *src, uint32_t src_len, uint32_t src_step, uint32_t start_val, uint32_t val_step) From 7738c4f7332160cab76ee2491c9b66bc010c2503 Mon Sep 17 00:00:00 2001 From: Shen Wei Long Date: Fri, 28 Nov 2025 09:06:14 +0000 Subject: [PATCH 036/156] change(ble): Updated the maximum number of concurrent connections to 70 on ESP32-H2 (cherry picked from commit cd33f13521179656817840f5a3743a60e2c28b3f) Co-authored-by: ShenWeilong --- components/bt/controller/esp32h2/Kconfig.in | 2 +- components/bt/host/nimble/Kconfig.in | 3 +-- .../ble_multi_conn_cent/sdkconfig.defaults.esp32h2 | 6 ------ .../ble_multi_conn_prph/sdkconfig.defaults.esp32h2 | 5 ----- 4 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/sdkconfig.defaults.esp32h2 delete mode 100644 examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/sdkconfig.defaults.esp32h2 diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index 17a1d9abf2..00724367d1 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -573,7 +573,7 @@ config BT_LE_LL_PEER_SCA config BT_LE_MAX_CONNECTIONS int "Maximum number of concurrent connections" depends on !BT_NIMBLE_ENABLED - range 1 35 + range 1 70 default 3 help Defines maximum number of concurrent BLE connections. For ESP32, user diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index d816de1840..41498e6a3a 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -247,8 +247,7 @@ menu "GAP / GATT / Device Settings" config BT_NIMBLE_MAX_CONNECTIONS int "Maximum number of concurrent connections" range 1 2 if IDF_TARGET_ESP32C2 - range 1 70 if IDF_TARGET_ESP32C6 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C61 - range 1 35 if IDF_TARGET_ESP32H2 + range 1 70 if SOC_ESP_NIMBLE_CONTROLLER range 1 9 default 2 if IDF_TARGET_ESP32C2 default 3 diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/sdkconfig.defaults.esp32h2 b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/sdkconfig.defaults.esp32h2 deleted file mode 100644 index e30be10c13..0000000000 --- a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_cent/sdkconfig.defaults.esp32h2 +++ /dev/null @@ -1,6 +0,0 @@ -# This file was generated using idf.py save-defconfig. It can be edited manually. -# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration -# -CONFIG_BT_NIMBLE_MAX_CONNECTIONS=35 -CONFIG_BT_NIMBLE_GATT_MAX_PROCS=35 -CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=50 diff --git a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/sdkconfig.defaults.esp32h2 b/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/sdkconfig.defaults.esp32h2 deleted file mode 100644 index f0cb07854e..0000000000 --- a/examples/bluetooth/nimble/ble_multi_conn/ble_multi_conn_prph/sdkconfig.defaults.esp32h2 +++ /dev/null @@ -1,5 +0,0 @@ -# This file was generated using idf.py save-defconfig. It can be edited manually. -# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration -# -CONFIG_BT_NIMBLE_MAX_CONNECTIONS=34 -CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=50 From f8c75d15bbc7a02ae023df8346182e6d67fd9240 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Fri, 28 Nov 2025 21:26:02 +0100 Subject: [PATCH 037/156] fix(app_trace): prevent possible system crash on uart buffer access --- components/app_trace/port/port_uart.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/components/app_trace/port/port_uart.c b/components/app_trace/port/port_uart.c index c4146d09d3..3761bc9046 100644 --- a/components/app_trace/port/port_uart.c +++ b/components/app_trace/port/port_uart.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -295,10 +295,9 @@ static esp_err_t esp_apptrace_uart_up_buffer_put(esp_apptrace_uart_data_t *hw_da static void esp_apptrace_uart_down_buffer_config(esp_apptrace_uart_data_t *hw_data, uint8_t *buf, uint32_t size) { - hw_data->down_buffer = (uint8_t *)malloc(size); - if (hw_data->down_buffer == NULL){ - assert(false && "Failed to allocate apptrace uart down buffer!"); - } + assert(buf != NULL && "Down buffer cannot be NULL"); + + hw_data->down_buffer = buf; hw_data->down_buffer_size = size; } From 26b91fc2620dbbc5d8468d41a382b7a9155fc2e2 Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Thu, 20 Nov 2025 14:02:53 +0800 Subject: [PATCH 038/156] feat(hw_support): add config version for c5 v1.2 --- components/esp_hw_support/port/esp32c5/Kconfig.hw_support | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esp_hw_support/port/esp32c5/Kconfig.hw_support b/components/esp_hw_support/port/esp32c5/Kconfig.hw_support index f5bc18b3b7..d90eb136f3 100644 --- a/components/esp_hw_support/port/esp32c5/Kconfig.hw_support +++ b/components/esp_hw_support/port/esp32c5/Kconfig.hw_support @@ -11,11 +11,14 @@ choice ESP32C5_REV_MIN config ESP32C5_REV_MIN_100 bool "Rev v1.0 (ECO2)" + config ESP32C5_REV_MIN_102 + bool "Rev v1.2" endchoice config ESP32C5_REV_MIN_FULL int default 100 if ESP32C5_REV_MIN_100 + default 102 if ESP32C5_REV_MIN_102 config ESP_REV_MIN_FULL int From 625c96675e0c4275e9926f84849f7694d85423cf Mon Sep 17 00:00:00 2001 From: Xiao Xufeng Date: Thu, 20 Nov 2025 14:03:08 +0800 Subject: [PATCH 039/156] feat(hw_support): add config version for c61 v1.1 --- components/esp_hw_support/port/esp32c61/Kconfig.hw_support | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/esp_hw_support/port/esp32c61/Kconfig.hw_support b/components/esp_hw_support/port/esp32c61/Kconfig.hw_support index 71e247da35..754f14c975 100644 --- a/components/esp_hw_support/port/esp32c61/Kconfig.hw_support +++ b/components/esp_hw_support/port/esp32c61/Kconfig.hw_support @@ -11,11 +11,14 @@ choice ESP32C61_REV_MIN config ESP32C61_REV_MIN_100 bool "Rev v1.0" + config ESP32C61_REV_MIN_101 + bool "Rev v1.1" endchoice config ESP32C61_REV_MIN_FULL int default 100 if ESP32C61_REV_MIN_100 + default 101 if ESP32C61_REV_MIN_101 config ESP_REV_MIN_FULL int From b940b46af1b0e93df653bec30f31e98a394c47d0 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Mon, 1 Dec 2025 11:10:35 +0800 Subject: [PATCH 040/156] fix(ble): put ble_log_write_hex in iram to avoid cache error (cherry picked from commit dc4e41fab83ff2bebb89f02b77e83fc221101f71) Co-authored-by: Zhou Xiao --- components/bt/common/ble_log/src/ble_log_lbm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/bt/common/ble_log/src/ble_log_lbm.c b/components/bt/common/ble_log/src/ble_log_lbm.c index 5078f2bad7..9b8626d1ad 100644 --- a/components/bt/common/ble_log/src/ble_log_lbm.c +++ b/components/bt/common/ble_log/src/ble_log_lbm.c @@ -421,6 +421,7 @@ deref: BLE_LOG_REF_COUNT_RELEASE(&lbm_ref_count); } +BLE_LOG_IRAM_ATTR bool ble_log_write_hex(ble_log_src_t src_code, const uint8_t *addr, size_t len) { BLE_LOG_REF_COUNT_ACQUIRE(&lbm_ref_count); From 63ceae8dd9d121799073ae5f1b4e682905ff1369 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Mon, 1 Dec 2025 11:10:35 +0800 Subject: [PATCH 041/156] feat(ble): enabled lc get time for ceva controller (cherry picked from commit 6924b8b372e6fca15e2f1b49f895f3e95ff131c2) Co-authored-by: Zhou Xiao --- .../bt/common/ble_log/src/internal_include/ble_log_ts.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/bt/common/ble_log/src/internal_include/ble_log_ts.h b/components/bt/common/ble_log/src/internal_include/ble_log_ts.h index 11e74e1508..5e0864b258 100644 --- a/components/bt/common/ble_log/src/internal_include/ble_log_ts.h +++ b/components/bt/common/ble_log/src/internal_include/ble_log_ts.h @@ -29,10 +29,10 @@ extern uint32_t r_ble_lll_timer_current_tick_get(void); #elif defined(CONFIG_IDF_TARGET_ESP32C2) extern uint32_t r_os_cputime_get32(void); #define BLE_LOG_GET_LC_TS r_os_cputime_get32() -/* Legacy BLE Controller (Wait for support) */ -// #elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) -// extern uint32_t lld_read_clock_us(void); -// #define BLE_LOG_GET_LC_TS lld_read_clock_us() +/* Legacy BLE Controller */ +#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) +extern uint32_t lld_read_clock_us(void); +#define BLE_LOG_GET_LC_TS lld_read_clock_us() #else /* Other targets */ #define BLE_LOG_GET_LC_TS 0 #endif /* BLE targets */ From 46c10bb9f901967db8fefbad0d06da164a05e484 Mon Sep 17 00:00:00 2001 From: yangfeng Date: Thu, 27 Nov 2025 14:22:04 +0800 Subject: [PATCH 042/156] fix(bt/bluedroid): Fix the status judgment of the A2DP source registration SEP --- components/bt/host/bluedroid/api/esp_a2dp_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/api/esp_a2dp_api.c b/components/bt/host/bluedroid/api/esp_a2dp_api.c index 254c43d5a3..e6761835d8 100644 --- a/components/bt/host/bluedroid/api/esp_a2dp_api.c +++ b/components/bt/host/bluedroid/api/esp_a2dp_api.c @@ -356,7 +356,7 @@ esp_err_t esp_a2d_source_register_stream_endpoint(uint8_t seid, const esp_a2d_mc return ESP_ERR_INVALID_STATE; } - if (g_a2dp_on_deinit || g_a2dp_sink_ongoing_deinit) { + if (g_a2dp_on_deinit || g_a2dp_source_ongoing_deinit) { return ESP_ERR_INVALID_STATE; } From 3fe406aa9223b8807861226e657b8b2c1369c314 Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Thu, 20 Nov 2025 14:40:12 +0100 Subject: [PATCH 043/156] feat(ci): updated Ethernet tests to align with new runners --- .../esp_eth/test_apps/main/esp_eth_test_l2.c | 2 +- .../esp_eth/test_apps/pytest_esp_eth.py | 24 ++--- .../network/bridge/pytest_example_bridge.py | 97 +++++++++++++------ .../l2tap/pytest_example_l2tap_echo.py | 38 +++++--- .../udp_multicast/pytest_udp_multicast.py | 20 ++-- 5 files changed, 117 insertions(+), 64 deletions(-) diff --git a/components/esp_eth/test_apps/main/esp_eth_test_l2.c b/components/esp_eth/test_apps/main/esp_eth_test_l2.c index 4f88c318ba..76220242e4 100644 --- a/components/esp_eth/test_apps/main/esp_eth_test_l2.c +++ b/components/esp_eth/test_apps/main/esp_eth_test_l2.c @@ -642,7 +642,7 @@ TEST_CASE("heap utilization", "[ethernet_l2]") } #define FORMAT_MAC(mac_addr, a, b, c, d, e, f) do { mac_addr[0] = a; mac_addr[1] = b; mac_addr[2] = c; mac_addr[3] = d; mac_addr[4] = e; mac_addr[5] = f; } while(0) -TEST_CASE("w5500_multicast_filter", "[ethernet_l2]") +TEST_CASE("multicast_filter", "[ethernet_l2]") { esp_eth_mac_t *mac = mac_init(NULL, NULL); TEST_ASSERT_NOT_NULL(mac); diff --git a/components/esp_eth/test_apps/pytest_esp_eth.py b/components/esp_eth/test_apps/pytest_esp_eth.py index 4a2b4003cc..5b897f51cd 100644 --- a/components/esp_eth/test_apps/pytest_esp_eth.py +++ b/components/esp_eth/test_apps/pytest_esp_eth.py @@ -31,16 +31,18 @@ class EthTestIntf(object): netifs.sort(reverse=True) logging.info('detected interfaces: %s', str(netifs)) - for netif in netifs: - # if no interface defined, try to find it automatically - if my_if == '': - if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: - self.target_if = netif - break + if my_if == '': + if 'dut_p1' in netifs: + self.target_if = 'dut_p1' else: - if netif.find(my_if) == 0: - self.target_if = my_if - break + for netif in netifs: + # if no interface defined, try to find it automatically + if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: + self.target_if = netif + break + elif my_if in netifs: + self.target_if = my_if + if self.target_if == '': raise RuntimeError('network interface not found') logging.info('Use %s for testing', self.target_if) @@ -132,8 +134,8 @@ def ethernet_int_emac_test(dut: IdfDut) -> None: dut.run_all_single_board_cases(group='esp_emac', timeout=240) -def ethernet_l2_test(dut: IdfDut) -> None: - target_if = EthTestIntf(ETH_TYPE) +def ethernet_l2_test(dut: IdfDut, test_if: str = '') -> None: + target_if = EthTestIntf(ETH_TYPE, test_if) dut.expect_exact('Press ENTER to see the list of tests') dut.write('\n') diff --git a/examples/network/bridge/pytest_example_bridge.py b/examples/network/bridge/pytest_example_bridge.py index 765e37c41d..861005a582 100644 --- a/examples/network/bridge/pytest_example_bridge.py +++ b/examples/network/bridge/pytest_example_bridge.py @@ -11,8 +11,11 @@ import subprocess import time from concurrent.futures import Future from concurrent.futures import ThreadPoolExecutor +from typing import Generator from typing import List +from typing import Match from typing import Optional +from typing import Tuple from typing import Union import netifaces @@ -276,28 +279,38 @@ def send_brcast_msg_endnode_to_host(endnode: EndnodeSsh, host_brcast_ip: str, te return nc_host_out -@pytest.mark.eth_w5500 -@pytest.mark.parametrize( - 'config', - [ - 'w5500', - ], - indirect=True, -) -@idf_parametrize('target', ['esp32'], indirect=['target']) -def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: +def get_legacy_host_name_match() -> Optional[Match[str]]: + host_name = socket.gethostname() + regex = r'ethVM-(\d+)-(\d+)' + host_name_match = re.search(regex, host_name, re.DOTALL) + return host_name_match + + +def get_host_info() -> Tuple[int, int]: + # Get switch configuration info from the hostname (legacy runners) + sw_info = get_legacy_host_name_match() + if sw_info is not None: + sw_num = int(sw_info.group(1)) + port_num = int(sw_info.group(2)) + return sw_num, port_num + else: + # Get switch configuration info from the IP address of the `switch` interface (new runners) + switch_if_ip = get_host_ip_by_interface('switch', netifaces.AF_INET) + # Parse IP address: x.y.. + ip_parts = switch_if_ip.split('.') + if len(ip_parts) == 4: + sw_num = int(ip_parts[2]) + port_num = int(ip_parts[3]) + return sw_num, port_num + else: + raise RuntimeError('Unexpected switch IP address') + + +def eth_bridge_test(dut: Dut, dev_user: str, dev_password: str) -> None: # ------------------------------ # # Pre-test testbed configuration # # ------------------------------ # - # Get switch configuration info from the hostname - host_name = socket.gethostname() - regex = r'ethVM-(\d+)-(\d+)' - sw_info = re.search(regex, host_name, re.DOTALL) - if sw_info is None: - raise RuntimeError('Unexpected hostname') - - sw_num = int(sw_info.group(1)) - port_num = int(sw_info.group(2)) + sw_num, port_num = get_host_info() port_num_endnode = int(port_num) + 1 # endnode address is always + 1 to the host endnode = EndnodeSsh(f'10.10.{sw_num}.{port_num_endnode}', ETHVM_ENDNODE_USER) @@ -333,7 +346,10 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: host_ip = get_host_ip_by_interface(host_if, netifaces.AF_INET) logging.info('Host IP %s', host_ip) - endnode_if = host_if # endnode is a clone of the host + if get_legacy_host_name_match() is not None: + endnode_if = host_if # endnode is a clone of the host (legacy runners) + else: + endnode_if = 'dut_p2' # interface name connected to the second port of the DUT (new runners) # Endnode MAC endnode_mac = get_endnode_mac_by_interface(endnode, endnode_if) logging.info('Endnode MAC %s', endnode_mac) @@ -355,12 +371,12 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: # TEST Objective 1: Ping the devices on the network # -------------------------------------------------- # ping bridge - ping_test = subprocess.call(f'ping {br_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', br_ip, '-c', '2']) if ping_test != 0: raise RuntimeError('ESP bridge is not reachable') # ping the end nodes of the network - ping_test = subprocess.call(f'ping {endnode_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', endnode_ip, '-c', '2']) if ping_test != 0: raise RuntimeError('End node is not reachable') @@ -529,13 +545,13 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: logging.info('Drop `Endnode` MAC') dut.write('add --addr=' + endnode_mac + ' -d') dut.expect_exact('Bridge Config OK!') - ping_test = subprocess.call(f'ping {endnode_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', endnode_ip, '-c', '2']) if ping_test == 0: raise RuntimeError('End node should not be reachable') logging.info('Remove Drop `Endnode` MAC entry') dut.write('remove --addr=' + endnode_mac) dut.expect_exact('Bridge Config OK!') - ping_test = subprocess.call(f'ping {endnode_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', endnode_ip, '-c', '2']) if ping_test != 0: raise RuntimeError('End node is not reachable') @@ -568,9 +584,9 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: # Remove ARP record from Test host computer. ARP is broadcasted, hence Bridge port does not reply to a request since # it does not receive it (no forward to Bridge port). As a result, Bridge is not pingable. - subprocess.call(f'sudo arp -d {br_ip}', shell=True) - subprocess.call('arp -a', shell=True) - ping_test = subprocess.call(f'ping {br_ip} -c 2', shell=True) + subprocess.call(['sudo', 'arp', '-d', br_ip]) + subprocess.call(['arp', '-a']) + ping_test = subprocess.call(['ping', br_ip, '-c', '2']) if ping_test == 0: raise RuntimeError('Bridge should not be reachable') @@ -580,7 +596,7 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: dut.expect_exact('Bridge Config OK!') dut.write('add --addr=ff:ff:ff:ff:ff:ff -p 1 -c') dut.expect_exact('Bridge Config OK!') - ping_test = subprocess.call(f'ping {br_ip} -c 2', shell=True) + ping_test = subprocess.call(['ping', br_ip, '-c', '2']) if ping_test != 0: raise RuntimeError('Bridge is not reachable') @@ -591,3 +607,28 @@ def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: endnode.close() switch1.close() + + +@pytest.fixture(scope='session', autouse=True) +def setup_test_environment() -> Generator[None, None, None]: + # Fixture code to run before any tests in the session + # make sure dut_p2 is down (only for new runners) + if get_legacy_host_name_match() is None: + subprocess.call(['sudo', 'ip', 'link', 'set', 'down', 'dev', 'dut_p2']) + + yield # Tests run here + + # Optional teardown after all tests... + + +@pytest.mark.eth_w5500 +@pytest.mark.parametrize( + 'config', + [ + 'w5500', + ], + indirect=True, +) +@idf_parametrize('target', ['esp32'], indirect=['target']) +def test_esp_eth_bridge(dut: Dut, dev_user: str, dev_password: str) -> None: + eth_bridge_test(dut, dev_user, dev_password) diff --git a/examples/protocols/l2tap/pytest_example_l2tap_echo.py b/examples/protocols/l2tap/pytest_example_l2tap_echo.py index 3defccbbed..87e1c355f7 100644 --- a/examples/protocols/l2tap/pytest_example_l2tap_echo.py +++ b/examples/protocols/l2tap/pytest_example_l2tap_echo.py @@ -20,18 +20,26 @@ ETH_TYPE_3 = 0x2223 @contextlib.contextmanager def configure_eth_if(eth_type: int, target_if: str = '') -> Iterator[socket.socket]: + # try to determine which interface to use + netifs = os.listdir('/sys/class/net/') + # order matters - ETH NIC with the highest number is connected to DUT on CI runner + netifs.sort(reverse=True) + logging.info('detected interfaces: %s', str(netifs)) + if target_if == '': - # try to determine which interface to use - netifs = os.listdir('/sys/class/net/') - # order matters - ETH NIC with the highest number is connected to DUT on CI runner - netifs.sort(reverse=True) - logging.info('detected interfaces: %s', str(netifs)) - for netif in netifs: - if netif.find('eth') == 0 or netif.find('enx') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: - target_if = netif - break - if target_if == '': - raise Exception('no network interface found') + if 'dut_p1' in netifs: + target_if = 'dut_p1' + else: + for netif in netifs: + # if no interface defined, try to find it automatically + if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: + target_if = netif + break + elif target_if not in netifs: + target_if = '' + + if target_if == '': + raise RuntimeError('network interface not found') logging.info('Use %s for testing', target_if) so = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(eth_type)) @@ -76,7 +84,7 @@ def recv_eth_frame(eth_type: int, eth_if: str = '') -> str: return str(eth_frame.load.decode().rstrip('\x00')) -def actual_test(dut: Dut) -> None: +def actual_test(dut: Dut, test_if: str = '') -> None: # Get DUT's MAC address res = dut.expect( r'([\s\S]*)' @@ -85,17 +93,17 @@ def actual_test(dut: Dut) -> None: dut_mac = res.group(2) # Receive "ESP32 Hello frame" - recv_eth_frame(ETH_TYPE_3) + recv_eth_frame(ETH_TYPE_3, test_if) # Sent a message and receive its echo message = 'ESP32 test message with EthType ' + hex(ETH_TYPE_1) - echoed = send_recv_eth_frame(message, ETH_TYPE_1, dut_mac) + echoed = send_recv_eth_frame(message, ETH_TYPE_1, dut_mac, test_if) if echoed == message: logging.info('PASS') else: raise Exception('Echoed message does not match!') message = 'ESP32 test message with EthType ' + hex(ETH_TYPE_2) - echoed = send_recv_eth_frame(message, ETH_TYPE_2, dut_mac) + echoed = send_recv_eth_frame(message, ETH_TYPE_2, dut_mac, test_if) if echoed == message: logging.info('PASS') else: diff --git a/examples/protocols/sockets/udp_multicast/pytest_udp_multicast.py b/examples/protocols/sockets/udp_multicast/pytest_udp_multicast.py index bfe7e70725..2f7a14bdf1 100644 --- a/examples/protocols/sockets/udp_multicast/pytest_udp_multicast.py +++ b/examples/protocols/sockets/udp_multicast/pytest_udp_multicast.py @@ -36,14 +36,16 @@ def find_target_if(my_if: str = '') -> str: netifs.sort(reverse=True) logging.info('detected interfaces: %s', str(netifs)) - for netif in netifs: - # if no interface defined, try to find it automatically - if my_if == '': - if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: - return netif + if my_if == '': + if 'dut_p1' in netifs: + return 'dut_p1' else: - if netif.find(my_if) == 0: - return my_if + for netif in netifs: + # if no interface defined, try to find it automatically + if netif.find('eth') == 0 or netif.find('enp') == 0 or netif.find('eno') == 0: + return netif + elif my_if in netifs: + return my_if raise RuntimeError('network interface not found') @@ -135,7 +137,7 @@ def test_examples_udp_multicast_proto(dut: Dut, ip_version: str = 'ipv4', nic: s try: data, recv_addr = sock.recvfrom(1024) logging.info(f'Received {len(data)} bytes from {recv_addr}') - except socket.timeout: + except TimeoutError: raise RuntimeError(f'Timeout waiting for {ip_version} multicast message from ESP32') # Check if received from expected source @@ -143,7 +145,7 @@ def test_examples_udp_multicast_proto(dut: Dut, ip_version: str = 'ipv4', nic: s raise RuntimeError(f'Received {ip_version} multicast message from unexpected source') # Send multicast message - message = '!!! Multicast test message from host !!!'.encode() + message = b'!!! Multicast test message from host !!!' logging.info(f'Sending {ip_version} multicast message to {multicast_addr}:{PORT}') sock.sendto(message, (multicast_addr, PORT)) if ip_version == 'ipv4_mapped': From ddd23f774029c1142d712c662f8df97a8a533965 Mon Sep 17 00:00:00 2001 From: xiongweichao Date: Thu, 20 Nov 2025 12:13:22 +0800 Subject: [PATCH 044/156] fix(bt): fixed crash caused by deinit during A2DP connection initiation - Only clean up when idle --- .../bluedroid/btc/profile/std/a2dp/btc_av.c | 74 +++++++++++-------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c index f13d125566..1fd74b6ada 100644 --- a/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c +++ b/components/bt/host/bluedroid/btc/profile/std/a2dp/btc_av.c @@ -148,6 +148,7 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *data); static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *data); static BOOLEAN btc_av_state_closing_handler(btc_sm_event_t event, void *data); static void clean_up(int service_id); +static BOOLEAN btc_a2d_deinit_if_ongoing(void); #if BTC_AV_SRC_INCLUDED static bt_status_t btc_a2d_src_init(void); @@ -332,11 +333,13 @@ static BOOLEAN btc_av_state_idle_handler(btc_sm_event_t event, void *p_data) switch (event) { case BTC_SM_ENTER_EVT: - /* clear the peer_bda */ - memset(&btc_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t)); - btc_av_cb.flags = 0; - btc_av_cb.edr = 0; - btc_a2dp_on_idle(); + if (btc_a2d_deinit_if_ongoing() == FALSE) { + /* clear the peer_bda */ + memset(&btc_av_cb.peer_bda, 0, sizeof(bt_bdaddr_t)); + btc_av_cb.flags = 0; + btc_av_cb.edr = 0; + btc_a2dp_on_idle(); + } break; case BTC_SM_EXIT_EVT: @@ -511,22 +514,18 @@ static BOOLEAN btc_av_state_opening_handler(btc_sm_event_t event, void *p_data) /* change state to open/idle based on the status */ btc_sm_change_state(btc_av_cb.sm_handle, av_state); - if (btc_av_cb.peer_sep == AVDT_TSEP_SNK) { - /* if queued PLAY command, send it now */ - /* necessary to add this? - btc_rc_check_handle_pending_play(p_bta_data->open.bd_addr, - (p_bta_data->open.status == BTA_AV_SUCCESS)); - */ - } else if (btc_av_cb.peer_sep == AVDT_TSEP_SRC && - (p_bta_data->open.status == BTA_AV_SUCCESS)) { - /* Bring up AVRCP connection too if AVRC Initialized */ - if(g_av_with_rc) { - BTA_AvOpenRc(btc_av_cb.bta_handle); - } else { - BTC_TRACE_WARNING("AVRC not Init, not using it."); + if (p_bta_data->open.status == BTA_AV_SUCCESS && !btc_a2d_deinit_if_ongoing()) { + if (btc_av_cb.peer_sep == AVDT_TSEP_SRC) { + /* Bring up AVRCP connection too if AVRC Initialized */ + if(g_av_with_rc) { + BTA_AvOpenRc(btc_av_cb.bta_handle); + } else { + BTC_TRACE_WARNING("AVRC not Init, not using it."); + } } } btc_queue_advance(); + } break; case BTC_AV_CONFIG_EVT: { @@ -805,12 +804,6 @@ static BOOLEAN btc_av_state_opened_handler(btc_sm_event_t event, void *p_data) /* change state to idle, send acknowledgement if start is pending */ btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE); - - if (g_a2dp_source_ongoing_deinit) { - clean_up(BTA_A2DP_SOURCE_SERVICE_ID); - } else if (g_a2dp_sink_ongoing_deinit) { - clean_up(BTA_A2DP_SINK_SERVICE_ID); - } break; } @@ -1014,11 +1007,6 @@ static BOOLEAN btc_av_state_started_handler(btc_sm_event_t event, void *p_data) close->disc_rsn); btc_sm_change_state(btc_av_cb.sm_handle, BTC_AV_STATE_IDLE); - if (g_a2dp_source_ongoing_deinit) { - clean_up(BTA_A2DP_SOURCE_SERVICE_ID); - } else if (g_a2dp_sink_ongoing_deinit) { - clean_up(BTA_A2DP_SINK_SERVICE_ID); - } break; CHECK_RC_EVENT(event, p_data); @@ -1848,13 +1836,17 @@ static void btc_a2d_sink_get_delay_value(void) static void btc_a2d_sink_deinit(void) { + // Cleanup will only occur when the state is IDLE. + // If connected, it will first disconnect and then wait for the state to change to IDLE before performing cleanup. + // If in any other state, it will wait for the process to complete and then call btc_a2d_sink_deinit again. g_a2dp_sink_ongoing_deinit = true; if (btc_av_is_connected()) { BTA_AvClose(btc_av_cb.bta_handle); if (btc_av_cb.peer_sep == AVDT_TSEP_SRC && g_av_with_rc == true) { BTA_AvCloseRc(btc_av_cb.bta_handle); } - } else { + } else if (btc_sm_get_state(btc_av_cb.sm_handle) == BTC_AV_STATE_IDLE) { + /* Only clean up when idle */ clean_up(BTA_A2DP_SINK_SERVICE_ID); } } @@ -1881,13 +1873,16 @@ static bt_status_t btc_a2d_src_init(void) static void btc_a2d_src_deinit(void) { + // Cleanup will only occur when the state is IDLE. + // If connected, it will first disconnect and then wait for the state to change to IDLE before performing cleanup. + // If in any other state, it will wait for the process to complete and then call btc_a2d_src_deinit again. g_a2dp_source_ongoing_deinit = true; if (btc_av_is_connected()) { BTA_AvClose(btc_av_cb.bta_handle); if (btc_av_cb.peer_sep == AVDT_TSEP_SNK && g_av_with_rc == true) { BTA_AvCloseRc(btc_av_cb.bta_handle); } - } else { + } else if (btc_sm_get_state(btc_av_cb.sm_handle) == BTC_AV_STATE_IDLE) { clean_up(BTA_A2DP_SOURCE_SERVICE_ID); } } @@ -1932,6 +1927,23 @@ bt_status_t btc_a2d_src_audio_data_send(esp_a2d_conn_hdl_t conn_hdl, esp_a2d_aud #endif /* BTC_AV_SRC_INCLUDED */ +static BOOLEAN btc_a2d_deinit_if_ongoing(void) +{ +#if BTC_AV_SRC_INCLUDED + if (g_a2dp_source_ongoing_deinit) { + btc_a2d_src_deinit(); + return TRUE; + } +#endif +#if BTC_AV_SINK_INCLUDED + if (g_a2dp_sink_ongoing_deinit) { + btc_a2d_sink_deinit(); + return TRUE; + } +#endif + return FALSE; +} + uint16_t btc_a2d_conn_handle_get(void) { return btc_av_cb.bta_handle; From 15609b042436b223cb1251fec38f1787f6331d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Tue, 2 Dec 2025 09:50:14 +0100 Subject: [PATCH 045/156] fix(sdmmc): Deinitialize only initialized slots (sdmmc_host_deinit function) Closes https://github.com/espressif/esp-idf/issues/17937 --- components/esp_driver_sdmmc/src/sdmmc_host.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/esp_driver_sdmmc/src/sdmmc_host.c b/components/esp_driver_sdmmc/src/sdmmc_host.c index c33479cb1c..4a84723e21 100644 --- a/components/esp_driver_sdmmc/src/sdmmc_host.c +++ b/components/esp_driver_sdmmc/src/sdmmc_host.c @@ -929,7 +929,9 @@ esp_err_t sdmmc_host_deinit(void) return ESP_ERR_INVALID_STATE; } for (int slot = 0; slot < SOC_SDMMC_NUM_SLOTS; slot++) { - sdmmc_host_deinit_slot_internal(slot); + if (sdmmc_host_slot_initialized(slot)) { + sdmmc_host_deinit_slot_internal(slot); + } } sdmmc_host_deinit_internal(); From 21cb976fd6dadc937d4db7dc7067e9f72ccb66c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= Date: Tue, 11 Nov 2025 14:43:53 +0100 Subject: [PATCH 046/156] fix(touch): Add missing bit swap to fix channel 8 and 9 --- components/hal/esp32/include/hal/touch_sensor_ll.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/hal/esp32/include/hal/touch_sensor_ll.h b/components/hal/esp32/include/hal/touch_sensor_ll.h index 357399fe1a..9f1ef2167b 100644 --- a/components/hal/esp32/include/hal/touch_sensor_ll.h +++ b/components/hal/esp32/include/hal/touch_sensor_ll.h @@ -327,7 +327,7 @@ static inline void touch_ll_set_init_charge_voltage(uint32_t touch_num, touch_in */ static inline void touch_ll_enable_channel_mask(uint16_t enable_mask) { - SENS.sar_touch_enable.touch_pad_worken = enable_mask; + SENS.sar_touch_enable.touch_pad_worken = TOUCH_LL_BITS_SWAP(enable_mask); } /** From 3d2dda8e72b2078e424d84e4a4d7571fe5ff35a6 Mon Sep 17 00:00:00 2001 From: Samuel Obuch Date: Mon, 1 Dec 2025 10:39:09 +0100 Subject: [PATCH 047/156] fix(bootloader_flash): invalidate FLASH_READ_VADDR before read Fixed address to match corresponding mmu_hal_map_region call. FLASH_MMAP_VADDR was invalidated by mistake in commit ea38a2e9a493ab35e1572057f275a1ac71d49343 --- .../bootloader_support/bootloader_flash/src/bootloader_flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c index 4b6967782c..0b63c884f5 100644 --- a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c +++ b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c @@ -519,7 +519,7 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest Cache_Read_Enable(0); #else #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, FLASH_MMAP_VADDR, actual_mapped_len); + cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, FLASH_READ_VADDR, actual_mapped_len); #endif #if !ESP_TEE_BUILD cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); From 3e4bed2e4d08a2caf8edbb7c39f0d3b575370b7e Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Fri, 28 Nov 2025 11:56:25 +0530 Subject: [PATCH 048/156] feat(mbedtls): add ECC P-384 mbedtls support and test_cases --- components/mbedtls/port/ecc/ecc_alt.c | 17 ++- components/mbedtls/port/include/ecc_impl.h | 15 ++- components/mbedtls/test_apps/main/test_ecp.c | 107 ++++++++++++++++++- 3 files changed, 127 insertions(+), 12 deletions(-) diff --git a/components/mbedtls/port/ecc/ecc_alt.c b/components/mbedtls/port/ecc/ecc_alt.c index 4ffa065c24..7b70da59cf 100644 --- a/components/mbedtls/port/ecc/ecc_alt.c +++ b/components/mbedtls/port/ecc/ecc_alt.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,14 +7,13 @@ #include #include "soc/hwcrypto_periph.h" #include "ecc_impl.h" +#include "hal/ecc_ll.h" #include "mbedtls/ecp.h" #include "mbedtls/platform_util.h" #if defined(MBEDTLS_ECP_MUL_ALT) || defined(MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK) -#define MAX_SIZE 32 // 256 bits - static int esp_mbedtls_ecp_point_multiply(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P) { @@ -54,7 +53,11 @@ int ecp_mul_restartable_internal( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, mbedtls_ecp_restart_ctx *rs_ctx ) { int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; - if (grp->id != MBEDTLS_ECP_DP_SECP192R1 && grp->id != MBEDTLS_ECP_DP_SECP256R1) { + if (grp->id != MBEDTLS_ECP_DP_SECP192R1 && grp->id != MBEDTLS_ECP_DP_SECP256R1 +#if SOC_ECC_SUPPORT_CURVE_P384 + && (grp->id != MBEDTLS_ECP_DP_SECP384R1 || !ecc_ll_is_p384_curve_operations_supported()) +#endif + ) { #if defined(MBEDTLS_ECP_MUL_ALT_SOFT_FALLBACK) return ecp_mul_restartable_internal_soft(grp, R, m, P, f_rng, p_rng, rs_ctx); #else @@ -85,7 +88,11 @@ int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; } - if (grp->id != MBEDTLS_ECP_DP_SECP192R1 && grp->id != MBEDTLS_ECP_DP_SECP256R1) { + if (grp->id != MBEDTLS_ECP_DP_SECP192R1 && grp->id != MBEDTLS_ECP_DP_SECP256R1 +#if SOC_ECC_SUPPORT_CURVE_P384 + && (grp->id != MBEDTLS_ECP_DP_SECP384R1 || !ecc_ll_is_p384_curve_operations_supported()) +#endif + ) { #if defined(MBEDTLS_ECP_VERIFY_ALT_SOFT_FALLBACK) return mbedtls_ecp_check_pubkey_soft(grp, pt); #else diff --git a/components/mbedtls/port/include/ecc_impl.h b/components/mbedtls/port/include/ecc_impl.h index c52c988195..d7900ee49f 100644 --- a/components/mbedtls/port/include/ecc_impl.h +++ b/components/mbedtls/port/include/ecc_impl.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +14,13 @@ extern "C" { #define P256_LEN (256/8) #define P192_LEN (192/8) +#define P384_LEN (384/8) + +#if SOC_ECC_SUPPORT_CURVE_P384 +#define MAX_SIZE P384_LEN +#else +#define MAX_SIZE P256_LEN +#endif /* Note: x & y are stored in little endian order (same as CPU byte order, and order used internally by most libraries). @@ -22,9 +29,9 @@ extern "C" { Note this is opposite to most byte string formats used to represent keys, which are often big endian */ typedef struct { - uint8_t x[P256_LEN]; /* Little endian order */ - uint8_t y[P256_LEN]; /* Little endian order */ - unsigned len; /* P192_LEN or P256_LEN */ + uint8_t x[MAX_SIZE]; /* Little endian order */ + uint8_t y[MAX_SIZE]; /* Little endian order */ + unsigned len; /* P192_LEN, P256_LEN, or P384_LEN */ } ecc_point_t; /** diff --git a/components/mbedtls/test_apps/main/test_ecp.c b/components/mbedtls/test_apps/main/test_ecp.c index db42587030..d711eef1e3 100644 --- a/components/mbedtls/test_apps/main/test_ecp.c +++ b/components/mbedtls/test_apps/main/test_ecp.c @@ -3,7 +3,7 @@ * Focus on testing functionality where we use ESP32 hardware * accelerated crypto features. * - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,6 +22,9 @@ #include "test_utils.h" #include "ccomp_timer.h" #include "unity.h" +#if CONFIG_MBEDTLS_HARDWARE_ECC +#include "hal/ecc_ll.h" +#endif /* Note: negative value here so that assert message prints a grep-able error hex value (mbedTLS uses -N for error codes) */ @@ -202,6 +205,70 @@ const uint8_t ecc_p256_small_mul_res_y[] = { 0x17, 0xFD, 0xF6, 0x64, 0x41, 0x9E, 0x50, 0x0C }; +#if SOC_ECC_SUPPORT_CURVE_P384 +const uint8_t ecc_p384_point_x[] = { + 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7 +}; + +const uint8_t ecc_p384_point_y[] = { + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, + 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, + 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, + 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f +}; + +const uint8_t ecc_p384_scalar[] = { + 0x68, 0xd1, 0x09, 0xa7, 0xc7, 0x7e, 0xeb, 0xbd, + 0x43, 0x18, 0x7e, 0xdd, 0x69, 0x23, 0x7e, 0x0a, + 0xef, 0x07, 0xc2, 0x0e, 0xc5, 0x3d, 0xe7, 0xcb, + 0xd4, 0x36, 0xad, 0x9b, 0xdc, 0xf8, 0x6c, 0x5c, + 0x0c, 0x3d, 0xce, 0x45, 0xcd, 0x6f, 0x7f, 0x18, + 0x40, 0xc5, 0x29, 0xf3, 0xcd, 0x12, 0x1d, 0xc2 +}; + +const uint8_t ecc_p384_mul_res_x[] = { + 0x74, 0x1d, 0xc3, 0xba, 0xac, 0x60, 0x37, 0xfc, + 0x57, 0x85, 0x90, 0x95, 0x64, 0xe6, 0xd1, 0xef, + 0x86, 0xdf, 0x42, 0xe0, 0xaf, 0x11, 0x24, 0x1f, + 0xe9, 0x97, 0x6e, 0x0c, 0xd9, 0xe5, 0xa0, 0x5d, + 0xd9, 0x91, 0x96, 0x71, 0xef, 0x96, 0xe9, 0x7e, + 0x90, 0xba, 0xa8, 0x33, 0xe2, 0x2e, 0xf0, 0x7b +}; + +const uint8_t ecc_p384_mul_res_y[] = { + 0xc3, 0xe0, 0x66, 0x50, 0xd9, 0x1e, 0xa9, 0x42, + 0xcb, 0x0d, 0xec, 0xb6, 0x29, 0xe2, 0xae, 0x75, + 0xc6, 0xa2, 0xb9, 0xa6, 0xcf, 0x2c, 0x97, 0x01, + 0xcc, 0xff, 0x7c, 0x1c, 0xd1, 0x01, 0xde, 0xbc, + 0x40, 0x56, 0x8c, 0x18, 0x21, 0x9d, 0xbd, 0xc0, + 0x2d, 0x41, 0x5b, 0x92, 0x52, 0x5a, 0x40, 0x57 +}; + +const uint8_t ecc_p384_small_mul_res_x[] = { + 0x35, 0x49, 0x60, 0x41, 0xea, 0x25, 0x3b, 0x0d, + 0x15, 0x3c, 0x9b, 0xfb, 0xc1, 0x8a, 0x9e, 0x41, + 0xaf, 0x34, 0x8a, 0xfd, 0x8b, 0x1c, 0x33, 0xa5, + 0xca, 0x5d, 0x7f, 0xbb, 0xfa, 0x2d, 0x5d, 0x9d, + 0x43, 0x6e, 0xd1, 0x01, 0x1b, 0x3d, 0x9d, 0x93, + 0xe4, 0xb4, 0x5d, 0x2a, 0x4b, 0x23, 0x27, 0xf1 +}; + +const uint8_t ecc_p384_small_mul_res_y[] = { + 0x73, 0xce, 0x1e, 0xaa, 0x4f, 0xfd, 0xdc, 0x1d, + 0x69, 0xd9, 0xe0, 0x9d, 0x16, 0x46, 0x19, 0xae, + 0x8d, 0xd2, 0xce, 0x26, 0x6f, 0x9d, 0xb6, 0xc3, + 0x30, 0xa5, 0x05, 0x7c, 0x7d, 0x62, 0xde, 0x8f, + 0x8e, 0xc3, 0xce, 0x9b, 0xa7, 0xc1, 0x71, 0xb9, + 0xb0, 0x2a, 0xda, 0x1c, 0xb3, 0x42, 0x61, 0x58 +}; +#endif /* SOC_ECC_SUPPORT_CURVE_P384 */ static int rng_wrapper(void *ctx, unsigned char *buf, size_t len) { @@ -213,8 +280,8 @@ static void test_ecp_mul(mbedtls_ecp_group_id id, const uint8_t *x_coord, const const uint8_t *result_x_coord, const uint8_t *result_y_coord) { int64_t elapsed_time; - uint8_t x[32]; - uint8_t y[32]; + uint8_t x[48]; + uint8_t y[48]; int size; int ret; @@ -259,6 +326,12 @@ static void test_ecp_mul(mbedtls_ecp_group_id id, const uint8_t *x_coord, const TEST_PERFORMANCE_CCOMP_LESS_THAN(ECP_P192_POINT_MULTIPLY_OP, "%" NEWLIB_NANO_COMPAT_FORMAT" us", NEWLIB_NANO_COMPAT_CAST(elapsed_time)); } else if (id == MBEDTLS_ECP_DP_SECP256R1) { TEST_PERFORMANCE_CCOMP_LESS_THAN(ECP_P256_POINT_MULTIPLY_OP, "%" NEWLIB_NANO_COMPAT_FORMAT" us", NEWLIB_NANO_COMPAT_CAST(elapsed_time)); +#if SOC_ECC_SUPPORT_CURVE_P384 + } else if (id == MBEDTLS_ECP_DP_SECP384R1) { + if (ecc_ll_is_p384_curve_operations_supported()) { + TEST_PERFORMANCE_CCOMP_LESS_THAN(ECP_P384_POINT_MULTIPLY_OP, "%" NEWLIB_NANO_COMPAT_FORMAT" us", NEWLIB_NANO_COMPAT_CAST(elapsed_time)); + } +#endif } mbedtls_ecp_point_free(&R); @@ -285,6 +358,19 @@ TEST_CASE("mbedtls ECP point multiply with SECP256R1", "[mbedtls]") ecc_p256_small_mul_res_x, ecc_p256_small_mul_res_y); } +#if SOC_ECC_SUPPORT_CURVE_P384 +TEST_CASE("mbedtls ECP point multiply with SECP384R1", "[mbedtls]") +{ + if (ecc_ll_is_p384_curve_operations_supported()) { + test_ecp_mul(MBEDTLS_ECP_DP_SECP384R1, ecc_p384_point_x, ecc_p384_point_y, ecc_p384_scalar, + ecc_p384_mul_res_x, ecc_p384_mul_res_y); + + test_ecp_mul(MBEDTLS_ECP_DP_SECP384R1, ecc_p384_point_x, ecc_p384_point_y, NULL, + ecc_p384_small_mul_res_x, ecc_p384_small_mul_res_y); + } +} +#endif /* SOC_ECC_SUPPORT_CURVE_P384 */ + static void test_ecp_verify(mbedtls_ecp_group_id id, const uint8_t *x_coord, const uint8_t *y_coord) { int64_t elapsed_time; @@ -315,6 +401,12 @@ static void test_ecp_verify(mbedtls_ecp_group_id id, const uint8_t *x_coord, con TEST_PERFORMANCE_CCOMP_LESS_THAN(ECP_P192_POINT_VERIFY_OP, "%" NEWLIB_NANO_COMPAT_FORMAT" us", NEWLIB_NANO_COMPAT_CAST(elapsed_time)); } else if (id == MBEDTLS_ECP_DP_SECP256R1) { TEST_PERFORMANCE_CCOMP_LESS_THAN(ECP_P256_POINT_VERIFY_OP, "%" NEWLIB_NANO_COMPAT_FORMAT" us", NEWLIB_NANO_COMPAT_CAST(elapsed_time)); +#if SOC_ECC_SUPPORT_CURVE_P384 + } else if (id == MBEDTLS_ECP_DP_SECP384R1) { + if (ecc_ll_is_p384_curve_operations_supported()) { + TEST_PERFORMANCE_CCOMP_LESS_THAN(ECP_P384_POINT_VERIFY_OP, "%" NEWLIB_NANO_COMPAT_FORMAT" us", NEWLIB_NANO_COMPAT_CAST(elapsed_time)); + } +#endif } mbedtls_ecp_point_free(&P); @@ -330,4 +422,13 @@ TEST_CASE("mbedtls ECP point verify with SECP256R1", "[mbedtls]") { test_ecp_verify(MBEDTLS_ECP_DP_SECP256R1, ecc_p256_mul_res_x, ecc_p256_mul_res_y); } + +#if SOC_ECC_SUPPORT_CURVE_P384 +TEST_CASE("mbedtls ECP point verify with SECP384R1", "[mbedtls]") +{ + if (ecc_ll_is_p384_curve_operations_supported()) { + test_ecp_verify(MBEDTLS_ECP_DP_SECP384R1, ecc_p384_mul_res_x, ecc_p384_mul_res_y); + } +} +#endif /* SOC_ECC_SUPPORT_CURVE_P384 */ #endif /* CONFIG_MBEDTLS_HARDWARE_ECC */ From 6e972acc98777e3356d2afebf0c958955d44fed3 Mon Sep 17 00:00:00 2001 From: "peter.marcisovsky" Date: Tue, 7 Oct 2025 11:33:16 +0200 Subject: [PATCH 049/156] feat(esp_hal_usb): Add remote wakeup support --- components/hal/include/hal/usb_dwc_hal.h | 5 +++-- components/hal/usb_dwc_hal.c | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/components/hal/include/hal/usb_dwc_hal.h b/components/hal/include/hal/usb_dwc_hal.h index 6178c1d4b8..5948c22c1e 100644 --- a/components/hal/include/hal/usb_dwc_hal.h +++ b/components/hal/include/hal/usb_dwc_hal.h @@ -67,6 +67,7 @@ typedef enum { USB_DWC_HAL_PORT_EVENT_DISABLED, /**< The host port has been disabled (no more SOFs). Could be due to disable/reset request, or a port error (e.g. port babble condition. See 11.8.1 of USB2.0 spec) */ USB_DWC_HAL_PORT_EVENT_OVRCUR, /**< The host port has encountered an overcurrent condition */ USB_DWC_HAL_PORT_EVENT_OVRCUR_CLR, /**< The host port has been cleared of the overcurrent condition */ + USB_DWC_HAL_PORT_EVENT_REMOTE_WAKEUP, /**< The host port has detected remote wakeup sequence from a device */ } usb_dwc_hal_port_event_t; /** @@ -305,7 +306,7 @@ static inline void usb_dwc_hal_port_init(usb_dwc_hal_context_t *hal) { //Configure Host related interrupts usb_dwc_ll_haintmsk_dis_chan_intr(hal->dev, 0xFFFFFFFF); //Disable interrupts for all channels - usb_dwc_ll_gintmsk_en_intrs(hal->dev, USB_DWC_LL_INTR_CORE_PRTINT | USB_DWC_LL_INTR_CORE_HCHINT); + usb_dwc_ll_gintmsk_en_intrs(hal->dev, USB_DWC_LL_INTR_CORE_PRTINT | USB_DWC_LL_INTR_CORE_HCHINT | USB_DWC_LL_INTR_CORE_WKUPINT); } /** @@ -318,7 +319,7 @@ static inline void usb_dwc_hal_port_init(usb_dwc_hal_context_t *hal) static inline void usb_dwc_hal_port_deinit(usb_dwc_hal_context_t *hal) { //Disable Host port and channel interrupts - usb_dwc_ll_gintmsk_dis_intrs(hal->dev, USB_DWC_LL_INTR_CORE_PRTINT | USB_DWC_LL_INTR_CORE_HCHINT); + usb_dwc_ll_gintmsk_dis_intrs(hal->dev, USB_DWC_LL_INTR_CORE_PRTINT | USB_DWC_LL_INTR_CORE_HCHINT | USB_DWC_LL_INTR_CORE_WKUPINT); } /** diff --git a/components/hal/usb_dwc_hal.c b/components/hal/usb_dwc_hal.c index ed646682b3..e8ae0afeae 100644 --- a/components/hal/usb_dwc_hal.c +++ b/components/hal/usb_dwc_hal.c @@ -44,7 +44,8 @@ //Interrupts that pertain to core events #define CORE_EVENTS_INTRS_MSK (USB_DWC_LL_INTR_CORE_DISCONNINT | \ - USB_DWC_LL_INTR_CORE_HCHINT) + USB_DWC_LL_INTR_CORE_HCHINT | \ + USB_DWC_LL_INTR_CORE_WKUPINT) //Interrupt that pertain to host port events #define PORT_EVENTS_INTRS_MSK (USB_DWC_LL_INTR_HPRT_PRTCONNDET | \ @@ -463,6 +464,8 @@ usb_dwc_hal_port_event_t usb_dwc_hal_decode_intr(usb_dwc_hal_context_t *hal) } else if (intrs_port & USB_DWC_LL_INTR_HPRT_PRTCONNDET && !hal->flags.dbnc_lock_enabled) { event = USB_DWC_HAL_PORT_EVENT_CONN; debounce_lock_enable(hal); + } else if (intrs_core & USB_DWC_LL_INTR_CORE_WKUPINT) { + event = USB_DWC_HAL_PORT_EVENT_REMOTE_WAKEUP; // Remote wakeup was generated from device } } //Port events always take precedence over channel events From b23f5165264c6a7bc5b5d646b605eb2cb0d5e038 Mon Sep 17 00:00:00 2001 From: Tan Yan Quan Date: Mon, 10 Nov 2025 15:52:24 +0800 Subject: [PATCH 050/156] feat(openthread/ota): support esp32h2 for ota examples over thread --- examples/system/.build-test-rules.yml | 12 ++++-- examples/system/ota/README.md | 40 +++++++++++++++++++ .../system/ota/advanced_https_ota/README.md | 4 +- .../sdkconfig.defaults.esp32h2 | 4 ++ .../system/ota/native_ota_example/README.md | 4 +- .../sdkconfig.defaults.esp32h2 | 4 ++ examples/system/ota/partitions_ota/README.md | 4 +- .../ota/partitions_ota/main/Kconfig.projbuild | 7 ++++ .../system/ota/partitions_ota/main/app_main.c | 2 + .../partitions_ota/sdkconfig.defaults.esp32h2 | 4 ++ .../system/ota/simple_ota_example/README.md | 4 +- .../simple_ota_example/main/Kconfig.projbuild | 6 +++ .../main/simple_ota_example.c | 2 + .../sdkconfig.defaults.esp32h2 | 4 ++ 14 files changed, 89 insertions(+), 12 deletions(-) create mode 100644 examples/system/ota/advanced_https_ota/sdkconfig.defaults.esp32h2 create mode 100644 examples/system/ota/native_ota_example/sdkconfig.defaults.esp32h2 create mode 100644 examples/system/ota/partitions_ota/sdkconfig.defaults.esp32h2 create mode 100644 examples/system/ota/simple_ota_example/sdkconfig.defaults.esp32h2 diff --git a/examples/system/.build-test-rules.yml b/examples/system/.build-test-rules.yml index 26eb93764b..ff5c6ab3b9 100644 --- a/examples/system/.build-test-rules.yml +++ b/examples/system/.build-test-rules.yml @@ -157,7 +157,7 @@ examples/system/nmi_isr: examples/system/ota/advanced_https_ota: disable: - - if: IDF_TARGET in ["esp32h2", "esp32h21", "esp32h4"] + - if: IDF_TARGET in ["esp32h21", "esp32h4"] temporary: true reason: not supported yet disable_test: @@ -174,10 +174,11 @@ examples/system/ota/advanced_https_ota: - esp_phy - bt - protocol_examples_common + - openthread examples/system/ota/native_ota_example: disable: - - if: IDF_TARGET in ["esp32h2", "esp32h21", "esp32h4"] + - if: IDF_TARGET in ["esp32h21", "esp32h4"] temporary: true reason: not supported yet disable_test: @@ -191,6 +192,7 @@ examples/system/ota/native_ota_example: - esp_driver_gpio - bootloader_support - protocol_examples_common + - openthread examples/system/ota/otatool: enable: @@ -198,7 +200,7 @@ examples/system/ota/otatool: examples/system/ota/partitions_ota: disable: - - if: IDF_TARGET in ["esp32h2", "esp32h21", "esp32h4"] + - if: IDF_TARGET in ["esp32h21", "esp32h4"] temporary: true reason: not supported yet - if: CONFIG_NAME == "recovery_bootloader" and SOC_RECOVERY_BOOTLOADER_SUPPORTED != 1 @@ -220,10 +222,11 @@ examples/system/ota/partitions_ota: - esp_wifi - esp_phy - mbedtls + - openthread examples/system/ota/simple_ota_example: disable: - - if: IDF_TARGET in ["esp32h2", "esp32h21", "esp32h4"] + - if: IDF_TARGET in ["esp32h21", "esp32h4"] temporary: true reason: not supported yet - if: CONFIG_NAME == "spiram" and SOC_SPIRAM_SUPPORTED != 1 @@ -240,6 +243,7 @@ examples/system/ota/simple_ota_example: - esp_wifi - esp_phy - mbedtls + - openthread examples/system/perfmon: enable: diff --git a/examples/system/ota/README.md b/examples/system/ota/README.md index ed153c1737..4a714722fa 100644 --- a/examples/system/ota/README.md +++ b/examples/system/ota/README.md @@ -158,6 +158,46 @@ The ``native_ota_example`` contains code to demonstrate how to check the version In ``native_ota_example``, ``$PROJECT_PATH/version.txt`` is used to define the app version. Change the version in the file to compile the new firmware. +## OTA over Thread + +These examples also support OTA (Over-the-Air) updates over a Thread network and supports binding to a Thread interface on targets with native IEEE 802.15.4 support, such as the ESP32-H2. + +### Thread Connectivity Prerequisites + +To enable OTA over Thread, you need a Thread End Device (which is the "ESP-Dev-Board", for example, ESP32-H2) and a [Thread Border Router](https://github.com/espressif/esp-thread-br). IPv6 connectivity must be established between the Thread End Device, the Thread Border Router, and the HTTP server. You can follow the guide in [Bi-directional IPv6 Connectivity](https://docs.espressif.com/projects/esp-thread-br/en/latest/codelab/connectivity.html) for setup instructions. + +Once IPv6 connectivity is established, the HTTP server will receive a valid IPv6 address starting with the On-link Prefix assigned by the Thread Border Router. This address will be used by the Thread End Device to retrieve the OTA binary. + +### HTTP(S) Server Requirements + +When running the HTTP(S) server, ensure that it supports IPv6. This can be achieved using a OpenSSL based server as detailed above: + +``` +openssl s_server -WWW -key ca_key.pem -cert ca_cert.pem -port 8070 +``` + +* **Note:** Use the IPv6 address from the Bi-directional IPv6 Connectivity guide to generate the certificate (CN prompt). + +* **Note:** The example script for the Python based server does not support IPv6 by default. + +An alternative means of debugging with IPv6 support is to use Python's built-in HTTP server with the `--bind ::` option: + +``` +python -m http.server 8070 --bind :: +``` + +OTA over Thread only supports IPv6 addresses. If the HTTP(S) server can only be accessed via an IPv4 address, the End Device will need to synthesize an IPv6 address using the [NAT64](https://docs.espressif.com/projects/esp-thread-br/en/latest/codelab/nat64.html) feature. + +### Thread Configuration Options (End Device) + +- `idf.py menuconfig → Component config → OpenThread → OpenThread` = `y` *(enabled by default for ESP32-H2)* +- `idf.py menuconfig → Component config → OpenThread → Thread Core Features → Thread Operational Dataset` — must match the Border Router configuration +- `idf.py menuconfig → Component config → Example Configuration → firmware upgrade URL endpoint` = `"https://[fda3:e29:9416:af10:db46:b477:354e:416e]:8070/blink.bin"` + *(Refer to [Thread Connectivity Prerequisites](#thread-connectivity-prerequisites) for details on obtaining this IPv6 address, which belongs to the HTTP(S) server host PC and is accessible by the end device.)* + +> **Note:** +> Thread network throughput is typically lower than Wi-Fi or Ethernet. It is recommended to start with a small OTA binary such as `blink.bin` from `examples/get-started/blink` to validate connectivity. + ## Troubleshooting * Check that your PC can ping the "ESP-Dev-Board" using its IP, and that the IP, AP and other configuration settings are correctly configured in menuconfig diff --git a/examples/system/ota/advanced_https_ota/README.md b/examples/system/ota/advanced_https_ota/README.md index 3ab4875b55..89b9ec3ddf 100644 --- a/examples/system/ota/advanced_https_ota/README.md +++ b/examples/system/ota/advanced_https_ota/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # Advanced HTTPS OTA example diff --git a/examples/system/ota/advanced_https_ota/sdkconfig.defaults.esp32h2 b/examples/system/ota/advanced_https_ota/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..909d9d7a8a --- /dev/null +++ b/examples/system/ota/advanced_https_ota/sdkconfig.defaults.esp32h2 @@ -0,0 +1,4 @@ +CONFIG_OPENTHREAD_ENABLED=y + +# CMAC is required for openthread +CONFIG_MBEDTLS_CMAC_C=y diff --git a/examples/system/ota/native_ota_example/README.md b/examples/system/ota/native_ota_example/README.md index 85500a1e2b..0b261f4351 100644 --- a/examples/system/ota/native_ota_example/README.md +++ b/examples/system/ota/native_ota_example/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # Native OTA example diff --git a/examples/system/ota/native_ota_example/sdkconfig.defaults.esp32h2 b/examples/system/ota/native_ota_example/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..909d9d7a8a --- /dev/null +++ b/examples/system/ota/native_ota_example/sdkconfig.defaults.esp32h2 @@ -0,0 +1,4 @@ +CONFIG_OPENTHREAD_ENABLED=y + +# CMAC is required for openthread +CONFIG_MBEDTLS_CMAC_C=y diff --git a/examples/system/ota/partitions_ota/README.md b/examples/system/ota/partitions_ota/README.md index 5e13b44073..0d01cf4273 100644 --- a/examples/system/ota/partitions_ota/README.md +++ b/examples/system/ota/partitions_ota/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # Partition OTA Example diff --git a/examples/system/ota/partitions_ota/main/Kconfig.projbuild b/examples/system/ota/partitions_ota/main/Kconfig.projbuild index 77681a9a49..5c69912b96 100644 --- a/examples/system/ota/partitions_ota/main/Kconfig.projbuild +++ b/examples/system/ota/partitions_ota/main/Kconfig.projbuild @@ -50,5 +50,12 @@ menu "Example Configuration" depends on EXAMPLE_CONNECT_ETHERNET help Select ethernet interface to pass the OTA data. + + config EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_THREAD + bool "Bind thread interface" + depends on EXAMPLE_CONNECT_THREAD + help + Select Thread interface to pass the OTA data. + endchoice endmenu diff --git a/examples/system/ota/partitions_ota/main/app_main.c b/examples/system/ota/partitions_ota/main/app_main.c index 02aa425365..925d7ed71b 100644 --- a/examples/system/ota/partitions_ota/main/app_main.c +++ b/examples/system/ota/partitions_ota/main/app_main.c @@ -48,6 +48,8 @@ static const char *bind_interface_name = EXAMPLE_NETIF_DESC_ETH; #elif CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_STA static const char *bind_interface_name = EXAMPLE_NETIF_DESC_STA; +#elif CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_THREAD +static const char *bind_interface_name = EXAMPLE_NETIF_DESC_THREAD; #endif #endif diff --git a/examples/system/ota/partitions_ota/sdkconfig.defaults.esp32h2 b/examples/system/ota/partitions_ota/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..909d9d7a8a --- /dev/null +++ b/examples/system/ota/partitions_ota/sdkconfig.defaults.esp32h2 @@ -0,0 +1,4 @@ +CONFIG_OPENTHREAD_ENABLED=y + +# CMAC is required for openthread +CONFIG_MBEDTLS_CMAC_C=y diff --git a/examples/system/ota/simple_ota_example/README.md b/examples/system/ota/simple_ota_example/README.md index 03415d7ba1..b63b17d522 100644 --- a/examples/system/ota/simple_ota_example/README.md +++ b/examples/system/ota/simple_ota_example/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- | # Simple OTA example diff --git a/examples/system/ota/simple_ota_example/main/Kconfig.projbuild b/examples/system/ota/simple_ota_example/main/Kconfig.projbuild index 4404a99f44..ec64ddedf4 100644 --- a/examples/system/ota/simple_ota_example/main/Kconfig.projbuild +++ b/examples/system/ota/simple_ota_example/main/Kconfig.projbuild @@ -50,6 +50,12 @@ menu "Example Configuration" depends on EXAMPLE_CONNECT_ETHERNET help Select ethernet interface to pass the OTA data. + + config EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_THREAD + bool "Bind thread interface" + depends on EXAMPLE_CONNECT_THREAD + help + Select Thread interface to pass the OTA data. endchoice config EXAMPLE_TLS_DYN_BUF_RX_STATIC diff --git a/examples/system/ota/simple_ota_example/main/simple_ota_example.c b/examples/system/ota/simple_ota_example/main/simple_ota_example.c index 52e1bac6bb..aeb87816d0 100644 --- a/examples/system/ota/simple_ota_example/main/simple_ota_example.c +++ b/examples/system/ota/simple_ota_example/main/simple_ota_example.c @@ -36,6 +36,8 @@ static const char *bind_interface_name = EXAMPLE_NETIF_DESC_ETH; #elif CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_STA static const char *bind_interface_name = EXAMPLE_NETIF_DESC_STA; +#elif CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF_THREAD +static const char *bind_interface_name = EXAMPLE_NETIF_DESC_THREAD; #endif #endif diff --git a/examples/system/ota/simple_ota_example/sdkconfig.defaults.esp32h2 b/examples/system/ota/simple_ota_example/sdkconfig.defaults.esp32h2 new file mode 100644 index 0000000000..909d9d7a8a --- /dev/null +++ b/examples/system/ota/simple_ota_example/sdkconfig.defaults.esp32h2 @@ -0,0 +1,4 @@ +CONFIG_OPENTHREAD_ENABLED=y + +# CMAC is required for openthread +CONFIG_MBEDTLS_CMAC_C=y From 6b490a278cb3869f07fa456bb992c37b07f8f974 Mon Sep 17 00:00:00 2001 From: wanckl Date: Fri, 14 Nov 2025 15:25:41 +0800 Subject: [PATCH 051/156] fix(driver_twai): enhance ci test and fix example --- .../test_apps/legacy_twai/pytest_twai.py | 73 +++++++++++++++---- .../test_apps/test_twai/pytest_driver_twai.py | 70 ++++++++++++++---- 2 files changed, 113 insertions(+), 30 deletions(-) diff --git a/components/driver/test_apps/legacy_twai/pytest_twai.py b/components/driver/test_apps/legacy_twai/pytest_twai.py index dd3a5d24e8..1c6086ceaf 100644 --- a/components/driver/test_apps/legacy_twai/pytest_twai.py +++ b/components/driver/test_apps/legacy_twai/pytest_twai.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: CC0-1.0 import logging import subprocess -from time import sleep +import time import pytest from can import Bus @@ -10,6 +10,10 @@ from can import Message from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize +# --------------------------------------------------------------------------- +# Loop Back Tests +# --------------------------------------------------------------------------- + @pytest.mark.generic @pytest.mark.parametrize( @@ -24,16 +28,57 @@ def test_legacy_twai_self(dut: Dut) -> None: dut.run_all_single_board_cases(group='twai-loop-back') +# --------------------------------------------------------------------------- +# Helper Functions +# --------------------------------------------------------------------------- + + +def esp_enter_flash_mode(dut: Dut) -> None: + ser = dut.serial.proc + ser.setRTS(True) # EN Low + time.sleep(0.5) + ser.setDTR(True) # GPIO0 Low + ser.setRTS(False) # EN High + dut.expect('waiting for download', timeout=2) + ser.setDTR(False) # Back RTS/DTR to 1/1 to avoid affect to esptool + + +def esp_reset_and_wait_ready(dut: Dut) -> None: + dut.serial.hard_reset() + time.sleep(0.5) + dut.expect_exact('Press ENTER to see the list of tests') + + @pytest.fixture(name='socket_can') def fixture_create_socket_can() -> Bus: # Set up the socket CAN with the bitrate - start_command = 'sudo ip link set can0 up type can bitrate 250000 restart-ms 100' - stop_command = 'sudo ip link set can0 down' - subprocess.run(start_command, shell=True, capture_output=True, text=True) - bus = Bus(interface='socketcan', channel='can0', bitrate=250000) - yield bus # test invoked here - bus.shutdown() - subprocess.run(stop_command, shell=True, capture_output=True, text=True) + start_command = 'sudo -n ip link set can0 up type can bitrate 250000 restart-ms 100' + stop_command = 'sudo -n ip link set can0 down' + status_command = 'sudo -n ip -details link show can0' + + try: + result = subprocess.run(status_command, shell=True, capture_output=True, text=True) + if result.returncode != 0: + raise Exception('CAN interface "can0" not found') + + if 'UP' in result.stdout: # Close the bus anyway if it is already up + subprocess.run(stop_command, shell=True, capture_output=True, text=True) + subprocess.run(start_command, shell=True, capture_output=True, text=True) + + time.sleep(0.5) + bus = Bus(interface='socketcan', channel='can0', bitrate=250000) + yield bus # test invoked here + + bus.shutdown() + except Exception as e: + pytest.skip(f'Open usb-can bus Error: {str(e)}') + finally: + subprocess.run(stop_command, shell=True, capture_output=True, text=True) + + +# --------------------------------------------------------------------------- +# Interactive Tests +# --------------------------------------------------------------------------- @pytest.mark.twai_std @@ -46,14 +91,13 @@ def fixture_create_socket_can() -> Bus: ) @idf_parametrize('target', ['esp32', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32s2', 'esp32s3'], indirect=['target']) def test_legacy_twai_listen_only(dut: Dut, socket_can: Bus) -> None: - dut.serial.hard_reset() - dut.expect_exact('Press ENTER to see the list of tests') + esp_reset_and_wait_ready(dut) # TEST_CASE("twai_listen_only", "[twai]") dut.write('"twai_listen_only"') - # wait the DUT to block at the receive API - sleep(0.03) + # wait the DUT to start listening + time.sleep(0.1) message = Message( arbitration_id=0x123, @@ -62,6 +106,7 @@ def test_legacy_twai_listen_only(dut: Dut, socket_can: Bus) -> None: ) socket_can.send(message, timeout=0.2) dut.expect_unity_test_output() + esp_enter_flash_mode(dut) @pytest.mark.twai_std @@ -74,8 +119,7 @@ def test_legacy_twai_listen_only(dut: Dut, socket_can: Bus) -> None: ) @idf_parametrize('target', ['esp32', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32s2', 'esp32s3'], indirect=['target']) def test_legacy_twai_remote_request(dut: Dut, socket_can: Bus) -> None: - dut.serial.hard_reset() - dut.expect_exact('Press ENTER to see the list of tests') + esp_reset_and_wait_ready(dut) # TEST_CASE("twai_remote_request", "[twai]") dut.write('"twai_remote_request"') @@ -97,3 +141,4 @@ def test_legacy_twai_remote_request(dut: Dut, socket_can: Bus) -> None: print('send', reply) dut.expect_unity_test_output() + esp_enter_flash_mode(dut) diff --git a/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py b/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py index 846b2bf8dc..6c22dad488 100644 --- a/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py +++ b/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 import subprocess -from time import sleep +import time import pytest from can import Bus @@ -12,6 +12,9 @@ from pytest_embedded_idf.utils import idf_parametrize from pytest_embedded_idf.utils import soc_filtered_targets +# --------------------------------------------------------------------------- +# Loop Back Tests +# --------------------------------------------------------------------------- @pytest.mark.generic @pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='p4 rev3 migration, IDF-14393') @pytest.mark.parametrize('config', ['release', 'cache_safe'], indirect=True) @@ -20,43 +23,77 @@ def test_driver_twai_loopbk(dut: Dut) -> None: dut.run_all_single_board_cases(group='twai', reset=True) -# -------------------------------- test twai interactive ------------------------------ +# --------------------------------------------------------------------------- +# Helper Functions +# --------------------------------------------------------------------------- + + +def esp_enter_flash_mode(dut: Dut) -> None: + ser = dut.serial.proc + ser.setRTS(True) # EN Low + time.sleep(0.5) + ser.setDTR(True) # GPIO0 Low + ser.setRTS(False) # EN High + dut.expect('waiting for download', timeout=2) + ser.setDTR(False) # Back RTS/DTR to 1/1 to avoid affect to esptool + + +def esp_reset_and_wait_ready(dut: Dut) -> None: + dut.serial.hard_reset() + time.sleep(0.5) + dut.expect_exact('Press ENTER to see the list of tests') + + @pytest.fixture(name='socket_can') def fixture_create_socket_can() -> Bus: # Set up the socket CAN with the bitrate - start_command = 'sudo ip link set can0 up type can bitrate 250000' - stop_command = 'sudo ip link set can0 down' + start_command = 'sudo -n ip link set can0 up type can bitrate 250000 restart-ms 100' + stop_command = 'sudo -n ip link set can0 down' + status_command = 'sudo -n ip -details link show can0' + try: + result = subprocess.run(status_command, shell=True, capture_output=True, text=True) + if result.returncode != 0: + raise Exception('CAN interface "can0" not found') + + if 'UP' in result.stdout: # Close the bus anyway if it is already up + subprocess.run(stop_command, shell=True, capture_output=True, text=True) subprocess.run(start_command, shell=True, capture_output=True, text=True) + + time.sleep(0.5) + bus = Bus(interface='socketcan', channel='can0', bitrate=250000) + yield bus # test invoked here + + bus.shutdown() except Exception as e: - print(f'Open bus Error: {e}') - bus = Bus(interface='socketcan', channel='can0', bitrate=250000) - yield bus # test invoked here - bus.shutdown() - subprocess.run(stop_command, shell=True, capture_output=True, text=True) + pytest.skip(f'Open usb-can bus Error: {str(e)}') + finally: + subprocess.run(stop_command, shell=True, capture_output=True, text=True) +# --------------------------------------------------------------------------- +# Interactive Tests +# --------------------------------------------------------------------------- @pytest.mark.twai_std @pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='p4 rev3 migration, IDF-14393') @pytest.mark.parametrize('config', ['release'], indirect=True) @idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target']) def test_driver_twai_listen_only(dut: Dut, socket_can: Bus) -> None: - dut.serial.hard_reset() - dut.expect_exact('Press ENTER to see the list of tests') + esp_reset_and_wait_ready(dut) dut.write('"twai_listen_only"') # wait the DUT to finish initialize - sleep(0.1) + time.sleep(0.1) message = Message( arbitration_id=0x6688, is_extended_id=True, data=[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88], ) - print('USB Socket CAN Send:', message) - socket_can.send(message, timeout=0.2) + print('USB Socket CAN Send:', message, 'Return:', socket_can.send(message)) dut.expect_unity_test_output(timeout=10) + esp_enter_flash_mode(dut) @pytest.mark.twai_std @@ -64,8 +101,7 @@ def test_driver_twai_listen_only(dut: Dut, socket_can: Bus) -> None: @pytest.mark.parametrize('config', ['release'], indirect=True) @idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target']) def test_driver_twai_remote_request(dut: Dut, socket_can: Bus) -> None: - dut.serial.hard_reset() - dut.expect_exact('Press ENTER to see the list of tests') + esp_reset_and_wait_ready(dut) dut.write('"twai_remote_request"') @@ -83,4 +119,6 @@ def test_driver_twai_remote_request(dut: Dut, socket_can: Bus) -> None: ) socket_can.send(reply, timeout=0.2) print('USB Socket CAN Replied:', reply) + dut.expect_unity_test_output(timeout=10) + esp_enter_flash_mode(dut) From c5b01fc62762349461558ea3f8a72733c0f98ce4 Mon Sep 17 00:00:00 2001 From: "peter.marcisovsky" Date: Thu, 4 Dec 2025 16:32:01 +0100 Subject: [PATCH 052/156] fix(usb_host): Dont abort on unsupported client events - suspend and resume client events --- .../usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c | 3 +-- examples/peripherals/usb/host/hid/main/hid_host_example.c | 5 +++-- examples/peripherals/usb/host/msc/main/msc_example_main.c | 2 ++ .../peripherals/usb/host/usb_host_lib/main/class_driver.c | 6 +++--- examples/peripherals/usb/host/uvc/main/main.c | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c b/examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c index f8c548e01a..4f8b4d02c9 100644 --- a/examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c +++ b/examples/peripherals/usb/host/cdc/cdc_acm_host/main/usb_cdc_example_main.c @@ -67,9 +67,8 @@ static void handle_event(const cdc_acm_host_dev_event_data_t *event, void *user_ case CDC_ACM_HOST_SERIAL_STATE: ESP_LOGI(TAG, "Serial state notif 0x%04X", event->data.serial_state.val); break; - case CDC_ACM_HOST_NETWORK_CONNECTION: default: - ESP_LOGW(TAG, "Unsupported CDC event: %i", event->type); + ESP_LOGW(TAG, "Unsupported CDC event: %d (possibly suspend/resume)", event->type); break; } } diff --git a/examples/peripherals/usb/host/hid/main/hid_host_example.c b/examples/peripherals/usb/host/hid/main/hid_host_example.c index d7e25f1015..16756b1f1b 100644 --- a/examples/peripherals/usb/host/hid/main/hid_host_example.c +++ b/examples/peripherals/usb/host/hid/main/hid_host_example.c @@ -502,8 +502,9 @@ void hid_host_interface_callback(hid_host_device_handle_t hid_device_handle, hid_proto_name_str[dev_params.proto]); break; default: - ESP_LOGE(TAG, "HID Device, protocol '%s' Unhandled event", - hid_proto_name_str[dev_params.proto]); + ESP_LOGW(TAG, "HID Device, protocol '%s' Unhandled event: %d (possibly suspend/resume)", + hid_proto_name_str[dev_params.proto], + event); break; } } diff --git a/examples/peripherals/usb/host/msc/main/msc_example_main.c b/examples/peripherals/usb/host/msc/main/msc_example_main.c index 690fb82dd3..8508d0a96a 100644 --- a/examples/peripherals/usb/host/msc/main/msc_example_main.c +++ b/examples/peripherals/usb/host/msc/main/msc_example_main.c @@ -264,6 +264,8 @@ static void msc_event_cb(const msc_host_event_t *event, void *arg) .data.device_handle = event->device.handle, }; xQueueSend(app_queue, &message, portMAX_DELAY); + } else { + ESP_LOGW(TAG, "Unsupported MSC event: %d (possibly suspend/resume)", event->event); } } diff --git a/examples/peripherals/usb/host/usb_host_lib/main/class_driver.c b/examples/peripherals/usb/host/usb_host_lib/main/class_driver.c index 5a89e40dea..a0b656b977 100644 --- a/examples/peripherals/usb/host/usb_host_lib/main/class_driver.c +++ b/examples/peripherals/usb/host/usb_host_lib/main/class_driver.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -80,8 +80,8 @@ static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void * xSemaphoreGive(driver_obj->constant.mux_lock); break; default: - // Should never occur - abort(); + ESP_LOGW(TAG, "Unsupported client event: %d (possibly suspend/resume)", event_msg->event); + break; } } diff --git a/examples/peripherals/usb/host/uvc/main/main.c b/examples/peripherals/usb/host/uvc/main/main.c index 60edd7326b..91d6548609 100644 --- a/examples/peripherals/usb/host/uvc/main/main.c +++ b/examples/peripherals/usb/host/uvc/main/main.c @@ -114,7 +114,7 @@ static void stream_callback(const uvc_host_stream_event_data_t *event, void *use ESP_LOGW(TAG, "Frame buffer underflow"); break; default: - abort(); + ESP_LOGW(TAG, "Unsupported UVC event: %d (possibly suspend/resume)", event->type); break; } } From 3146ab33abeb8275afcc8a4ef1fb890d71398c8c Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Wed, 10 Dec 2025 12:06:43 +0800 Subject: [PATCH 053/156] fix(esp_system): fix c61 mspi core/axi reset order --- components/esp_system/port/soc/esp32c61/system_internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_system/port/soc/esp32c61/system_internal.c b/components/esp_system/port/soc/esp32c61/system_internal.c index 896dc34e3c..0f7991676e 100644 --- a/components/esp_system/port/soc/esp32c61/system_internal.c +++ b/components/esp_system/port/soc/esp32c61/system_internal.c @@ -62,8 +62,8 @@ void esp_system_reset_modules_on_exit(void) SET_PERI_REG_MASK(PCR_REGDMA_CONF_REG, PCR_REGDMA_RST_EN); // Clear Peripheral clk rst - CLEAR_PERI_REG_MASK(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); // Must release mspi core reset before mspi AXI. CLEAR_PERI_REG_MASK(PCR_MSPI_CONF_REG, PCR_MSPI_RST_EN); + CLEAR_PERI_REG_MASK(PCR_MSPI_CLK_CONF_REG, PCR_MSPI_AXI_RST_EN); // Must release mspi core reset before mspi AXI. CLEAR_PERI_REG_MASK(PCR_UART0_CONF_REG, PCR_UART0_RST_EN); CLEAR_PERI_REG_MASK(PCR_UART1_CONF_REG, PCR_UART1_RST_EN); CLEAR_PERI_REG_MASK(PCR_SYSTIMER_CONF_REG, PCR_SYSTIMER_RST_EN); From a5601fbf0d50997642f3eb5f952dc629d3ab7f67 Mon Sep 17 00:00:00 2001 From: Mahavir Jain Date: Thu, 20 Nov 2025 14:22:40 +0530 Subject: [PATCH 054/156] fix(protocomm): add validation for Security1 client verifier data Add checks to validate client_verify_data pointer and length before processing in handle_session_command1. Prevents NULL pointer dereference when client omits verifier data in Session_Command1, which could cause device crash during provisioning (remote DoS attack). We would like to thank Pavel Kohout from Aisle Research for reporting this vulnerability along with a mitigation strategy. --- components/protocomm/src/security/security1.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/components/protocomm/src/security/security1.c b/components/protocomm/src/security/security1.c index 08911df4fd..da707ea175 100644 --- a/components/protocomm/src/security/security1.c +++ b/components/protocomm/src/security/security1.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -101,6 +101,21 @@ static esp_err_t handle_session_command1(session_t *cur_session, return ESP_ERR_INVALID_STATE; } + /* Validate client verifier data before processing */ + if (!in || !in->sc1 || + in->sc1->client_verify_data.data == NULL || + in->sc1->client_verify_data.len != PUBLIC_KEY_LEN) { + ESP_LOGE(TAG, "Invalid client verifier (ptr=%p len=%d)", + (void *) (in && in->sc1 ? in->sc1->client_verify_data.data : NULL), + (int) (in && in->sc1 ? in->sc1->client_verify_data.len : -1)); + if (esp_event_post(PROTOCOMM_SECURITY_SESSION_EVENT, + PROTOCOMM_SECURITY_SESSION_INVALID_SECURITY_PARAMS, + NULL, 0, portMAX_DELAY) != ESP_OK) { + ESP_LOGE(TAG, "Failed to post invalid security params event"); + } + return ESP_ERR_INVALID_ARG; + } + /* Initialize crypto context */ mbedtls_aes_init(&cur_session->ctx_aes); memset(cur_session->stb, 0, sizeof(cur_session->stb)); From c3c6304091f479194e1356e13d331b4cafb25999 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Thu, 11 Dec 2025 16:21:47 +0800 Subject: [PATCH 055/156] feat(ble/blufi): Support setting BLE encryption for blufi (cherry picked from commit 60a028fb17cb6462fbe7a5c4e5573bffef6fa029) Co-authored-by: zhanghaipeng --- .../esp/blufi/bluedroid_host/esp_blufi.c | 166 +++++++++++++++++- .../btc/profile/esp/blufi/include/esp_blufi.h | 18 +- components/bt/host/bluedroid/Kconfig.in | 10 ++ docs/en/api-guides/ble/blufi.rst | 39 +++- docs/zh_CN/api-guides/ble/blufi.rst | 39 +++- .../main/ble_compatibility_test.c | 2 +- examples/bluetooth/blufi/README.md | 6 + .../bluetooth/blufi/main/Kconfig.projbuild | 19 ++ .../bluetooth/blufi/main/blufi_example_main.c | 10 +- examples/bluetooth/blufi/main/blufi_init.c | 39 +++- 10 files changed, 332 insertions(+), 16 deletions(-) diff --git a/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c b/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c index 744c0df83a..380da2edb5 100644 --- a/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c +++ b/components/bt/common/btc/profile/esp/blufi/bluedroid_host/esp_blufi.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -32,6 +32,7 @@ #include "esp_bt_device.h" #include "esp_err.h" #include "esp_blufi.h" +#include #if (BLUFI_INCLUDED == TRUE) @@ -70,12 +71,155 @@ static esp_ble_adv_params_t blufi_adv_params = { .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, }; +#ifdef CONFIG_BT_BLUFI_BLE_SMP_ENABLE +static char *esp_auth_req_to_str(esp_ble_auth_req_t auth_req) +{ + char *auth_str = NULL; + switch(auth_req) { + case ESP_LE_AUTH_NO_BOND: + auth_str = "ESP_LE_AUTH_NO_BOND"; + break; + case ESP_LE_AUTH_BOND: + auth_str = "ESP_LE_AUTH_BOND"; + break; + case ESP_LE_AUTH_REQ_MITM: + auth_str = "ESP_LE_AUTH_REQ_MITM"; + break; + case ESP_LE_AUTH_REQ_BOND_MITM: + auth_str = "ESP_LE_AUTH_REQ_BOND_MITM"; + break; + case ESP_LE_AUTH_REQ_SC_ONLY: + auth_str = "ESP_LE_AUTH_REQ_SC_ONLY"; + break; + case ESP_LE_AUTH_REQ_SC_BOND: + auth_str = "ESP_LE_AUTH_REQ_SC_BOND"; + break; + case ESP_LE_AUTH_REQ_SC_MITM: + auth_str = "ESP_LE_AUTH_REQ_SC_MITM"; + break; + case ESP_LE_AUTH_REQ_SC_MITM_BOND: + auth_str = "ESP_LE_AUTH_REQ_SC_MITM_BOND"; + break; + default: + auth_str = "INVALID BLE AUTH REQ"; + break; + } + + return auth_str; +} + +static char *esp_key_type_to_str(esp_ble_key_type_t key_type) +{ + char *key_str = NULL; + switch(key_type) { + case ESP_LE_KEY_NONE: + key_str = "ESP_LE_KEY_NONE"; + break; + case ESP_LE_KEY_PENC: + key_str = "ESP_LE_KEY_PENC"; + break; + case ESP_LE_KEY_PID: + key_str = "ESP_LE_KEY_PID"; + break; + case ESP_LE_KEY_PCSRK: + key_str = "ESP_LE_KEY_PCSRK"; + break; + case ESP_LE_KEY_PLK: + key_str = "ESP_LE_KEY_PLK"; + break; + case ESP_LE_KEY_LLK: + key_str = "ESP_LE_KEY_LLK"; + break; + case ESP_LE_KEY_LENC: + key_str = "ESP_LE_KEY_LENC"; + break; + case ESP_LE_KEY_LID: + key_str = "ESP_LE_KEY_LID"; + break; + case ESP_LE_KEY_LCSRK: + key_str = "ESP_LE_KEY_LCSRK"; + break; + default: + key_str = "INVALID BLE KEY TYPE"; + break; + } + return key_str; +} +#endif + void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) { + BLUFI_TRACE_DEBUG("GAP_EVT, event %d", event); switch (event) { case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&blufi_adv_params); break; + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: + //advertising start complete event to indicate advertising start successfully or failed + if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + BTC_TRACE_ERROR("Advertising start failed, status %x", param->adv_start_cmpl.status); + break; + } + BLUFI_TRACE_API("Advertising start successfully"); + break; +#ifdef CONFIG_BT_BLUFI_BLE_SMP_ENABLE + case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ + BLUFI_TRACE_API("Passkey request"); + break; + case ESP_GAP_BLE_OOB_REQ_EVT: { + BLUFI_TRACE_API("OOB request"); + uint8_t tk[16] = {1}; //If you paired with OOB, both devices need to use the same tk + esp_ble_oob_req_reply(param->ble_security.ble_req.bd_addr, tk, sizeof(tk)); + break; + } + case ESP_GAP_BLE_LOCAL_IR_EVT: /* BLE local IR event */ + BLUFI_TRACE_API("Local identity root"); + break; + case ESP_GAP_BLE_LOCAL_ER_EVT: /* BLE local ER event */ + BLUFI_TRACE_API("Local encryption root"); + break; + case ESP_GAP_BLE_NC_REQ_EVT: + /* The app will receive this evt when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability. + show the passkey number to the user to confirm it with the number displayed by peer device. */ + esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, true); + BLUFI_TRACE_WARNING("Numeric Comparison request, passkey %" PRIu32, param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_SEC_REQ_EVT: + /* send the positive(true) security response to the peer device to accept the security request. + If not accept the security request, should send the security response with negative(false) accept value*/ + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); + break; + case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. + ///show the passkey number to the user to input it in the peer device. + BLUFI_TRACE_WARNING("Passkey notify, passkey %06" PRIu32, param->ble_security.key_notif.passkey); + break; + case ESP_GAP_BLE_KEY_EVT: + //shows the ble key info share with peer device to the user. + BLUFI_TRACE_API("Key exchanged, key_type %s", esp_key_type_to_str(param->ble_security.ble_key.key_type)); + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: { + esp_bd_addr_t bd_addr; + memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t)); + BLUFI_TRACE_API("Authentication complete, addr_type %u, addr "ESP_BD_ADDR_STR"", + param->ble_security.auth_cmpl.addr_type, ESP_BD_ADDR_HEX(bd_addr)); + if(!param->ble_security.auth_cmpl.success) { + BLUFI_TRACE_WARNING("Pairing failed, reason 0x%x",param->ble_security.auth_cmpl.fail_reason); + } else { + BLUFI_TRACE_WARNING("Pairing successfully, auth_mode %s",esp_auth_req_to_str(param->ble_security.auth_cmpl.auth_mode)); + } + break; + } + case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT: { + BLUFI_TRACE_DEBUG("Bond device remove, status %d, device "ESP_BD_ADDR_STR"", + param->remove_bond_dev_cmpl.status, ESP_BD_ADDR_HEX(param->remove_bond_dev_cmpl.bd_addr)); + break; + } + case ESP_GAP_BLE_SET_LOCAL_PRIVACY_COMPLETE_EVT: + if (param->local_privacy_cmpl.status != ESP_BT_STATUS_SUCCESS){ + BLUFI_TRACE_WARNING("Local privacy config failed, status %x", param->local_privacy_cmpl.status); + } + break; +#endif // CONFIG_BT_BLUFI_BLE_SMP_ENABLE default: break; } @@ -251,10 +395,16 @@ static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data) break; case BTA_GATTS_CREATE_EVT: blufi_env.handle_srvc = p_data->create.service_id; - + #if CONFIG_BT_BLUFI_BLE_SMP_ENABLE + BLUFI_TRACE_WARNING("BLE SMP support in BLUFI is ENABLED!"); + #endif // CONFIG_BT_BLUFI_BLE_SMP_ENABLE //add the first blufi characteristic --> write characteristic BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_p2e, - (GATT_PERM_WRITE), + #if CONFIG_BT_BLUFI_BLE_SMP_ENABLE + GATT_PERM_WRITE_ENC_MITM, + #else + GATT_PERM_WRITE, + #endif (GATT_CHAR_PROP_BIT_WRITE), NULL, NULL); break; @@ -398,6 +548,16 @@ void esp_blufi_adv_stop(void) esp_ble_gap_stop_advertising(); } + +esp_err_t esp_blufi_start_security_request(esp_blufi_bd_addr_t remote_bda) +{ + #ifdef CONFIG_BT_BLUFI_BLE_SMP_ENABLE + return esp_ble_set_encryption(remote_bda, ESP_BLE_SEC_ENCRYPT_MITM); + #else + return ESP_ERR_INVALID_STATE; + #endif // CONFIG_BT_BLUFI_BLE_SMP_ENABLE +} + void esp_blufi_send_encap(void *arg) { struct blufi_hdr *hdr = (struct blufi_hdr *)arg; diff --git a/components/bt/common/btc/profile/esp/blufi/include/esp_blufi.h b/components/bt/common/btc/profile/esp/blufi/include/esp_blufi.h index 8dc9a674ba..96d97591df 100644 --- a/components/bt/common/btc/profile/esp/blufi/include/esp_blufi.h +++ b/components/bt/common/btc/profile/esp/blufi/include/esp_blufi.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -90,6 +90,22 @@ void esp_blufi_adv_start_with_name(const char *name); void esp_blufi_send_encap(void *arg); +/* + * @brief Initiate BLE security request with the connected peer device. + * + * This function triggers the BLE Security Manager Protocol (SMP) procedure + * to establish a secure, encrypted connection with the specified remote device. + * It should be called after a BLE connection is established. + * + * @param[in] remote_bda Bluetooth device address of the connected peer. + * + * @return + * - ESP_OK: Security request initiated successfully + * - ESP_FAIL: Security request failed + * - ESP_ERR_INVALID_STATE: BluFi BLE SMP is not enabled + */ +esp_err_t esp_blufi_start_security_request(esp_blufi_bd_addr_t remote_bda); + #ifdef CONFIG_BT_NIMBLE_ENABLED /** * @brief Handle gap event for BluFi. diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in index 1d4b24b195..34165f97d9 100644 --- a/components/bt/host/bluedroid/Kconfig.in +++ b/components/bt/host/bluedroid/Kconfig.in @@ -298,6 +298,16 @@ config BT_BLE_BLUFI_ENABLE help This option can be close when the app does not require blufi function. +config BT_BLUFI_BLE_SMP_ENABLE + bool "Enable BLE SMP support for BluFi" + depends on BT_BLE_BLUFI_ENABLE && BT_BLE_SMP_ENABLE + default n + help + Enable BLE Security Manager Protocol (SMP) for BluFi. + When enabled, BluFi will support BLE pairing and encryption + before Wi-Fi provisioning, providing a more secure provisioning process. + This feature is only supported with the Bluedroid host. + config BT_GATT_MAX_SR_PROFILES int "Max GATT Server Profiles" depends on BT_GATTS_ENABLE && BT_BLUEDROID_ENABLED diff --git a/docs/en/api-guides/ble/blufi.rst b/docs/en/api-guides/ble/blufi.rst index 22f9bc8cb8..13cde0a83a 100644 --- a/docs/en/api-guides/ble/blufi.rst +++ b/docs/en/api-guides/ble/blufi.rst @@ -12,6 +12,16 @@ Fragmenting, data encryption, and checksum verification in the BluFi layer are t You can customize symmetric encryption, asymmetric encryption, and checksum support customization. Here we use the DH algorithm for key negotiation, 128-AES algorithm for data encryption, and CRC16 algorithm for checksum verification. +.. note:: + + **BluFi is currently in maintenance mode, and no new features are planned.** + + For new projects or when adding Wi-Fi provisioning, we recommend using the network_provisioning component + + (`network_provisioning `_) + + for a modern, secure, and actively maintained solution. + Getting Started ----------------- @@ -693,15 +703,36 @@ The data to be encrypted and decrypted must be in the same length. The IV8 is an This function is used to compute CheckSum and return a value of CheckSum. BluFi uses the returned value to compare the CheckSum of the frame. -5. Implementing Stronger Security +5. BLE SMP Encryption for Blufi -The default encryption/decryption logic in this example is intended for demonstration purposes only. +Before Wi-Fi provisioning, you can use BLE SMP pairing to establish a secure connection, making the provisioning process safer. -If you require a higher level of security, it is recommended to implement your own encryption, decryption, authentication, and checksum algorithms by customizing the security callbacks in the BluFi framework. +This feature can be enabled or disabled via the configuration option: .. code-block:: c - esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks) + CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + +If this option is enabled, the ESP32 device will issue a pairing request once it is connected. Only after a successful pairing can the device proceed with provisioning. + +Currently, BLE SMP pairing is supported **only on the Bluedroid host**. + +6. Implementing Stronger Security + +The default encryption and decryption logic in this example is intended for demonstration purposes only. + +If you require a higher level of security, you may consider one of the following approaches: + +1. **Custom Security Callbacks** – Implement your own encryption, decryption, authentication, and checksum algorithms by customizing the security callbacks in the Blufi framework: + + .. code-block:: c + + esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks); + +2. **Network Provisioning Component (recommended)** – Alternatively, you can use the network_provisioning component for a secure, ready-to-use provisioning solution: + + `network_provisioning `_ + GATT Related Instructions ---------------------------- diff --git a/docs/zh_CN/api-guides/ble/blufi.rst b/docs/zh_CN/api-guides/ble/blufi.rst index 50a170ffae..844ed27c43 100644 --- a/docs/zh_CN/api-guides/ble/blufi.rst +++ b/docs/zh_CN/api-guides/ble/blufi.rst @@ -12,6 +12,16 @@ BluFi 流程的关键部分包括数据的分片、加密以及校验和验证 用户可按需自定义用于对称加密、非对称加密以及校验的算法。此处,我们采用 DH 算法进行密钥协商,128-AES 算法用于数据加密,CRC16 算法用于校验和验证。 +.. note:: + + **BluFi 目前处于维护模式,不再规划新功能。** + + 对于新项目或新增 Wi-Fi 配网的场景,建议使用 network_provisioning 组件 + + (`network_provisioning `_) + + 来实现现代化、安全且有持续维护的解决方案。 + 快速入门 -------- @@ -693,15 +703,36 @@ BluFi 会在调用完 Negotiate_data_handler 后,发送 Negotiate_data_handler 该函数用来进行校验,返回值为校验的值。BluFi 会使用该函数返回值与帧的校验值进行比较。 -5. 实现更强的安全性 +5. BLE SMP Encryption for Blufi -本示例中默认的加密/解密逻辑仅用于演示目的。 +在 Wi-Fi 配网之前,可以使用 BLE SMP 配对建立安全连接,使配网过程更安全。 -如果需要更高等级的安全性,建议通过自定义 BluFi 框架中的安全回调函数,实现您自己的加密、解密、认证以及校验算法。 +此功能可通过配置选项启用或禁用: .. code-block:: c - esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks) + CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + +如果启用该选项,ESP32 设备在连接成功后会发起配对请求。仅在配对成功后,设备才可继续进行 Wi-Fi 配网。 + +目前 BLE SMP 配对 **仅支持 Bluedroid 主机**。 + +6. 实现更强的安全性 + +示例中的默认加密/解密逻辑仅用于演示目的。 + +如果需要更高等级的安全性,可以考虑以下方法: + +1. **自定义安全回调** – 通过自定义 BluFi 框架中的安全回调函数,实现自己的加密、解密、认证以及校验算法: + + .. code-block:: c + + esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks); + +2. **Network Provisioning 组件(推荐使用)** – 或者可以使用 ESP-IDF 提供的 network_provisioning 组件,实现安全、可直接使用的配网解决方案: + + `network_provisioning `_ + GATT 相关说明 diff --git a/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c index 34b6cc1185..171289a8a9 100644 --- a/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c +++ b/examples/bluetooth/bluedroid/ble/ble_compatibility_test/main/ble_compatibility_test.c @@ -695,7 +695,7 @@ void app_main(void) /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/ esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; //bonding with peer device after authentication - esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; //set the IO capability to No output No input + esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; //set the IO capability to DisplayOnly uint8_t key_size = 16; //the key size should be 7~16 bytes uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; diff --git a/examples/bluetooth/blufi/README.md b/examples/bluetooth/blufi/README.md index 6a07013c72..6534187eb9 100644 --- a/examples/bluetooth/blufi/README.md +++ b/examples/bluetooth/blufi/README.md @@ -82,3 +82,9 @@ I (1198) BLUFI_EXAMPLE: BLUFI init finish ## Troubleshooting For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. + +## Note +BluFi is currently in maintenance mode, and no new features are planned. + +For new projects or when adding network_provisioning, we recommend using the [network_provisioning](https://github.com/espressif/idf-extra-components/tree/master/network_provisioning). + diff --git a/examples/bluetooth/blufi/main/Kconfig.projbuild b/examples/bluetooth/blufi/main/Kconfig.projbuild index b8fe9f1957..fc1a20695b 100644 --- a/examples/bluetooth/blufi/main/Kconfig.projbuild +++ b/examples/bluetooth/blufi/main/Kconfig.projbuild @@ -33,4 +33,23 @@ menu "Example Configuration" bool "WAPI PSK" endchoice + config EXAMPLE_BLUFI_BLE_SMP_ENABLE + bool "Enable BLE SMP support in BLUFI" + depends on BT_BLUEDROID_ENABLED + select BT_BLUFI_BLE_SMP_ENABLE + select BT_BLE_SMP_ENABLE + default n + help + Enable BLE Security Manager Protocol (SMP) for BLUFI. + Currently, this feature is only supported with the Bluedroid host. + + If enabled: + - BLUFI will configure SMP security parameters such as + IO capabilities, authentication mode, and key size. + - After a BLE connection is established, BLUFI will + proactively initiate a security request. + - Only after the BLE pairing is successfully completed, + BLUFI can proceed with Wi-Fi provisioning. + - If the user rejects pairing or inputs an incorrect passkey, + BLUFI will not start Wi-Fi provisioning. endmenu diff --git a/examples/bluetooth/blufi/main/blufi_example_main.c b/examples/bluetooth/blufi/main/blufi_example_main.c index 9d3d05360d..b5dbf3e7ee 100644 --- a/examples/bluetooth/blufi/main/blufi_example_main.c +++ b/examples/bluetooth/blufi/main/blufi_example_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -319,6 +319,14 @@ static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_para ble_is_connected = true; esp_blufi_adv_stop(); blufi_security_init(); + #ifdef CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + // Try to initiate BLE security request after connection established. + BLUFI_INFO("Try to initiate BLE security request\n"); + esp_err_t ret = esp_blufi_start_security_request(param->connect.remote_bda); + if (ret != ESP_OK) { + BLUFI_ERROR("Failed to start security request: %s\n", esp_err_to_name(ret)); + } + #endif // CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE break; case ESP_BLUFI_EVENT_BLE_DISCONNECT: BLUFI_INFO("BLUFI ble disconnect\n"); diff --git a/examples/bluetooth/blufi/main/blufi_init.c b/examples/bluetooth/blufi/main/blufi_init.c index ea998657e9..2c1af14bc8 100644 --- a/examples/bluetooth/blufi/main/blufi_init.c +++ b/examples/bluetooth/blufi/main/blufi_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -16,6 +16,7 @@ #ifdef CONFIG_BT_BLUEDROID_ENABLED #include "esp_bt_main.h" #include "esp_bt_device.h" +#include "esp_gap_ble_api.h" #endif #ifdef CONFIG_BT_NIMBLE_ENABLED @@ -56,6 +57,37 @@ esp_err_t esp_blufi_host_init(void) } +#ifdef CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + +void esp_blufi_set_ble_security_params(void) +{ + /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/ + esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM; // Secure Connections with MITM protection (no bonding) + esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; // IO capability: DisplayOnly + uint8_t key_size = 16; //the key size should be 7~16 bytes + uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + //set static passkey + uint32_t passkey = 123456; + uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE; + uint8_t oob_support = ESP_BLE_OOB_DISABLE; + BLUFI_INFO("BLE SMP passkey: %06" PRIu32 " (WARNING: Change this default value for production or don't use static passkey!)\n", passkey); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t)); + /* If your BLE device acts as a Slave, the init_key means you hope which types of key of the master should distribute to you, + and the response key means which key you can distribute to the master; + If your BLE device acts as a master, the response key means you hope which types of key of the slave should distribute to you, + and the init key means which key you can distribute to the slave. */ + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t)); +} + +#endif // #if CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + esp_err_t esp_blufi_host_deinit(void) { int ret; @@ -112,8 +144,11 @@ esp_err_t esp_blufi_host_and_cb_init(esp_blufi_callbacks_t *example_callbacks) return ret; } - return ESP_OK; + #ifdef CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + esp_blufi_set_ble_security_params(); + #endif // CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE + return ESP_OK; } #endif /* CONFIG_BT_BLUEDROID_ENABLED */ From 540b6bad349d50c3199154ec82c0243b4bdc1a65 Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Thu, 11 Dec 2025 16:21:48 +0800 Subject: [PATCH 056/156] docs: Update CN translation and improve formatting (cherry picked from commit feff20614e4408aa3682ab88bf389f8db58b890e) Co-authored-by: Zhang Shuxian --- docs/en/api-guides/ble/blufi.rst | 87 +++++++++++----------------- docs/zh_CN/api-guides/ble/blufi.rst | 89 ++++++++++++----------------- 2 files changed, 69 insertions(+), 107 deletions(-) diff --git a/docs/en/api-guides/ble/blufi.rst b/docs/en/api-guides/ble/blufi.rst index 13cde0a83a..718f7abaab 100644 --- a/docs/en/api-guides/ble/blufi.rst +++ b/docs/en/api-guides/ble/blufi.rst @@ -16,11 +16,7 @@ You can customize symmetric encryption, asymmetric encryption, and checksum supp **BluFi is currently in maintenance mode, and no new features are planned.** - For new projects or when adding Wi-Fi provisioning, we recommend using the network_provisioning component - - (`network_provisioning `_) - - for a modern, secure, and actively maintained solution. + For new projects or when adding Wi-Fi provisioning, we recommend using the `network_provisioning`_ component, which offers a modern, secure, and actively maintained solution. Getting Started @@ -675,64 +671,46 @@ The Security Implementation of {IDF_TARGET_NAME} The application layer needs to register several security-related functions to BluFi: -.. code-block:: c + .. code-block:: c - typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free) + typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free) -This function is for {IDF_TARGET_NAME} to receive normal data during negotiation. After processing is completed, the data will be transmitted using Output_data and Output_len. + This function is for {IDF_TARGET_NAME} to receive normal data during negotiation. After processing is completed, the data will be transmitted using Output_data and Output_len. -BluFi will send output_data from Negotiate_data_handler after Negotiate_data_handler is called. + BluFi will send output_data from Negotiate_data_handler after Negotiate_data_handler is called. -Here are two "*", which means the length of the data to be emitted is unknown. Therefore, it requires the function to allocate itself (malloc) or point to the global variable to inform whether the memory needs to be freed by NEED_FREE. - -.. code-block:: c - - typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) - -The data to be encrypted and decrypted must be in the same length. The IV8 is an 8-bit sequence value of frames, which can be used as a 8-bit of IV. - -.. code-block:: c - - typedef int (* esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) - -The data to be encrypted and decrypted must be in the same length. The IV8 is an 8-bit sequence value of frames, which can be used as an 8-bit of IV. - -.. code-block:: c - - typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len) - -This function is used to compute CheckSum and return a value of CheckSum. BluFi uses the returned value to compare the CheckSum of the frame. - -5. BLE SMP Encryption for Blufi - -Before Wi-Fi provisioning, you can use BLE SMP pairing to establish a secure connection, making the provisioning process safer. - -This feature can be enabled or disabled via the configuration option: - -.. code-block:: c - - CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE - -If this option is enabled, the ESP32 device will issue a pairing request once it is connected. Only after a successful pairing can the device proceed with provisioning. - -Currently, BLE SMP pairing is supported **only on the Bluedroid host**. - -6. Implementing Stronger Security - -The default encryption and decryption logic in this example is intended for demonstration purposes only. - -If you require a higher level of security, you may consider one of the following approaches: - -1. **Custom Security Callbacks** – Implement your own encryption, decryption, authentication, and checksum algorithms by customizing the security callbacks in the Blufi framework: + Here are two ``*``, which means the length of the data to be emitted is unknown. Therefore, it requires the function to allocate itself (malloc) or point to the global variable to inform whether the memory needs to be freed by NEED_FREE. .. code-block:: c - esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks); + typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) -2. **Network Provisioning Component (recommended)** – Alternatively, you can use the network_provisioning component for a secure, ready-to-use provisioning solution: + The data to be encrypted and decrypted must be in the same length. The IV8 is an 8-bit sequence value of frames, which can be used as a 8-bit of IV. - `network_provisioning `_ + .. code-block:: c + typedef int (* esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) + + The data to be encrypted and decrypted must be in the same length. The IV8 is an 8-bit sequence value of frames, which can be used as an 8-bit of IV. + + .. code-block:: c + + typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len) + + This function is used to compute CheckSum and return a value of CheckSum. BluFi uses the returned value to compare the CheckSum of the frame. + + +5. Implementing Stronger Security + + The default encryption and decryption logic in this example is intended for demonstration purposes only. If your application requires stronger security guarantees, consider one of the following approaches: + + - **Custom Security Callbacks**: Implement your own encryption, decryption, authentication, and checksum algorithms by defining custom security callbacks in the Blufi framework: + + .. code-block:: c + + esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks); + + - **Network Provisioning Component (recommended)**: For a more robust, secure, and production-ready provisioning solution, consider using the `network_provisioning`_ component. GATT Related Instructions ---------------------------- @@ -745,3 +723,6 @@ BluFi Service UUID: 0xFFFF, 16 bit BluFi (the mobile > {IDF_TARGET_NAME}): 0xFF01, writable Blufi ({IDF_TARGET_NAME} > the mobile phone): 0xFF02, readable and callable + + +.. _network_provisioning: https://github.com/espressif/idf-extra-components/tree/master/network_provisioning diff --git a/docs/zh_CN/api-guides/ble/blufi.rst b/docs/zh_CN/api-guides/ble/blufi.rst index 844ed27c43..4629c8634d 100644 --- a/docs/zh_CN/api-guides/ble/blufi.rst +++ b/docs/zh_CN/api-guides/ble/blufi.rst @@ -14,13 +14,9 @@ BluFi 流程的关键部分包括数据的分片、加密以及校验和验证 .. note:: - **BluFi 目前处于维护模式,不再规划新功能。** + **BluFi 目前处于维护模式,暂不计划增加新功能。** - 对于新项目或新增 Wi-Fi 配网的场景,建议使用 network_provisioning 组件 - - (`network_provisioning `_) - - 来实现现代化、安全且有持续维护的解决方案。 + 对于新项目或需要添加 Wi-Fi 配网功能的场景,建议使用 `network_provisioning`_ 组件。该组件更加现代、安全,并且仍在积极维护中。 快速入门 @@ -675,64 +671,46 @@ ACK 帧格式 (8 bit): 应用层需向 BluFi 注册以下几个与安全相关的函数: -.. code-block:: c + .. code-block:: c - typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free) + typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free) -该函数用来接收协商期间的正常数据 (normal data)。数据处理完成后,需要将待发送的数据使用 output_data 和 output_len 传出。 + 该函数用来接收协商期间的正常数据 (normal data)。数据处理完成后,需要将待发送的数据使用 output_data 和 output_len 传出。 -BluFi 会在调用完 Negotiate_data_handler 后,发送 Negotiate_data_handler 传出的 output_data。 + BluFi 会在调用完 Negotiate_data_handler 后,发送 Negotiate_data_handler 传出的 output_data。 -这里的两个 “*” 是因为需要发出去的数据长度未知,所以需要函数自行分配 (malloc) 或者指向全局变量,并告知是否需要通过 NEED_FREE 释放内存。 - -.. code-block:: c - - typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) - -加密和解密的数据长度必须一致。其中 IV8 为帧的 8 位序列,可作为 IV 的某 8 个位来使用。 - -.. code-block:: c - - typedef int (* esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) - -加密和解密的数据长度必须一致。其中 IV8 为帧的 8 位序列,可作为 IV 的某 8 个位来使用。 - -.. code-block:: c - - typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len) - -该函数用来进行校验,返回值为校验的值。BluFi 会使用该函数返回值与帧的校验值进行比较。 - -5. BLE SMP Encryption for Blufi - -在 Wi-Fi 配网之前,可以使用 BLE SMP 配对建立安全连接,使配网过程更安全。 - -此功能可通过配置选项启用或禁用: - -.. code-block:: c - - CONFIG_EXAMPLE_BLUFI_BLE_SMP_ENABLE - -如果启用该选项,ESP32 设备在连接成功后会发起配对请求。仅在配对成功后,设备才可继续进行 Wi-Fi 配网。 - -目前 BLE SMP 配对 **仅支持 Bluedroid 主机**。 - -6. 实现更强的安全性 - -示例中的默认加密/解密逻辑仅用于演示目的。 - -如果需要更高等级的安全性,可以考虑以下方法: - -1. **自定义安全回调** – 通过自定义 BluFi 框架中的安全回调函数,实现自己的加密、解密、认证以及校验算法: + 这里的两个 ``*`` 是因为需要发出去的数据长度未知,所以需要函数自行分配 (malloc) 或者指向全局变量,并告知是否需要通过 NEED_FREE 释放内存。 .. code-block:: c - esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks); + typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) -2. **Network Provisioning 组件(推荐使用)** – 或者可以使用 ESP-IDF 提供的 network_provisioning 组件,实现安全、可直接使用的配网解决方案: + 加密和解密的数据长度必须一致。其中 IV8 为帧的 8 位序列,可作为 IV 的某 8 个位来使用。 - `network_provisioning `_ + .. code-block:: c + typedef int (* esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len) + + 加密和解密的数据长度必须一致。其中 IV8 为帧的 8 位序列,可作为 IV 的某 8 个位来使用。 + + .. code-block:: c + + typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len) + + 该函数用来进行校验,返回值为校验的值。BluFi 会使用该函数返回值与帧的校验值进行比较。 + + +5. 实现更强的安全性 + + 示例中的默认加密、解密逻辑仅用于演示目的。如果你的应用需要更高的安全保障,可选择以下任一方法: + + - **自定义安全回调**:通过改写 BluFi 框架中的安全回调函数,自定义加密、解密、认证以及校验算法: + + .. code-block:: c + + esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks); + + - **网络配网组件(推荐使用)**:使用 ESP-IDF 提供的 `network_provisioning`_ 组件,实现安全、可直接使用的配网解决方案。 GATT 相关说明 @@ -746,3 +724,6 @@ BluFi Service UUID: 0xFFFF,16 bit BluFi(手机 > {IDF_TARGET_NAME})特性:0xFF01,主要权限:可写 BluFi({IDF_TARGET_NAME} > 手机)特性:0xFF02,主要权限:可读可通知 + + +.. _network_provisioning: https://github.com/espressif/idf-extra-components/tree/master/network_provisioning From b0b2130475b6c509c40505e72da7d7e7467ed895 Mon Sep 17 00:00:00 2001 From: Jin Chen Date: Thu, 11 Dec 2025 16:23:07 +0800 Subject: [PATCH 057/156] fix(ble): add soc caps config for pawr feat on ESP32C6 (cherry picked from commit 4e4b863299164bfb78fa2c4142e0a57a2894232f) Co-authored-by: cjin --- components/bt/controller/esp32c6/Kconfig.in | 2 +- components/bt/host/nimble/Kconfig.in | 2 +- components/soc/esp32c6/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c6/include/soc/soc_caps.h | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/components/bt/controller/esp32c6/Kconfig.in b/components/bt/controller/esp32c6/Kconfig.in index 93ba378454..229de5b0d9 100644 --- a/components/bt/controller/esp32c6/Kconfig.in +++ b/components/bt/controller/esp32c6/Kconfig.in @@ -239,7 +239,7 @@ config BT_LE_CTE_FEATURE_ENABLED config BT_LE_PERIODIC_ADV_WITH_RESPONSE_ENABLED bool "Enable BLE periodic advertising with response" - depends on BT_LE_50_FEATURE_SUPPORT + depends on BT_LE_50_FEATURE_SUPPORT && SOC_BLE_PERIODIC_ADV_WITH_RESPONSE default n help This enables BLE periodic advertising with response feature diff --git a/components/bt/host/nimble/Kconfig.in b/components/bt/host/nimble/Kconfig.in index d816de1840..eaa112fce0 100644 --- a/components/bt/host/nimble/Kconfig.in +++ b/components/bt/host/nimble/Kconfig.in @@ -593,7 +593,7 @@ menu "BLE 5.x Features" config BT_NIMBLE_PERIODIC_ADV_WITH_RESPONSES bool "Enable Periodic Advertisement with Response (EXPERIMENTAL)" - depends on BT_NIMBLE_ENABLE_PERIODIC_ADV + depends on BT_NIMBLE_ENABLE_PERIODIC_ADV && SOC_BLE_PERIODIC_ADV_WITH_RESPONSE default n help This enables controller PAwR (Periodic Advertisement with Response). diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index f365dc2ebd..6e0a205e53 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1643,6 +1643,10 @@ config SOC_BLE_MULTI_CONN_OPTIMIZATION bool default y +config SOC_BLE_PERIODIC_ADV_WITH_RESPONSE + bool + default y + config SOC_BLE_USE_WIFI_PWR_CLK_WORKAROUND bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index e0f696a26d..1a3b8cb9cd 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -634,6 +634,7 @@ #define SOC_BLE_PERIODIC_ADV_ENH_SUPPORTED (1) /*!< Support For BLE Periodic Adv Enhancements */ #define SOC_BLUFI_SUPPORTED (1) /*!< Support BLUFI */ #define SOC_BLE_MULTI_CONN_OPTIMIZATION (1) /*!< Support multiple connections optimization */ +#define SOC_BLE_PERIODIC_ADV_WITH_RESPONSE (1) /*!< Support Bluetooth LE Periodic Advertising with Response (PAwR) */ #define SOC_BLE_USE_WIFI_PWR_CLK_WORKAROUND (1) From a6aa9bf7f5e0999c20333b711efa31ed32087547 Mon Sep 17 00:00:00 2001 From: Jin Chen Date: Thu, 11 Dec 2025 16:23:08 +0800 Subject: [PATCH 058/156] fix(ble): add soc caps config for pawr feat on ESP32H2 (cherry picked from commit 2eb79c71f10766c94176fe206024777183750d53) Co-authored-by: cjin --- components/bt/controller/esp32h2/Kconfig.in | 2 +- components/soc/esp32h2/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32h2/include/soc/soc_caps.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/bt/controller/esp32h2/Kconfig.in b/components/bt/controller/esp32h2/Kconfig.in index 17a1d9abf2..b9eccdba05 100644 --- a/components/bt/controller/esp32h2/Kconfig.in +++ b/components/bt/controller/esp32h2/Kconfig.in @@ -242,7 +242,7 @@ config BT_LE_CTE_FEATURE_ENABLED config BT_LE_PERIODIC_ADV_WITH_RESPONSE_ENABLED bool "Enable BLE periodic advertising with response" - depends on BT_LE_50_FEATURE_SUPPORT + depends on BT_LE_50_FEATURE_SUPPORT && SOC_BLE_PERIODIC_ADV_WITH_RESPONSE default n help This enables BLE periodic advertising with response feature diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 5ebc633d98..b3f5913496 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -1599,6 +1599,10 @@ config SOC_BLE_CTE_SUPPORTED bool default y +config SOC_BLE_PERIODIC_ADV_WITH_RESPONSE + bool + default y + config SOC_DEBUG_HAVE_OCD_STUB_BINS bool default y diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index c3fb45c689..453c29dbc8 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -633,6 +633,7 @@ #define SOC_BLE_MULTI_CONN_OPTIMIZATION (1) /*!< Support multiple connections optimization */ #define SOC_BLE_PERIODIC_ADV_ENH_SUPPORTED (1) /*!< Support For BLE Periodic Adv Enhancements */ #define SOC_BLE_CTE_SUPPORTED (1) /*!< Support Bluetooth LE Constant Tone Extension (CTE) */ +#define SOC_BLE_PERIODIC_ADV_WITH_RESPONSE (1) /*!< Support Bluetooth LE Periodic Advertising with Response (PAwR) */ /*------------------------------------- DEBUG CAPS -------------------------------------*/ #define SOC_DEBUG_HAVE_OCD_STUB_BINS (1) From 0cce37f934ab7b954572ebe6ddebccd3c1503af8 Mon Sep 17 00:00:00 2001 From: Jin Chen Date: Thu, 11 Dec 2025 16:23:09 +0800 Subject: [PATCH 059/156] fix(ble): add soc caps config for pawr feat on ESP32C5 (cherry picked from commit 19130df4f39b45a88d51baf9b7a0381bb73db063) Co-authored-by: cjin --- components/bt/controller/esp32c5/Kconfig.in | 2 +- components/soc/esp32c5/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c5/include/soc/soc_caps.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/bt/controller/esp32c5/Kconfig.in b/components/bt/controller/esp32c5/Kconfig.in index c85bd425c8..6106906c1d 100644 --- a/components/bt/controller/esp32c5/Kconfig.in +++ b/components/bt/controller/esp32c5/Kconfig.in @@ -198,7 +198,7 @@ config BT_LE_POWER_CONTROL_ENABLED config BT_LE_PERIODIC_ADV_WITH_RESPONSE_ENABLED bool "Enable BLE periodic advertising with response" - depends on BT_LE_50_FEATURE_SUPPORT + depends on BT_LE_50_FEATURE_SUPPORT && SOC_BLE_PERIODIC_ADV_WITH_RESPONSE default n help This enables BLE periodic advertising with response feature diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 3c63b50a5c..c9a58a0afa 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1875,6 +1875,10 @@ config SOC_BLE_CTE_SUPPORTED bool default y +config SOC_BLE_PERIODIC_ADV_WITH_RESPONSE + bool + default y + config SOC_PHY_CALIBRATION_CLOCK_IS_INDEPENDENT bool default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index ad186c54e0..a862e13460 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -716,6 +716,7 @@ #define SOC_BLE_MULTI_CONN_OPTIMIZATION (1) /*!< Support multiple connections optimization */ #define SOC_BLE_PERIODIC_ADV_ENH_SUPPORTED (1) /*!< Support For BLE Periodic Adv Enhancements */ #define SOC_BLE_CTE_SUPPORTED (1) /*!< Support Bluetooth LE Constant Tone Extension (CTE) */ +#define SOC_BLE_PERIODIC_ADV_WITH_RESPONSE (1) /*!< Support Bluetooth LE Periodic Advertising with Response (PAwR) */ /*------------------------------------- PHY CAPS -------------------------------------*/ // #define SOC_PHY_COMBO_MODULE (1) /*!< Support Wi-Fi, BLE and 15.4*/ From 7569042a610ad6caab3f29516d63c956e73a6ce7 Mon Sep 17 00:00:00 2001 From: Jin Chen Date: Thu, 11 Dec 2025 16:23:10 +0800 Subject: [PATCH 060/156] fix(ble): add soc caps config for pawr feat on ESP32C61 (cherry picked from commit d667a418261d00a0f5c8a9a359324f72d64447ff) Co-authored-by: cjin --- components/soc/esp32c61/include/soc/Kconfig.soc_caps.in | 4 ++++ components/soc/esp32c61/include/soc/soc_caps.h | 1 + 2 files changed, 5 insertions(+) diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 7469604368..7e2a445294 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -1351,6 +1351,10 @@ config SOC_BLE_CTE_SUPPORTED bool default y +config SOC_BLE_PERIODIC_ADV_WITH_RESPONSE + bool + default y + config SOC_PHY_COMBO_MODULE bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 6ca25d6feb..7631b38871 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -534,6 +534,7 @@ #define SOC_BLUFI_SUPPORTED (1) /*!< Support BLUFI */ #define SOC_BLE_MULTI_CONN_OPTIMIZATION (1) /*!< Support multiple connections optimization */ #define SOC_BLE_CTE_SUPPORTED (1) /*!< Support Bluetooth LE Constant Tone Extension (CTE) */ +#define SOC_BLE_PERIODIC_ADV_WITH_RESPONSE (1) /*!< Support Bluetooth LE Periodic Advertising with Response (PAwR) */ /*------------------------------------- PHY CAPS -------------------------------------*/ #define SOC_PHY_COMBO_MODULE (1) /*!< Support Wi-Fi, BLE and 15.4*/ From b84629814ae9f9edf793d365f0e864a757ffd713 Mon Sep 17 00:00:00 2001 From: Jin Chen Date: Thu, 11 Dec 2025 16:23:16 +0800 Subject: [PATCH 061/156] fix(ble): remove target dependency on power control config on ESP32C6 (cherry picked from commit f29f500ac8a2ea0e8de2005f08e7c0e79c3c4adc) Co-authored-by: cjin --- components/bt/controller/esp32c6/Kconfig.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/esp32c6/Kconfig.in b/components/bt/controller/esp32c6/Kconfig.in index 229de5b0d9..3c47a0838c 100644 --- a/components/bt/controller/esp32c6/Kconfig.in +++ b/components/bt/controller/esp32c6/Kconfig.in @@ -222,7 +222,7 @@ config BT_LE_MAX_PERIODIC_ADVERTISER_LIST config BT_LE_POWER_CONTROL_ENABLED bool "Enable controller support for BLE Power Control" - depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED && IDF_TARGET_ESP32C6 + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED default n help Set this option to enable the Power Control feature on controller From df9e35edb3abcc9fa55b02715f0cbfadf9000543 Mon Sep 17 00:00:00 2001 From: Jin Chen Date: Thu, 11 Dec 2025 16:23:17 +0800 Subject: [PATCH 062/156] fix(ble): remove target dependency on power control config on ESP32C5 (cherry picked from commit 82da79224e571b1630f0e360af06e536c5ea68f3) Co-authored-by: cjin --- components/bt/controller/esp32c5/Kconfig.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/controller/esp32c5/Kconfig.in b/components/bt/controller/esp32c5/Kconfig.in index 6106906c1d..8912a6e86c 100644 --- a/components/bt/controller/esp32c5/Kconfig.in +++ b/components/bt/controller/esp32c5/Kconfig.in @@ -191,7 +191,7 @@ config BT_LE_MAX_PERIODIC_ADVERTISER_LIST config BT_LE_POWER_CONTROL_ENABLED bool "Enable controller support for BLE Power Control" - depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED && IDF_TARGET_ESP32C6 + depends on BT_LE_50_FEATURE_SUPPORT && !BT_NIMBLE_ENABLED default n help Set this option to enable the Power Control feature on controller From 5dbc296b1eb4cedd6302316f4f039c11e2976727 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Tue, 9 Dec 2025 18:03:33 +0100 Subject: [PATCH 063/156] fix(espcoredump): support ESP32P4 ECO5 unified memory layout --- components/espcoredump/src/core_dump_common.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/espcoredump/src/core_dump_common.c b/components/espcoredump/src/core_dump_common.c index 7442d85688..c49980b98b 100644 --- a/components/espcoredump/src/core_dump_common.c +++ b/components/espcoredump/src/core_dump_common.c @@ -26,12 +26,7 @@ const static char TAG[] __attribute__((unused)) = "esp_core_dump_common"; * @brief Memory regions to dump, defined at compile time. */ #if CONFIG_ESP_COREDUMP_CAPTURE_DRAM -#if !CONFIG_IDF_TARGET_ESP32P4 -extern int _bss_start; -extern int _bss_end; -extern int _data_start; -extern int _data_end; -#else +#if CONFIG_ESP32P4_SELECTS_REV_LESS_V3 extern int _bss_start_low; extern int _bss_end_low; extern int _data_start_low; @@ -40,6 +35,11 @@ extern int _bss_start_high; extern int _bss_end_high; extern int _data_start_high; extern int _data_end_high; +#else +extern int _bss_start; +extern int _bss_end; +extern int _data_start; +extern int _data_end; #endif #endif @@ -280,14 +280,14 @@ static const struct { } s_memory_sections[COREDUMP_MEMORY_MAX] = { [COREDUMP_MEMORY_IRAM] = { &_coredump_iram_start, &_coredump_iram_end }, #if CONFIG_ESP_COREDUMP_CAPTURE_DRAM -#if !CONFIG_IDF_TARGET_ESP32P4 - [COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start, &_bss_end }, - [COREDUMP_MEMORY_DRAM_DATA] = { &_data_start, &_data_end }, -#else +#if CONFIG_ESP32P4_SELECTS_REV_LESS_V3 [COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start_low, &_bss_end_low }, [COREDUMP_MEMORY_DRAM_DATA] = { &_data_start_low, &_data_end_low }, [COREDUMP_MEMORY_DRAM_BSS_HIGH] = { &_bss_start_high, &_bss_end_high }, [COREDUMP_MEMORY_DRAM_DATA_HIGH] = { &_data_start_high, &_data_end_high }, +#else + [COREDUMP_MEMORY_DRAM_BSS] = { &_bss_start, &_bss_end }, + [COREDUMP_MEMORY_DRAM_DATA] = { &_data_start, &_data_end }, #endif #else [COREDUMP_MEMORY_DRAM] = { &_coredump_dram_start, &_coredump_dram_end }, From ac196562d906b616fed4958530a330c4d00b2f4d Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Fri, 12 Dec 2025 19:14:30 +0800 Subject: [PATCH 064/156] test(tsens): Re-enable temperature sensor test on esp32p4 v3 --- components/driver/test_apps/.build-test-rules.yml | 4 ---- .../pytest_legacy_temp_sensor_driver.py | 1 - components/efuse/esp32p4/esp_efuse_rtc_calib.c | 1 - .../esp_driver_tsens/test_apps/.build-test-rules.yml | 4 ---- .../temperature_sensor/pytest_temperature_sensor.py | 2 -- examples/peripherals/.build-test-rules.yml | 8 -------- .../temp_sensor/pytest_temp_sensor_example.py | 1 - .../pytest_temp_sensor_monitor_example.py | 1 - 8 files changed, 22 deletions(-) diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index c721e4a2b3..0a4a9f9ef5 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -60,10 +60,6 @@ components/driver/test_apps/legacy_rmt_driver: components/driver/test_apps/legacy_rtc_temp_driver: disable: - if: SOC_TEMP_SENSOR_SUPPORTED != 1 - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: p4 rev3 migration # TODO: IDF-14834 components/driver/test_apps/legacy_sigma_delta_driver: disable: diff --git a/components/driver/test_apps/legacy_rtc_temp_driver/pytest_legacy_temp_sensor_driver.py b/components/driver/test_apps/legacy_rtc_temp_driver/pytest_legacy_temp_sensor_driver.py index 3d27a10b43..47646ffe48 100644 --- a/components/driver/test_apps/legacy_rtc_temp_driver/pytest_legacy_temp_sensor_driver.py +++ b/components/driver/test_apps/legacy_rtc_temp_driver/pytest_legacy_temp_sensor_driver.py @@ -18,6 +18,5 @@ from pytest_embedded_idf.utils import idf_parametrize ['esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c5', 'esp32c61'], indirect=['target'], ) -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='p4 rev3 migration, IDF-14834') def test_legacy_temp_sensor_driver(dut: Dut) -> None: dut.run_all_single_board_cases(timeout=120) diff --git a/components/efuse/esp32p4/esp_efuse_rtc_calib.c b/components/efuse/esp32p4/esp_efuse_rtc_calib.c index 2867168c8a..080278cb1b 100644 --- a/components/efuse/esp32p4/esp_efuse_rtc_calib.c +++ b/components/efuse/esp32p4/esp_efuse_rtc_calib.c @@ -199,7 +199,6 @@ esp_err_t esp_efuse_rtc_calib_get_tsens_val(float* tsens_cal) const esp_efuse_desc_t** cal_temp_efuse; cal_temp_efuse = ESP_EFUSE_TEMPERATURE_SENSOR; int cal_temp_size = esp_efuse_get_field_size(cal_temp_efuse); - assert(cal_temp_size == 9); uint32_t cal_temp = 0; esp_err_t err = esp_efuse_read_field_blob(cal_temp_efuse, &cal_temp, cal_temp_size); diff --git a/components/esp_driver_tsens/test_apps/.build-test-rules.yml b/components/esp_driver_tsens/test_apps/.build-test-rules.yml index ee00111112..0117f07d13 100644 --- a/components/esp_driver_tsens/test_apps/.build-test-rules.yml +++ b/components/esp_driver_tsens/test_apps/.build-test-rules.yml @@ -6,10 +6,6 @@ components/esp_driver_tsens/test_apps/temperature_sensor: - if: IDF_TARGET == "esp32c5" and CONFIG_NAME == "iram_safe" temporary: false reason: Use test_temperature_sensor_cbs_esp32c5 instead, iram_safe need to use single app large partition table on c5 - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: p4 rev3 migration # TODO: IDF-14834 depends_components: - esp_driver_tsens - esp_phy diff --git a/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py b/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py index ee39b9a29a..987e0db89f 100644 --- a/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py +++ b/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py @@ -19,7 +19,6 @@ from pytest_embedded_idf.utils import idf_parametrize ['esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c5', 'esp32c61'], indirect=['target'], ) -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='p4 rev3 migration, IDF-14834') def test_temperature_sensor_driver(dut: Dut) -> None: dut.run_all_single_board_cases() @@ -33,7 +32,6 @@ def test_temperature_sensor_driver(dut: Dut) -> None: indirect=True, ) @idf_parametrize('target', ['esp32c6', 'esp32h2', 'esp32p4', 'esp32c61'], indirect=['target']) -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='p4 rev3 migration, IDF-14834') def test_temperature_sensor_cbs(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 20dfad0ee9..f44e6ad3fc 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -442,20 +442,12 @@ examples/peripherals/spi_slave_hd/segment_mode/seg_slave: examples/peripherals/temperature_sensor/temp_sensor: disable: - if: SOC_TEMP_SENSOR_SUPPORTED != 1 - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: p4 rev3 migration # TODO: IDF-14834 depends_components: - esp_driver_tsens examples/peripherals/temperature_sensor/temp_sensor_monitor: disable: - if: SOC_TEMPERATURE_SENSOR_INTR_SUPPORT != 1 - disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: p4 rev3 migration # TODO: IDF-14834 depends_components: - esp_driver_tsens diff --git a/examples/peripherals/temperature_sensor/temp_sensor/pytest_temp_sensor_example.py b/examples/peripherals/temperature_sensor/temp_sensor/pytest_temp_sensor_example.py index 97dcf3aba1..df1727e3f4 100644 --- a/examples/peripherals/temperature_sensor/temp_sensor/pytest_temp_sensor_example.py +++ b/examples/peripherals/temperature_sensor/temp_sensor/pytest_temp_sensor_example.py @@ -11,7 +11,6 @@ from pytest_embedded_idf.utils import idf_parametrize ['esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c5', 'esp32c61'], indirect=['target'], ) -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='p4 rev3 migration, IDF-14834') def test_temp_sensor_example(dut: Dut) -> None: dut.expect_exact('Install temperature sensor') dut.expect_exact('Enable temperature sensor') diff --git a/examples/peripherals/temperature_sensor/temp_sensor_monitor/pytest_temp_sensor_monitor_example.py b/examples/peripherals/temperature_sensor/temp_sensor_monitor/pytest_temp_sensor_monitor_example.py index a1fc48b1a0..f5cccf04ac 100644 --- a/examples/peripherals/temperature_sensor/temp_sensor_monitor/pytest_temp_sensor_monitor_example.py +++ b/examples/peripherals/temperature_sensor/temp_sensor_monitor/pytest_temp_sensor_monitor_example.py @@ -7,7 +7,6 @@ from pytest_embedded_idf.utils import idf_parametrize @pytest.mark.generic @idf_parametrize('target', ['esp32c6', 'esp32h2', 'esp32p4', 'esp32c5', 'esp32c61'], indirect=['target']) -@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='p4 rev3 migration, IDF-14834') def test_temp_sensor_monitor_example(dut: Dut) -> None: dut.expect_exact('Install temperature sensor') dut.expect_exact('Enable temperature sensor') From d569b7df6bb3b62042f57ef527842ab2b0d7c776 Mon Sep 17 00:00:00 2001 From: linruihao Date: Tue, 9 Dec 2025 15:04:25 +0800 Subject: [PATCH 065/156] change(bt/bluedroid): Change AVRCP version according to feature enabled - Version will be set to 1.6 if Cover Art feature enabled - Otherwise, version will be set to 1.5 --- components/bt/host/bluedroid/Kconfig.in | 4 +++- .../bt/host/bluedroid/stack/avrc/avrc_sdp.c | 20 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/components/bt/host/bluedroid/Kconfig.in b/components/bt/host/bluedroid/Kconfig.in index 1d4b24b195..41807eedeb 100644 --- a/components/bt/host/bluedroid/Kconfig.in +++ b/components/bt/host/bluedroid/Kconfig.in @@ -114,7 +114,9 @@ menu "AVRCP Features" default y select BT_GOEPC_ENABLED help - This enable Cover Art feature of AVRCP CT role + This enable Cover Art feature for AVRCP CT role, Cover Art requires AVRCP + version 1.6 or higher. Therefore, if the Cover Art feature is enabled, + AVRCP version will set to 1.6, otherwise, it will remain at 1.5 endmenu diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_sdp.c b/components/bt/host/bluedroid/stack/avrc/avrc_sdp.c index 0b624b3f0c..3d84d1f985 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_sdp.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_sdp.c @@ -29,8 +29,14 @@ #if (defined(AVRC_INCLUDED) && AVRC_INCLUDED == TRUE) -#ifndef SDP_AVRCP_1_6 +#if AVRC_CA_INCLUDED == TRUE +/* If Cover Art feature is enabled, set AVRCP version to 1.6 */ #define SDP_AVRCP_1_6 TRUE +#define SDP_AVRCP_1_5 FALSE +#else +/* Otherwise, set to 1.5 */ +#define SDP_AVRCP_1_6 FALSE +#define SDP_AVRCP_1_5 TRUE #endif #ifndef SDP_AVCTP_1_4 @@ -52,7 +58,7 @@ const tSDP_PROTOCOL_ELEM avrc_proto_list [] = { #if SDP_AVCTP_1_4 == TRUE {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_4, 0} } #else -#if SDP_AVRCP_1_6 == TRUE +#if (SDP_AVRCP_1_5 == TRUE || SDP_AVRCP_1_6 == TRUE) {UUID_PROTOCOL_AVCTP, 1, {AVCT_REV_1_3, 0} } #else #if AVRC_METADATA_INCLUDED == TRUE @@ -64,7 +70,7 @@ const tSDP_PROTOCOL_ELEM avrc_proto_list [] = { #endif }; -#if SDP_AVRCP_1_6 == TRUE +#if (SDP_AVRCP_1_5 == TRUE || SDP_AVRCP_1_6 == TRUE) const tSDP_PROTO_LIST_ELEM avrc_add_proto_list [] = { { AVRC_NUM_PROTO_ELEMS, @@ -251,7 +257,7 @@ UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provide /* add service class id list */ class_list[0] = service_uuid; -#if (SDP_AVCTP_1_4 == TRUE || SDP_AVRCP_1_6 == TRUE) +#if (SDP_AVCTP_1_4 == TRUE || SDP_AVRCP_1_5 == TRUE || SDP_AVRCP_1_6 == TRUE) if ( service_uuid == UUID_SERVCLASS_AV_REMOTE_CONTROL ) { class_list[1] = UUID_SERVCLASS_AV_REM_CTRL_CONTROL; count = 2; @@ -263,7 +269,7 @@ UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provide result &= SDP_AddProtocolList(sdp_handle, AVRC_NUM_PROTO_ELEMS, (tSDP_PROTOCOL_ELEM *)avrc_proto_list); /* add profile descriptor list */ -#if SDP_AVRCP_1_6 == TRUE +#if (SDP_AVRCP_1_5 == TRUE || SDP_AVRCP_1_6 == TRUE) if (browsing_en) { add_additional_protocol_list = TRUE; } else if (service_uuid == UUID_SERVCLASS_AV_REM_CTRL_TARGET && @@ -277,7 +283,11 @@ UINT16 AVRC_AddRecord(UINT16 service_uuid, char *p_service_name, char *p_provide result &= SDP_AddAdditionProtoLists( sdp_handle, 1, (tSDP_PROTO_LIST_ELEM *)avrc_add_proto_list); } +#if SDP_AVRCP_1_5 == TRUE + result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_5); +#elif SDP_AVRCP_1_6 == TRUE result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_6); +#endif #else #if AVRC_METADATA_INCLUDED == TRUE result &= SDP_AddProfileDescriptorList(sdp_handle, UUID_SERVCLASS_AV_REMOTE_CONTROL, AVRC_REV_1_3); From 99b9913406b3c5c736bbca1f3b4a83d14024ec3a Mon Sep 17 00:00:00 2001 From: Tan Yan Quan Date: Thu, 20 Nov 2025 17:42:15 +0800 Subject: [PATCH 066/156] feat(openthread): support RCP console debug via spinel --- components/openthread/CMakeLists.txt | 5 + components/openthread/Kconfig | 6 + .../include/esp_openthread_spinel.h | 8 + .../private_include/esp_openthread_ncp.h | 4 + .../esp_spinel_ncp_vendor_macro.h | 2 + .../openthread-core-esp32x-radio-config.h | 4 +- .../openthread/src/ncp/esp_openthread_ncp.cpp | 105 ++++++++++- .../src/ncp/esp_openthread_ncp_console.cpp | 170 ++++++++++++++++++ .../src/port/esp_openthread_radio_spinel.cpp | 7 + .../openthread/ot_rcp/main/CMakeLists.txt | 1 - examples/openthread/ot_rcp/main/esp_ot_rcp.c | 10 ++ examples/openthread/ot_rcp/sdkconfig.defaults | 6 + 12 files changed, 321 insertions(+), 7 deletions(-) create mode 100644 components/openthread/src/ncp/esp_openthread_ncp_console.cpp diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index 54e8f99d8a..dd9a60000a 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -196,6 +196,11 @@ if(CONFIG_OPENTHREAD_ENABLED) "src/port/esp_openthread_messagepool.c") endif() + if(NOT CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE) + list(APPEND exclude_srcs + "src/ncp/esp_openthread_ncp_console.cpp") + endif() + if(CONFIG_OPENTHREAD_FTD) set(device_type "OPENTHREAD_FTD=1") elseif(CONFIG_OPENTHREAD_MTD) diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index b113cfd1f4..cded85a78b 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -239,6 +239,12 @@ menu "OpenThread" default y help Select this to enable OpenThread NCP vendor commands. + + config OPENTHREAD_RCP_SPINEL_CONSOLE + bool "Enable RCP console via Spinel" + default n + help + Select this to enable sending console commands to OpenThread RCP via Spinel. endmenu config OPENTHREAD_BORDER_ROUTER diff --git a/components/openthread/include/esp_openthread_spinel.h b/components/openthread/include/esp_openthread_spinel.h index 2900095420..09f7dfe99e 100644 --- a/components/openthread/include/esp_openthread_spinel.h +++ b/components/openthread/include/esp_openthread_spinel.h @@ -76,6 +76,14 @@ esp_err_t esp_openthread_rcp_init(void); */ esp_err_t esp_openthread_rcp_version_set(const char *version_str); +/** + * @brief Sends a console command to RCP. + * + * @param[in] input The pointer to a command string to be run on RCP. + * + */ +void esp_openthread_rcp_send_command(const char *input); + #ifdef __cplusplus } #endif diff --git a/components/openthread/private_include/esp_openthread_ncp.h b/components/openthread/private_include/esp_openthread_ncp.h index 45b585cf33..2d529dd770 100644 --- a/components/openthread/private_include/esp_openthread_ncp.h +++ b/components/openthread/private_include/esp_openthread_ncp.h @@ -12,6 +12,10 @@ extern "C" { void otAppNcpInit(otInstance *aInstance); +#if CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE +esp_err_t esp_console_redirect_to_otlog(void); +#endif // CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE + #ifdef __cplusplus } #endif diff --git a/components/openthread/private_include/esp_spinel_ncp_vendor_macro.h b/components/openthread/private_include/esp_spinel_ncp_vendor_macro.h index 3bd9f4fb85..6d572f45b3 100644 --- a/components/openthread/private_include/esp_spinel_ncp_vendor_macro.h +++ b/components/openthread/private_include/esp_spinel_ncp_vendor_macro.h @@ -11,3 +11,5 @@ #define SPINEL_PROP_VENDOR_ESP_SET_PENDINGMODE (SPINEL_PROP_VENDOR_ESP__BEGIN + 2) /* Vendor command for pending mode.*/ #define SPINEL_PROP_VENDOR_ESP_COEX_EVENT (SPINEL_PROP_VENDOR_ESP__BEGIN + 3) + +#define SPINEL_PROP_VENDOR_ESP_SET_CONSOLE_CMD (SPINEL_PROP_VENDOR_ESP__BEGIN + 4) diff --git a/components/openthread/private_include/openthread-core-esp32x-radio-config.h b/components/openthread/private_include/openthread-core-esp32x-radio-config.h index 8be7e0de72..3df6677e2e 100644 --- a/components/openthread/private_include/openthread-core-esp32x-radio-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-radio-config.h @@ -192,10 +192,10 @@ /** * @def OPENTHREAD_CONFIG_LOG_OUTPUT * - * The ESP-IDF platform provides an otPlatLog() function. + * Use app log for RCP to transmit logs to host via Spinel. */ #ifndef OPENTHREAD_CONFIG_LOG_OUTPUT -#define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED +#define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_APP #endif /** diff --git a/components/openthread/src/ncp/esp_openthread_ncp.cpp b/components/openthread/src/ncp/esp_openthread_ncp.cpp index b6e70eca1f..eb0bad9c50 100644 --- a/components/openthread/src/ncp/esp_openthread_ncp.cpp +++ b/components/openthread/src/ncp/esp_openthread_ncp.cpp @@ -5,6 +5,7 @@ */ #include "sdkconfig.h" +#include "esp_check.h" #include "esp_ieee802154.h" #include "esp_openthread_ncp.h" #include "esp_spinel_ncp_vendor_macro.h" @@ -18,6 +19,24 @@ #include "utils/uart.h" #endif +#if CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE +#include "esp_console.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "esp_openthread_common_macro.h" + +static constexpr size_t s_console_command_max_length = 256; +static constexpr size_t s_console_command_queue_length = 8; +static QueueHandle_t s_console_command_queue = nullptr; + +#define NO_LOG_TAG "" // don't use a tag to reduce log lengths from RCP + +struct ConsoleCmdMsg +{ + char cmd[s_console_command_max_length]; +}; +#endif // CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE + #if (CONFIG_OPENTHREAD_RCP_UART || CONFIG_OPENTHREAD_RCP_USB_SERIAL_JTAG) extern "C" { static int NcpSend(const uint8_t *aBuf, uint16_t aBufLength) @@ -28,15 +47,69 @@ extern "C" { } #endif +#if CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE +static void console_command_worker_task(void *arg) +{ + ConsoleCmdMsg msg; + + for (;;) { + if (xQueueReceive(s_console_command_queue, &msg, portMAX_DELAY) != pdTRUE) { + continue; + } + + int ret = 0; + esp_err_t err = esp_console_run(msg.cmd, &ret); + + if (err == ESP_ERR_NOT_FOUND){ + ESP_LOGI(NO_LOG_TAG, "Unrecognized command: %s", msg.cmd); + } else if (err == ESP_ERR_INVALID_ARG) { + ESP_LOGI(NO_LOG_TAG, "Command is empty"); + } else if (err == ESP_OK && ret != ESP_OK) { + ESP_LOGI(NO_LOG_TAG, "Command returned non-zero error code: 0x%x (%s)", ret, esp_err_to_name(ret)); + } else if (err != ESP_OK) { + ESP_LOGI(NO_LOG_TAG, "Internal error running '%s': %s", msg.cmd, esp_err_to_name(err)); + } + } +} + +static esp_err_t init_console_command_worker() +{ + if (s_console_command_queue) { + return ESP_OK; + } + + s_console_command_queue = xQueueCreate(s_console_command_queue_length, sizeof(ConsoleCmdMsg)); + ESP_RETURN_ON_FALSE(s_console_command_queue, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to create s_console_command_queue"); + + BaseType_t ret = xTaskCreatePinnedToCore(console_command_worker_task, "ot_console", 3072, nullptr, 3, nullptr, tskNO_AFFINITY); + + if (ret != pdPASS) { + vQueueDelete(s_console_command_queue); + s_console_command_queue = nullptr; + return ESP_FAIL; + } + + return ESP_OK; +} +#endif // CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE + extern "C" void otAppNcpInit(otInstance *aInstance) { -#if CONFIG_OPENTHREAD_RCP_SPI - otNcpSpiInit(aInstance); -#else +#if (CONFIG_OPENTHREAD_RCP_UART || CONFIG_OPENTHREAD_RCP_USB_SERIAL_JTAG) IgnoreError(otPlatUartEnable()); - otNcpHdlcInit(aInstance, NcpSend); +#else + otNcpSpiInit(aInstance); #endif + +#if CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE + esp_err_t err = esp_console_redirect_to_otlog(); + if (err != ESP_OK) { + ESP_LOGE(NO_LOG_TAG, "Failed to redirect console to otPlatLog: %s", esp_err_to_name(err)); + } + + init_console_command_worker(); +#endif // CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE } namespace ot { @@ -127,6 +200,30 @@ otError NcpBase::VendorSetPropertyHandler(spinel_prop_key_t aPropKey) #endif break; } +#if CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE + case SPINEL_PROP_VENDOR_ESP_SET_CONSOLE_CMD: { + const uint8_t *data = nullptr; + uint16_t len = 0; + mDecoder.ReadDataWithLen(data, len); + + if (len >= s_console_command_max_length) { + ESP_LOGW(NO_LOG_TAG, "Console command too long (%u bytes, max %zu), dropping", len, s_console_command_max_length - 1); + break; + } + + ConsoleCmdMsg msg{}; + memcpy(msg.cmd, data, len); + msg.cmd[len] = '\0'; + + // Use a separate task to run the command so that RCP does not time out + if (s_console_command_queue == nullptr) { + ESP_LOGW(NO_LOG_TAG, "Console worker not initialized, dropping cmd: %s", msg.cmd); + } else if (xQueueSend(s_console_command_queue, &msg, 0) != pdTRUE) { + ESP_LOGW(NO_LOG_TAG, "Console cmd queue full, dropping cmd: %s", msg.cmd); + } + break; + } +#endif // CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE default: error = OT_ERROR_NOT_FOUND; diff --git a/components/openthread/src/ncp/esp_openthread_ncp_console.cpp b/components/openthread/src/ncp/esp_openthread_ncp_console.cpp new file mode 100644 index 0000000000..e70c247f55 --- /dev/null +++ b/components/openthread/src/ncp/esp_openthread_ncp_console.cpp @@ -0,0 +1,170 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_check.h" +#include "esp_err.h" +#include "esp_vfs.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/stream_buffer.h" +#include "openthread/platform/logging.h" +#include "esp_openthread_common_macro.h" +#include "esp_openthread_ncp.h" + +#define OTLOG_LINE_MAX 256 +#define ROM_TAP_SB_SIZE 1024 +#define ROM_TAP_TRIGLVL 1 + +typedef struct { + char line[OTLOG_LINE_MAX]; + size_t len; +} line_buf_t; + +static SemaphoreHandle_t s_mutex; +static line_buf_t s_stdout_buf; +static line_buf_t s_stderr_buf; +static StreamBufferHandle_t s_rom_tap_sb; +static line_buf_t s_rom_line; + +static inline line_buf_t *get_buf_for_fd(int fd) +{ + if (fd == STDERR_FILENO) return &s_stderr_buf; + // default: treat as stdout + return &s_stdout_buf; +} + +// Flush one assembled line to otPlatLog (strip trailing CR/LF) +static void flush_line_to_otlog(line_buf_t *b, otLogLevel level, bool allow_empty) +{ + while (b->len > 0 && (b->line[b->len - 1] == '\n' || b->line[b->len - 1] == '\r')) { + b->len--; + } + b->line[b->len] = '\0'; + + if (b->len == 0 && allow_empty) { + otPlatLog(level, OT_LOG_REGION_NCP, "%s", " "); + return; + } + + otPlatLog(level, OT_LOG_REGION_NCP, "%s", b->line); + b->len = 0; +} + +// Accumulate bytes; emit at newline or buffer full. +static void buffer_and_maybe_flush(int fd, const char *data, size_t size) +{ + line_buf_t *b = get_buf_for_fd(fd); + otLogLevel lvl = (fd == STDERR_FILENO) ? OT_LOG_LEVEL_WARN : OT_LOG_LEVEL_NOTE; + + for (size_t i = 0; i < size; i++) { + char c = data[i]; + if (b->len < OTLOG_LINE_MAX - 1) { + b->line[b->len++] = c; + } + + if (c == '\n') { + flush_line_to_otlog(b, lvl, /*allow_empty=*/true); + } else if (b->len == OTLOG_LINE_MAX - 1) { + flush_line_to_otlog(b, lvl, /*allow_empty=*/false); + } + } +} + +static ssize_t otlog_write(int fd, const void *data, size_t size) +{ + if (!data || size == 0) return 0; + + if (s_mutex) xSemaphoreTake(s_mutex, portMAX_DELAY); + buffer_and_maybe_flush(fd, (const char *)data, size); + if (s_mutex) xSemaphoreGive(s_mutex); + + return (ssize_t)size; +} + +static ssize_t otlog_read(int fd, void *dst, size_t size) +{ + (void)fd; (void)dst; (void)size; + return 0; +} + +static int otlog_open(const char *path, int flags, int mode) +{ + (void)path; (void)flags; (void)mode; + return 0; +} + +static int otlog_close(int fd) +{ + (void)fd; + return 0; +} + +static IRAM_ATTR void rom_putc_tap(char c) +{ + BaseType_t woken = pdFALSE; + + if (!xPortCanYield()) { + xStreamBufferSendFromISR(s_rom_tap_sb, &c, 1, &woken); + if (woken) portYIELD_FROM_ISR(); + } else { + xStreamBufferSend(s_rom_tap_sb, &c, 1, 0); + } +} + +static esp_err_t esp_rom_printf_mirror_install(void) +{ + s_rom_tap_sb = xStreamBufferCreate(ROM_TAP_SB_SIZE, ROM_TAP_TRIGLVL); + ESP_RETURN_ON_FALSE(s_rom_tap_sb, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to create s_rom_tap_sb buffer"); + + esp_rom_install_channel_putc(1, rom_putc_tap); + return ESP_OK; +} + +static void rom_tap_consumer_task(void *arg) +{ + const otLogLevel lvl = OT_LOG_LEVEL_NOTE; + uint8_t ch; + + for (;;) { + if (xStreamBufferReceive(s_rom_tap_sb, &ch, 1, portMAX_DELAY) != 1) continue; + + if (s_rom_line.len < OTLOG_LINE_MAX - 1) { + s_rom_line.line[s_rom_line.len++] = (char)ch; + } + if (ch == '\n' || s_rom_line.len == OTLOG_LINE_MAX - 1) { + flush_line_to_otlog(&s_rom_line, lvl, /*allow_empty=*/true); + s_rom_line.len = 0; + } + } +} + +esp_err_t esp_console_redirect_to_otlog(void) +{ + if (!s_mutex) { + s_mutex = xSemaphoreCreateMutex(); + ESP_RETURN_ON_FALSE(s_mutex, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to create s_mutex"); + } + + esp_vfs_t vfs = {}; + vfs.flags = ESP_VFS_FLAG_DEFAULT; + vfs.write = &otlog_write; + vfs.read = &otlog_read; + vfs.open = &otlog_open; + vfs.close = &otlog_close; + + ESP_RETURN_ON_ERROR(esp_vfs_register("/dev/otlog", &vfs, NULL), OT_PLAT_LOG_TAG, "vfs register failed"); + + FILE *fout = freopen("/dev/otlog", "w", stdout); + FILE *ferr = freopen("/dev/otlog", "w", stderr); + ESP_RETURN_ON_FALSE(fout && ferr, ESP_FAIL, OT_PLAT_LOG_TAG, "freopen failed (stdout=%p, stderr=%p)", fout, ferr); + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + ESP_RETURN_ON_ERROR(esp_rom_printf_mirror_install(), OT_PLAT_LOG_TAG, "esp_rom_printf mirror install failed"); + xTaskCreatePinnedToCore(rom_tap_consumer_task, "ot_rom_tap", 2048, NULL, 4, NULL, tskNO_AFFINITY); + + return ESP_OK; +} diff --git a/components/openthread/src/port/esp_openthread_radio_spinel.cpp b/components/openthread/src/port/esp_openthread_radio_spinel.cpp index 846544b98a..c5ff44923d 100644 --- a/components/openthread/src/port/esp_openthread_radio_spinel.cpp +++ b/components/openthread/src/port/esp_openthread_radio_spinel.cpp @@ -11,10 +11,12 @@ #include "esp_err.h" #include "esp_openthread_border_router.h" #include "esp_openthread_common_macro.h" +#include "esp_openthread_ncp.h" #include "esp_openthread_platform.h" #include "esp_openthread_types.h" #include "esp_system.h" #include "esp_spinel_interface.hpp" +#include "esp_spinel_ncp_vendor_macro.h" #include "esp_spi_spinel_interface.hpp" #include "esp_uart_spinel_interface.hpp" #include "openthread-core-config.h" @@ -210,6 +212,11 @@ void esp_openthread_handle_netif_state_change(bool state) s_radio.SetTimeSyncState(state); } +void esp_openthread_rcp_send_command(const char *input) +{ + s_radio.Set(SPINEL_PROP_VENDOR_ESP_SET_CONSOLE_CMD, SPINEL_DATATYPE_DATA_WLEN_S, input, strlen(input)); +} + void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64) { SuccessOrDie(s_radio.GetIeeeEui64(ieee_eui64)); diff --git a/examples/openthread/ot_rcp/main/CMakeLists.txt b/examples/openthread/ot_rcp/main/CMakeLists.txt index e881658a31..83b084e909 100644 --- a/examples/openthread/ot_rcp/main/CMakeLists.txt +++ b/examples/openthread/ot_rcp/main/CMakeLists.txt @@ -1,3 +1,2 @@ idf_component_register(SRCS "esp_ot_rcp.c" - PRIV_REQUIRES esp_coex esp_event nvs_flash openthread INCLUDE_DIRS ".") diff --git a/examples/openthread/ot_rcp/main/esp_ot_rcp.c b/examples/openthread/ot_rcp/main/esp_ot_rcp.c index fddd776684..b3c4e6c26f 100644 --- a/examples/openthread/ot_rcp/main/esp_ot_rcp.c +++ b/examples/openthread/ot_rcp/main/esp_ot_rcp.c @@ -29,6 +29,10 @@ #error "RCP is only supported for the SoCs which have IEEE 802.15.4 module" #endif +#if CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE +#include "esp_console.h" +#endif + #define TAG "ot_esp_rcp" extern void otAppNcpInit(otInstance *instance); @@ -59,5 +63,11 @@ void app_main(void) }, }; +#if CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE + esp_console_config_t console_config = ESP_CONSOLE_CONFIG_DEFAULT(); + esp_console_init(&console_config); + esp_console_register_help_command(); +#endif + ESP_ERROR_CHECK(esp_openthread_start(&config)); } diff --git a/examples/openthread/ot_rcp/sdkconfig.defaults b/examples/openthread/ot_rcp/sdkconfig.defaults index 0419e6a33c..d35408beb2 100644 --- a/examples/openthread/ot_rcp/sdkconfig.defaults +++ b/examples/openthread/ot_rcp/sdkconfig.defaults @@ -52,3 +52,9 @@ CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC=n CONFIG_OPENTHREAD_LOG_LEVEL_NONE=y CONFIG_OPENTHREAD_TIMING_OPTIMIZATION=y CONFIG_FREERTOS_HZ=1000 + +# +# Turn on RCP console by default, overriding default log level from above +# +CONFIG_OPENTHREAD_RCP_SPINEL_CONSOLE=y +CONFIG_LOG_DEFAULT_LEVEL_INFO=y From c9c25684ca3bc55a4c341e2646ac4f0af7a35222 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 8 Sep 2025 17:24:25 +0800 Subject: [PATCH 067/156] feat(isp): support Crop driver on p4 rev3 Add support for crop driver on p4eco5 and update example in `isp/multi_pipelines` --- components/esp_driver_isp/CMakeLists.txt | 4 + .../esp_driver_isp/include/driver/isp.h | 1 + .../esp_driver_isp/include/driver/isp_crop.h | 64 +++++ .../include/esp_private/isp_private.h | 1 + components/esp_driver_isp/src/isp_crop.c | 80 ++++++ .../esp_lcd/dsi/include/esp_lcd_mipi_dsi.h | 2 +- components/hal/esp32p4/include/hal/isp_ll.h | 143 ++++++++++ .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 1 + docs/doxygen/Doxyfile_esp32p4 | 1 + docs/en/api-reference/peripherals/isp.rst | 49 +++- docs/zh_CN/api-reference/peripherals/isp.rst | 55 +++- .../dsi_init/example_dsi_init.c | 42 ++- .../dsi_init/include/example_dsi_init.h | 39 ++- .../camera/dvp_dsi/main/dvp_dsi_main.c | 6 +- .../camera/dvp_dsi/main/example_config.h | 3 + .../dvp_isp_dsi/main/dvp_isp_dsi_main.c | 6 +- .../camera/dvp_isp_dsi/main/example_config.h | 1 + .../dvp_spi_lcd/main/dvp_spi_lcd_main.c | 4 +- .../camera/dvp_spi_lcd/main/example_config.h | 1 + .../camera/mipi_isp_dsi/main/example_config.h | 1 + .../mipi_isp_dsi/main/mipi_isp_dsi_main.c | 4 +- .../peripherals/isp/multi_pipelines/README.md | 44 +++- .../multi_pipelines/main/Kconfig.projbuild | 53 ++++ .../isp/multi_pipelines/main/example_config.h | 1 + .../isp/multi_pipelines/main/isp_dsi_main.c | 248 ++++++++++++++++-- .../ppa/ppa_dsi/main/ppa_dsi_main.c | 2 +- 27 files changed, 806 insertions(+), 54 deletions(-) create mode 100644 components/esp_driver_isp/include/driver/isp_crop.h create mode 100644 components/esp_driver_isp/src/isp_crop.c diff --git a/components/esp_driver_isp/CMakeLists.txt b/components/esp_driver_isp/CMakeLists.txt index f20d5847b7..476fb925a2 100644 --- a/components/esp_driver_isp/CMakeLists.txt +++ b/components/esp_driver_isp/CMakeLists.txt @@ -46,6 +46,10 @@ if(CONFIG_SOC_ISP_WBG_SUPPORTED) list(APPEND srcs "src/isp_wbg.c") endif() +if(CONFIG_SOC_ISP_CROP_SUPPORTED) + list(APPEND srcs "src/isp_crop.c") +endif() + if(NOT ${target} STREQUAL "linux") list(APPEND requires esp_mm) endif() diff --git a/components/esp_driver_isp/include/driver/isp.h b/components/esp_driver_isp/include/driver/isp.h index 0bdd11d8db..7fcd99650a 100644 --- a/components/esp_driver_isp/include/driver/isp.h +++ b/components/esp_driver_isp/include/driver/isp.h @@ -25,3 +25,4 @@ #include "driver/isp_lsc.h" #include "driver/isp_sharpen.h" #include "driver/isp_wbg.h" +#include "driver/isp_crop.h" diff --git a/components/esp_driver_isp/include/driver/isp_crop.h b/components/esp_driver_isp/include/driver/isp_crop.h new file mode 100644 index 0000000000..fa6986d3eb --- /dev/null +++ b/components/esp_driver_isp/include/driver/isp_crop.h @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_err.h" +#include "driver/isp_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief ISP crop configurations + */ +typedef struct { + isp_window_t window; /*!< Crop window coordinates */ +} esp_isp_crop_config_t; + +/** + * @brief ISP Crop configuration + * + * @note After calling this API, crop doesn't take into effect until `esp_isp_crop_enable` is called + * + * @param[in] isp_proc Processor handle + * @param[in] config Crop configurations, set NULL to de-configure the ISP Crop + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid + */ +esp_err_t esp_isp_crop_configure(isp_proc_handle_t isp_proc, const esp_isp_crop_config_t *config); + +/** + * @brief Enable ISP crop function + * + * @param[in] isp_proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_crop_enable(isp_proc_handle_t isp_proc); + +/** + * @brief Disable ISP crop function + * + * @param[in] isp_proc Processor handle + * + * @return + * - ESP_OK On success + * - ESP_ERR_INVALID_ARG If the combination of arguments is invalid. + * - ESP_ERR_INVALID_STATE Driver state is invalid. + */ +esp_err_t esp_isp_crop_disable(isp_proc_handle_t isp_proc); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_driver_isp/include/esp_private/isp_private.h b/components/esp_driver_isp/include/esp_private/isp_private.h index e94fe16e64..7684801b84 100644 --- a/components/esp_driver_isp/include/esp_private/isp_private.h +++ b/components/esp_driver_isp/include/esp_private/isp_private.h @@ -85,6 +85,7 @@ typedef struct isp_processor_t { ISP_ATOMIC_TYPE(isp_fsm_t) blc_fsm; ISP_ATOMIC_TYPE(isp_fsm_t) ccm_fsm; ISP_ATOMIC_TYPE(isp_fsm_t) color_fsm; + ISP_ATOMIC_TYPE(isp_fsm_t) crop_fsm; ISP_ATOMIC_TYPE(isp_fsm_t) demosaic_fsm; ISP_ATOMIC_TYPE(isp_fsm_t) gamma_fsm; ISP_ATOMIC_TYPE(isp_fsm_t) lsc_fsm; diff --git a/components/esp_driver_isp/src/isp_crop.c b/components/esp_driver_isp/src/isp_crop.c new file mode 100644 index 0000000000..dd879eec72 --- /dev/null +++ b/components/esp_driver_isp/src/isp_crop.c @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/isp_core.h" +#include "driver/isp_crop.h" +#include "esp_private/isp_private.h" +#include "hal/efuse_hal.h" +#include "soc/chip_revision.h" + +/*--------------------------------------------------------------- + Crop +---------------------------------------------------------------*/ + +#define IS_EVEN(x) ((x) % 2 == 0) +#define IS_ODD(x) ((x) % 2 != 0) + +static const char *TAG = "ISP_CROP"; + +esp_err_t esp_isp_crop_configure(isp_proc_handle_t isp_proc, const esp_isp_crop_config_t *config) +{ +#if CONFIG_IDF_TARGET_ESP32P4 + unsigned chip_version = efuse_hal_chip_revision(); + if (!ESP_CHIP_REV_ABOVE(chip_version, 300)) { + ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "Crop is not supported on ESP32P4 chips prior than v3.0"); + } +#endif + uint32_t x_start = config->window.top_left.x; + uint32_t x_end = config->window.btm_right.x; + uint32_t y_start = config->window.top_left.y; + uint32_t y_end = config->window.btm_right.y; + + ESP_RETURN_ON_FALSE(isp_proc && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(isp_proc->crop_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "crop is enabled already"); + ESP_RETURN_ON_FALSE(x_start < x_end, ESP_ERR_INVALID_ARG, TAG, "invalid window x coordinates"); + ESP_RETURN_ON_FALSE(y_start < y_end, ESP_ERR_INVALID_ARG, TAG, "invalid window y coordinates"); + ESP_RETURN_ON_FALSE(x_end <= isp_proc->h_res, ESP_ERR_INVALID_ARG, TAG, "window exceeds horizontal resolution"); + ESP_RETURN_ON_FALSE(y_end <= isp_proc->v_res, ESP_ERR_INVALID_ARG, TAG, "window exceeds vertical resolution"); + + // Check the validity of x/y coordinates + ESP_RETURN_ON_FALSE(IS_EVEN(x_start), ESP_ERR_INVALID_ARG, TAG, "x_start must be even"); + ESP_RETURN_ON_FALSE(IS_ODD(x_end), ESP_ERR_INVALID_ARG, TAG, "x_end must be odd"); + ESP_RETURN_ON_FALSE(IS_EVEN(y_start), ESP_ERR_INVALID_ARG, TAG, "y_start must be even"); + ESP_RETURN_ON_FALSE(IS_ODD(y_end), ESP_ERR_INVALID_ARG, TAG, "y_end must be odd"); + + isp_ll_crop_set_clk_ctrl_mode(isp_proc->hal.hw, ISP_LL_PIPELINE_CLK_CTRL_AUTO); + isp_ll_crop_set_window(isp_proc->hal.hw, x_start, x_end, y_start, y_end); + + return ESP_OK; +} + +esp_err_t esp_isp_crop_enable(isp_proc_handle_t isp_proc) +{ + ESP_RETURN_ON_FALSE(isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(isp_proc->crop_fsm == ISP_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "crop is enabled already"); + + isp_ll_crop_enable(isp_proc->hal.hw, true); + isp_proc->crop_fsm = ISP_FSM_ENABLE; + + ESP_LOGD(TAG, "Crop enabled"); + return ESP_OK; +} + +esp_err_t esp_isp_crop_disable(isp_proc_handle_t isp_proc) +{ + ESP_RETURN_ON_FALSE(isp_proc, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(isp_proc->crop_fsm == ISP_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "crop isn't enabled yet"); + + isp_ll_crop_enable(isp_proc->hal.hw, false); + isp_proc->crop_fsm = ISP_FSM_INIT; + + ESP_LOGD(TAG, "Crop disabled"); + return ESP_OK; +} diff --git a/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h b/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h index 1a78873968..99917c7742 100644 --- a/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h +++ b/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/hal/esp32p4/include/hal/isp_ll.h b/components/hal/esp32p4/include/hal/isp_ll.h index e4fa919634..d5abfc435d 100644 --- a/components/hal/esp32p4/include/hal/isp_ll.h +++ b/components/hal/esp32p4/include/hal/isp_ll.h @@ -70,7 +70,11 @@ extern "C" { #define ISP_LL_EVENT_WBG_FRAME (1<<30) #define ISP_LL_EVENT_CROP_ERR (1<<31) +#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 +#define ISP_LL_EVENT_ALL_MASK (0xFFFFFFFF) +#else #define ISP_LL_EVENT_ALL_MASK (0x1FFFFFFF) +#endif #define ISP_LL_EVENT_AF_MASK (ISP_LL_EVENT_AF_FDONE | ISP_LL_EVENT_AF_ENV) #define ISP_LL_EVENT_AE_MASK (ISP_LL_EVENT_AE_FDONE | ISP_LL_EVENT_AE_ENV) #define ISP_LL_EVENT_AWB_MASK (ISP_LL_EVENT_AWB_FDONE | ISP_LL_EVENT_WBG_FRAME) @@ -199,6 +203,23 @@ typedef enum { ISP_SHADOW_MODE_UPDATE_ONLY_NEXT_VSYNC, } isp_ll_shadow_mode_t; +/*--------------------------------------------------------------- + Crop +---------------------------------------------------------------*/ + +/** + * @brief ISP crop error types + */ +typedef enum { + ISP_LL_CROP_ERR_X_MISMATCH = (1 << 0), /*!< X end coordinate exceeds image size */ + ISP_LL_CROP_ERR_Y_MISMATCH = (1 << 1), /*!< Y end coordinate exceeds image size */ + ISP_LL_CROP_ERR_X_END_EVEN = (1 << 2), /*!< X end coordinate is even (should be odd) */ + ISP_LL_CROP_ERR_Y_END_EVEN = (1 << 3), /*!< Y end coordinate is even (should be odd) */ + ISP_LL_CROP_ERR_X_START_ODD = (1 << 4), /*!< X start coordinate is odd (should be even) */ + ISP_LL_CROP_ERR_Y_START_ODD = (1 << 5), /*!< Y start coordinate is odd (should be even) */ +} isp_ll_crop_error_t; + + /*--------------------------------------------------------------- Clock ---------------------------------------------------------------*/ @@ -2451,6 +2472,128 @@ static inline void isp_ll_hist_set_rgb_coefficient(isp_dev_t *hw, const isp_hist HAL_FORCE_MODIFY_U32_REG_FIELD(hw->hist_coeff, hist_coeff_b, rgb_coeff->coeff_b.decimal); } +/*--------------------------------------------------------------- + CROP +---------------------------------------------------------------*/ + +#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 +/** + * @brief Set crop clock control mode + * + * @param[in] hw Hardware instance address + * @param[in] mode 'isp_ll_pipeline_clk_ctrl_t` + */ +static inline void isp_ll_crop_set_clk_ctrl_mode(isp_dev_t *hw, isp_ll_pipeline_clk_ctrl_t mode) +{ + hw->clk_en.clk_crop_force_on = mode; +} + +/** + * @brief Enable/Disable ISP crop + * + * @param[in] hw Hardware instance address + * @param[in] en enable / disable + */ +static inline void isp_ll_crop_enable(isp_dev_t *hw, bool enable) +{ + hw->cntl.crop_en = enable; +} + +/** + * @brief Set ISP crop window coordinates + * + * @param[in] hw Hardware instance address + * @param[in] x_start Crop start x coordinate (0 to image_width-1) + * @param[in] x_end Crop end x coordinate (x_start+1 to image_width-1) + * @param[in] y_start Crop start y coordinate (0 to image_height-1) + * @param[in] y_end Crop end y coordinate (y_start+1 to image_height-1) + */ +static inline void isp_ll_crop_set_window(isp_dev_t *hw, + uint32_t x_start, uint32_t x_end, + uint32_t y_start, uint32_t y_end) +{ + hw->crop_x_capture.crop_x_start = x_start; + hw->crop_x_capture.crop_x_end = x_end; + hw->crop_y_capture.crop_y_start = y_start; + hw->crop_y_capture.crop_y_end = y_end; +} + +/** + * @brief Get crop window coordinates + * + * @param[in] hw Hardware instance address + * @param[out] x_start Crop start x coordinate (0 to image_width-1) + * @param[out] x_end Crop end x coordinate (x_start+1 to image_width-1) + * @param[out] y_start Crop start y coordinate (0 to image_height-1) + * @param[out] y_end Crop end y coordinate (y_start+1 to image_height-1) + */ +static inline void isp_ll_crop_get_window(isp_dev_t *hw, + uint32_t *x_start, uint32_t *x_end, + uint32_t *y_start, uint32_t *y_end) +{ + *x_start = hw->crop_x_capture.crop_x_start; + *x_end = hw->crop_x_capture.crop_x_end; + *y_start = hw->crop_y_capture.crop_y_start; + *y_end = hw->crop_y_capture.crop_y_end; +} + +/** + * @brief Get crop error status + * + * @param[in] hw Hardware instance address + * @param[out] error_bits Error status bits + */ +static inline void isp_ll_crop_get_error_status(isp_dev_t *hw, uint32_t *error_bits) +{ + *error_bits = hw->crop_err_st.val & 0x3F; // Retrieve lower 6 bits +} + +/** + * @brief Clear crop error + * + * @param[in] hw Hardware instance address + */ +static inline void isp_ll_crop_clear_error(isp_dev_t *hw) +{ + hw->crop_ctrl.crop_sft_rst = 1; +} + +#else +static inline void isp_ll_crop_set_clk_ctrl_mode(isp_dev_t *hw, isp_ll_pipeline_clk_ctrl_t mode) +{ + // for compatibility +} + +static inline void isp_ll_crop_enable(isp_dev_t *hw, bool enable) +{ + // for compatibility +} + +static inline void isp_ll_crop_set_window(isp_dev_t *hw, + uint32_t x_start, uint32_t x_end, + uint32_t y_start, uint32_t y_end) +{ + // for compatibility +} + +static inline void isp_ll_crop_get_window(isp_dev_t *hw, + uint32_t *x_start, uint32_t *x_end, + uint32_t *y_start, uint32_t *y_end) +{ + // for compatibility +} + +static inline void isp_ll_crop_get_error_status(isp_dev_t *hw, uint32_t *error_bits) +{ + // for compatibility +} + +static inline void isp_ll_crop_clear_error(isp_dev_t *hw) +{ + // for compatibility +} +#endif //#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 2abc997658..f5246f3bfb 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -947,6 +947,10 @@ config SOC_ISP_COLOR_SUPPORTED bool default y +config SOC_ISP_CROP_SUPPORTED + bool + default y + config SOC_ISP_DEMOSAIC_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index af7dfdaabe..4b75ab90c7 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -357,6 +357,7 @@ #define SOC_ISP_BLC_SUPPORTED 1 #define SOC_ISP_CCM_SUPPORTED 1 #define SOC_ISP_COLOR_SUPPORTED 1 +#define SOC_ISP_CROP_SUPPORTED 1 #define SOC_ISP_DEMOSAIC_SUPPORTED 1 #define SOC_ISP_DVP_SUPPORTED 1 #define SOC_ISP_LSC_SUPPORTED 1 diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index bf64bf8cb7..3760106517 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -39,6 +39,7 @@ INPUT += \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_bf.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_blc.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_lsc.h \ + $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_crop.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_demosaic.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_sharpen.h \ $(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_core.h \ diff --git a/docs/en/api-reference/peripherals/isp.rst b/docs/en/api-reference/peripherals/isp.rst index 52a829c66c..b20fd02bdd 100644 --- a/docs/en/api-reference/peripherals/isp.rst +++ b/docs/en/api-reference/peripherals/isp.rst @@ -47,7 +47,7 @@ ISP Pipeline isp_chs [label = "Contrast &\n Hue & Saturation", width = 150, height = 70]; isp_yuv [label = "YUV Limit\n YUB2RGB", width = 120, height = 70]; - isp_header -> BLC -> BF -> LSC -> Demosaic -> CCM -> Gamma -> RGB2YUV -> SHARP -> isp_chs -> isp_yuv -> isp_tail; + isp_header -> BLC -> BF -> LSC -> Demosaic -> CCM -> Gamma -> RGB2YUV -> SHARP -> isp_chs -> isp_yuv -> CROP -> isp_tail; LSC -> HIST Demosaic -> AWB @@ -77,6 +77,7 @@ The ISP driver offers following services: - :ref:`isp-demosaic` - covers how to configure the Demosaic function. - :ref:`isp-gamma-correction` - covers how to enable and configure gamma correction. - :ref:`isp-sharpen` - covers how to configure the sharpening function. +- :ref:`isp-crop` - covers how to enable and configure image cropping function. - :ref:`isp-callback` - covers how to hook user specific code to ISP driver event callback function. - :ref:`isp-thread-safety` - lists which APIs are guaranteed to be thread safe by the driver. - :ref:`isp-kconfig-options` - lists the supported Kconfig options that can bring different effects to the driver. @@ -800,6 +801,51 @@ Calling :cpp:func:`esp_isp_sharpen_disable` does the opposite, that is, put the :cpp:func:`esp_isp_sharpen_configure` is allowed to be called even if the driver is in **init** state, but the sharpen configurations will only be taken into effect when in **enable** state. +.. _isp-crop: + +ISP Image Crop Controller +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ISP image crop function can extract a specified region from the original image, reducing the amount of data for subsequent processing and improving processing efficiency. The crop function is executed at the end of the ISP pipeline and can output a smaller region than the input image. + +.. note:: + + The ISP image crop function is only available on ESP32-P4 revision 3.0 and above. + +Calling :cpp:func:`esp_isp_crop_configure` to configure the image crop function, you can take the following code as reference: + +.. code-block:: c + + esp_isp_crop_config_t crop_config = { + .window = { + .top_left = { + .x = 100, // Top-left X coordinate of crop region + .y = 100, // Top-left Y coordinate of crop region + }, + .btm_right = { + .x = 699, // Bottom-right X coordinate of crop region + .y = 499, // Bottom-right Y coordinate of crop region + } + } + }; + ESP_ERROR_CHECK(esp_isp_crop_configure(isp_proc, &crop_config)); + ESP_ERROR_CHECK(esp_isp_crop_enable(isp_proc)); + +After calling :cpp:func:`esp_isp_crop_configure`, you need to enable the ISP image crop controller by calling :cpp:func:`esp_isp_crop_enable`. This function: + +* Switches the driver state from **init** to **enable**. + +Calling :cpp:func:`esp_isp_crop_disable` does the opposite, that is, put the driver back to the **init** state. + +:cpp:func:`esp_isp_crop_configure` is allowed to be called even if the driver is in **init** state, but the crop configurations will only be taken into effect when in **enable** state. + +.. note:: + + - The top-left coordinates (top_left) of the crop region must be smaller than the bottom-right coordinates (btm_right) + - The top-left coordinates (top_left) of the crop region must be even, and the bottom-right coordinates (btm_right) must be odd + - The crop region cannot exceed the boundaries of the original image + - Adjust the display medium (such as LCD) size according to the cropped resolution to ensure complete display and avoid black borders or stretching. + .. _isp-callback: @@ -927,6 +973,7 @@ API Reference .. include-build-file:: inc/isp_gamma.inc .. include-build-file:: inc/isp_hist.inc .. include-build-file:: inc/isp_color.inc +.. include-build-file:: inc/isp_crop.inc .. include-build-file:: inc/isp_core.inc .. include-build-file:: inc/components/esp_driver_isp/include/driver/isp_types.inc .. include-build-file:: inc/components/hal/include/hal/isp_types.inc diff --git a/docs/zh_CN/api-reference/peripherals/isp.rst b/docs/zh_CN/api-reference/peripherals/isp.rst index 4b7e441f8a..009eed08b0 100644 --- a/docs/zh_CN/api-reference/peripherals/isp.rst +++ b/docs/zh_CN/api-reference/peripherals/isp.rst @@ -47,7 +47,7 @@ ISP 流水线 isp_chs [label = "对比度 &\n 色调 & 饱和度", width = 150, height = 70]; isp_yuv [label = "YUV 限制\n YUB2RGB", width = 120, height = 70]; - isp_header -> BLC -> BF -> LSC -> 去马赛克 -> CCM -> gamma 校正 -> RGB 转 YUV -> 锐化 -> isp_chs -> isp_yuv -> isp_tail; + isp_header -> BLC -> BF -> LSC -> 去马赛克 -> CCM -> gamma 校正 -> RGB 转 YUV -> 锐化 -> isp_chs -> isp_yuv -> 裁剪 -> isp_tail; LSC -> HIST 去马赛克 -> AWB @@ -77,6 +77,7 @@ ISP 驱动程序提供以下服务: - :ref:`isp-demosaic` - 涵盖如何配置去马赛克功能。 - :ref:`isp-gamma-correction` - 涵盖如何启用和配置 gamma 校正。 - :ref:`isp-sharpen` - 涵盖如何配置锐化功能。 +- :ref:`isp-crop` - 涵盖如何启用和配置图像裁剪功能。 - :ref:`isp-callback` - 涵盖如何将用户特定代码挂接到 ISP 驱动事件回调。 - :ref:`isp-thread-safety` - 列出了驱动程序中线程安全的 API。 - :ref:`isp-kconfig-options` - 列出了支持的 Kconfig 选项,这些选项可以对驱动程序产生不同影响。 @@ -262,7 +263,7 @@ ISP AF 控制器 使用连续统计时,AF 环境检测器将失效。 -.. code-block:: c +.. code:: c esp_isp_af_config_t af_config = { .edge_thresh = 128, @@ -399,7 +400,7 @@ ISP AE 控制器 .. code-block:: c - esp_isp_ae_config_t ae_config = { + esp_isp_ae_config_t ae_config = { .sample_point = ISP_AE_SAMPLE_POINT_AFTER_DEMOSAIC, }; isp_ae_ctlr_t ae_ctlr = NULL; @@ -518,7 +519,6 @@ ISP BF 控制器 调用 :cpp:func:`esp_isp_bf_disable` 函数会执行相反的操作,即将驱动程序恢复到 **init** 状态。 - .. _isp-blc: ISP BLC 控制器 @@ -801,6 +801,50 @@ ISP 锐化控制器 即使驱动程序处于 **init** 状态,也可以调用 :cpp:func:`esp_isp_sharpen_configure`,但锐化配置只有在 **enable** 状态下才会生效。 +.. _isp-crop: + +ISP 图像裁剪控制器 +~~~~~~~~~~~~~~~~~~ + +ISP 图像裁剪功能可以从原始图像中提取指定区域,减少后续处理的数据量,提高处理效率。裁剪功能在 ISP 流水线的末端执行,可以输出比输入图像更小的区域。 + +.. note:: + + ISP 图像裁剪功能仅在 ESP32-P4 revision 3.0 及以上版本中可用。 + +可调用 :cpp:func:`esp_isp_crop_configure` 函数配置图像裁剪功能,请参考以下代码: + +.. code-block:: c + + esp_isp_crop_config_t crop_config = { + .window = { + .top_left = { + .x = 100, // 裁剪区域左上角 X 坐标 + .y = 100, // 裁剪区域左上角 Y 坐标 + }, + .btm_right = { + .x = 699, // 裁剪区域右下角 X 坐标 + .y = 499, // 裁剪区域右下角 Y 坐标 + } + } + }; + ESP_ERROR_CHECK(esp_isp_crop_configure(isp_proc, &crop_config)); + ESP_ERROR_CHECK(esp_isp_crop_enable(isp_proc)); + +调用 :cpp:func:`esp_isp_crop_configure` 后,需要通过调用 :cpp:func:`esp_isp_crop_enable` 来启用 ISP 图像裁剪控制器。此函数: + +* 将驱动程序状态从 **init** 切换到 **enable**。 + +调用 :cpp:func:`esp_isp_crop_disable` 函数会执行相反的操作,即将驱动程序恢复到 **init** 状态。 + +即使驱动程序处于 **init** 状态,也可以调用 :cpp:func:`esp_isp_crop_configure`,但裁剪配置只有在 **enable** 状态下才会生效。 + +.. note:: + + - 裁剪区域的左上角坐标 (top_left) 必须小于右下角坐标 (btm_right) + - 裁剪区域的左上角坐标必须为偶数,右下角坐标必须为奇数 + - 裁剪区域不能超出原始图像的边界 + - 需根据裁剪后分辨率调整显示介质(如LCD)的尺寸,确保显示完整,避免出现黑边或拉伸现象。 .. _isp-callback: @@ -850,7 +894,7 @@ ISP AE 环境检测器启动后,将动态生成特定事件。若想在事件 注册 ISP HIST 统计完成事件回调函数 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -ISP HIST 控制器完成亮度统计后,将动态生成特定事件。若想在统计完成时收到通知,请通过调用 :cpp:func:`esp_isp_hist_register_event_callbacks` 将目标函数挂挂接到中断服务程序。所有支持的事件回调函数可参见 :cpp:type:`esp_isp_hist_cbs_t`: +ISP HIST 控制器完成亮度统计后,将动态生成特定事件。若想在统计完成时收到通知,请通过调用 :cpp:func:`esp_isp_hist_register_event_callbacks` 将目标函数挂接到中断服务程序。所有支持的事件回调函数可参见 :cpp:type:`esp_isp_hist_cbs_t`: - :cpp:member:`esp_isp_hist_cbs_t::on_statistics_done` 在完成亮度统计时设置回调函数。该函数原型在 :cpp:type:`esp_isp_hist_callback_t` 中声明。 @@ -928,6 +972,7 @@ API 参考 .. include-build-file:: inc/isp_gamma.inc .. include-build-file:: inc/isp_hist.inc .. include-build-file:: inc/isp_color.inc +.. include-build-file:: inc/isp_crop.inc .. include-build-file:: inc/isp_core.inc .. include-build-file:: inc/components/esp_driver_isp/include/driver/isp_types.inc .. include-build-file:: inc/components/hal/include/hal/isp_types.inc diff --git a/examples/peripherals/camera/common_components/dsi_init/example_dsi_init.c b/examples/peripherals/camera/common_components/dsi_init/example_dsi_init.c index 3b2413b988..f9bc0c8cde 100644 --- a/examples/peripherals/camera/common_components/dsi_init/example_dsi_init.c +++ b/examples/peripherals/camera/common_components/dsi_init/example_dsi_init.c @@ -15,7 +15,14 @@ #include "example_dsi_init_config.h" #include "sdkconfig.h" -void example_dsi_resource_alloc(esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, esp_lcd_panel_io_handle_t *mipi_dbi_io, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer) +static const char *TAG = "example_dsi_init"; + +void example_dsi_resource_alloc(const example_dsi_alloc_config_t *config, + esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, + esp_lcd_panel_io_handle_t *mipi_dbi_io, + esp_lcd_panel_handle_t *mipi_dpi_panel, + void** fb0, + void** fb1) { //---------------DSI resource allocation------------------// esp_lcd_dsi_bus_config_t bus_config = { @@ -32,7 +39,22 @@ void example_dsi_resource_alloc(esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, esp_lcd_ }; ESP_ERROR_CHECK(esp_lcd_new_panel_io_dbi(*mipi_dsi_bus, &dbi_config, mipi_dbi_io)); + // Use default config if not provided + example_dsi_alloc_config_t default_config = EXAMPLE_DSI_ALLOC_CONFIG_DEFAULT(); + if (config == NULL) { + config = &default_config; + } + + if (config->num_fbs < 1 || config->num_fbs > 2) { + ESP_LOGE(TAG, "Invalid num_fbs: %d, must be 1 or 2", config->num_fbs); + return; + } + + uint8_t num_fbs = config->num_fbs; + ESP_LOGI(TAG, "Allocating DSI resources with %d frame buffer(s)", num_fbs); + esp_lcd_dpi_panel_config_t dpi_config = { + .num_fbs = num_fbs, .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, .dpi_clock_freq_mhz = EXAMPLE_MIPI_DSI_DPI_CLK_MHZ, .virtual_channel = 0, @@ -83,7 +105,23 @@ void example_dsi_resource_alloc(esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, esp_lcd_ ESP_ERROR_CHECK(esp_lcd_new_panel_ek79007(*mipi_dbi_io, &lcd_dev_config, mipi_dpi_panel)); #endif - ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 1, frame_buffer)); + // Get frame buffer addresses + if (fb0 != NULL) { + if (num_fbs == 2) { + if (fb1 != NULL) { + ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 2, fb0, fb1)); + ESP_LOGD(TAG, "Frame buffer[0] allocated at: %p", *fb0); + ESP_LOGD(TAG, "Frame buffer[1] allocated at: %p", *fb1); + } else { + ESP_LOGW(TAG, "num_fbs is 2 but fb1 is NULL, only getting fb0"); + ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 1, fb0)); + ESP_LOGD(TAG, "Frame buffer[0] allocated at: %p", *fb0); + } + } else { + ESP_ERROR_CHECK(esp_lcd_dpi_panel_get_frame_buffer(*mipi_dpi_panel, 1, fb0)); + ESP_LOGD(TAG, "Frame buffer[0] allocated at: %p", *fb0); + } + } } void example_dpi_panel_reset(esp_lcd_panel_handle_t mipi_dpi_panel) diff --git a/examples/peripherals/camera/common_components/dsi_init/include/example_dsi_init.h b/examples/peripherals/camera/common_components/dsi_init/include/example_dsi_init.h index 433c3d0881..bcf1f1073c 100644 --- a/examples/peripherals/camera/common_components/dsi_init/include/example_dsi_init.h +++ b/examples/peripherals/camera/common_components/dsi_init/include/example_dsi_init.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,14 +14,37 @@ extern "C" { #endif /** - * @brief DSI init function - * - * @param[out] mipi_dsi_bus MIPI DSI bus handle - * @param[out] mipi_dbi_io MIPI DBI io handle - * @param[out] mipi_dpi_panel MIPI DPI panel handle - * @param[out] frame_buffer frame buffer + * @brief DSI allocation configuration */ -void example_dsi_resource_alloc(esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, esp_lcd_panel_io_handle_t *mipi_dbi_io, esp_lcd_panel_handle_t *mipi_dpi_panel, void **frame_buffer); +typedef struct { + uint8_t num_fbs; /*!< Number of frame buffers (1-2). */ +} example_dsi_alloc_config_t; + +/** + * @brief Default DSI allocation configuration + */ +#define EXAMPLE_DSI_ALLOC_CONFIG_DEFAULT() { \ + .num_fbs = 1, \ +} + +/** + * @brief DSI init function with configurable frame buffers + * + * @param[in] config DSI allocation configuration. If NULL, uses default (single buffer) + * @param[out] mipi_dsi_bus MIPI DSI bus handle + * @param[out] mipi_dbi_io MIPI DBI io handle + * @param[out] mipi_dpi_panel MIPI DPI panel handle + * @param[out] fb0 Pointer to receive the address of frame buffer 0 (first frame buffer) + * @param[out] fb1 Pointer to receive the address of frame buffer 1 (second frame buffer). If NULL, single buffer mode is used. + * + * @note The number of frame buffers allocated is determined by config->num_fbs. If config is NULL, single buffer mode is used. + */ +void example_dsi_resource_alloc(const example_dsi_alloc_config_t *config, + esp_lcd_dsi_bus_handle_t *mipi_dsi_bus, + esp_lcd_panel_io_handle_t *mipi_dbi_io, + esp_lcd_panel_handle_t *mipi_dpi_panel, + void **fb0, + void **fb1); /** * @brief DPI panel reset function diff --git a/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c b/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c index 8b27b2241a..0bf5d203cc 100644 --- a/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c +++ b/examples/peripherals/camera/dvp_dsi/main/dvp_dsi_main.c @@ -57,10 +57,10 @@ void app_main(void) ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); //---------------DSI Init------------------// - example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer); + example_dsi_resource_alloc(NULL, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer, NULL); //---------------Necessary variable config------------------// - frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL; ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, EXAMPLE_RGB565_BITS_PER_PIXEL); ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); @@ -108,7 +108,7 @@ void app_main(void) } //--------Allocate Camera Buffer----------// - size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL; void *cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM); if (!cam_buffer) { ESP_LOGE(TAG, "no mem for cam_buffer"); diff --git a/examples/peripherals/camera/dvp_dsi/main/example_config.h b/examples/peripherals/camera/dvp_dsi/main/example_config.h index 6ff0ec4137..eb76ca211f 100644 --- a/examples/peripherals/camera/dvp_dsi/main/example_config.h +++ b/examples/peripherals/camera/dvp_dsi/main/example_config.h @@ -13,6 +13,8 @@ extern "C" { #endif #define EXAMPLE_RGB565_BITS_PER_PIXEL (16) +#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8) + #define EXAMPLE_DVP_CAM_XCLK_FREQ_HZ (20000000) #define EXAMPLE_DVP_CAM_DATA_WIDTH (8) @@ -36,6 +38,7 @@ extern "C" { #define EXAMPLE_DVP_CAM_HSYNC_IO (-1) #else + #define EXAMPLE_DVP_CAM_SCCB_SCL_IO (33) #define EXAMPLE_DVP_CAM_SCCB_SDA_IO (32) diff --git a/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c b/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c index 9b6c049dfb..6bd754312e 100644 --- a/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c +++ b/examples/peripherals/camera/dvp_isp_dsi/main/dvp_isp_dsi_main.c @@ -89,10 +89,10 @@ void app_main(void) * ISP convert to RGB565 */ //---------------DSI Init------------------// - example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer); + example_dsi_resource_alloc(NULL, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer, NULL); //---------------Necessary variable config------------------// - frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL; ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, EXAMPLE_RGB565_BITS_PER_PIXEL); ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); @@ -157,7 +157,7 @@ void app_main(void) } //--------Allocate Camera Buffer----------// - size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL; void *cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM); if (!cam_buffer) { ESP_LOGE(TAG, "no mem for cam_buffer"); diff --git a/examples/peripherals/camera/dvp_isp_dsi/main/example_config.h b/examples/peripherals/camera/dvp_isp_dsi/main/example_config.h index 81b3188c62..c2eb00ffce 100644 --- a/examples/peripherals/camera/dvp_isp_dsi/main/example_config.h +++ b/examples/peripherals/camera/dvp_isp_dsi/main/example_config.h @@ -13,6 +13,7 @@ extern "C" { #endif #define EXAMPLE_RGB565_BITS_PER_PIXEL 16 +#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8) #define EXAMPLE_ISP_DVP_CAM_SCCB_SCL_IO (33) #define EXAMPLE_ISP_DVP_CAM_SCCB_SDA_IO (32) diff --git a/examples/peripherals/camera/dvp_spi_lcd/main/dvp_spi_lcd_main.c b/examples/peripherals/camera/dvp_spi_lcd/main/dvp_spi_lcd_main.c index eacaf2dff7..d9032a57c5 100644 --- a/examples/peripherals/camera/dvp_spi_lcd/main/dvp_spi_lcd_main.c +++ b/examples/peripherals/camera/dvp_spi_lcd/main/dvp_spi_lcd_main.c @@ -24,7 +24,7 @@ static const char *TAG = "dvp_spi_lcd"; -#define BUFFER_SIZE (CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8) +#define BUFFER_SIZE (CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL) typedef struct { esp_lcd_panel_handle_t panel_hdl; @@ -164,7 +164,7 @@ void app_main(void) } //--------Allocate Camera Buffer----------// - size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + size_t cam_buffer_size = CONFIG_EXAMPLE_CAM_HRES * CONFIG_EXAMPLE_CAM_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL; void *cam_buffer = NULL; cam_buffer = esp_cam_ctlr_alloc_buffer(cam_handle, cam_buffer_size, EXAMPLE_DVP_CAM_BUF_ALLOC_CAPS); diff --git a/examples/peripherals/camera/dvp_spi_lcd/main/example_config.h b/examples/peripherals/camera/dvp_spi_lcd/main/example_config.h index 5609ef560c..95d178d468 100644 --- a/examples/peripherals/camera/dvp_spi_lcd/main/example_config.h +++ b/examples/peripherals/camera/dvp_spi_lcd/main/example_config.h @@ -14,6 +14,7 @@ extern "C" { //----------CAM Config------------// #define EXAMPLE_RGB565_BITS_PER_PIXEL 16 +#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8) #define EXAMPLE_DVP_CAM_SCCB_SCL_IO (5) #define EXAMPLE_DVP_CAM_SCCB_SDA_IO (4) diff --git a/examples/peripherals/camera/mipi_isp_dsi/main/example_config.h b/examples/peripherals/camera/mipi_isp_dsi/main/example_config.h index 570ebdc866..dc2725abad 100644 --- a/examples/peripherals/camera/mipi_isp_dsi/main/example_config.h +++ b/examples/peripherals/camera/mipi_isp_dsi/main/example_config.h @@ -13,6 +13,7 @@ extern "C" { #endif #define EXAMPLE_RGB565_BITS_PER_PIXEL 16 +#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8) #define EXAMPLE_MIPI_IDI_CLOCK_RATE (50000000) #define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4 diff --git a/examples/peripherals/camera/mipi_isp_dsi/main/mipi_isp_dsi_main.c b/examples/peripherals/camera/mipi_isp_dsi/main/mipi_isp_dsi_main.c index d7f3645da6..da5329845c 100644 --- a/examples/peripherals/camera/mipi_isp_dsi/main/mipi_isp_dsi_main.c +++ b/examples/peripherals/camera/mipi_isp_dsi/main/mipi_isp_dsi_main.c @@ -51,10 +51,10 @@ void app_main(void) * ISP convert to RGB565 */ //---------------DSI Init------------------// - example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer); + example_dsi_resource_alloc(NULL, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer, NULL); //---------------Necessary variable config------------------// - frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL; ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, EXAMPLE_RGB565_BITS_PER_PIXEL); ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); diff --git a/examples/peripherals/isp/multi_pipelines/README.md b/examples/peripherals/isp/multi_pipelines/README.md index b526b160d8..1fc9625535 100644 --- a/examples/peripherals/isp/multi_pipelines/README.md +++ b/examples/peripherals/isp/multi_pipelines/README.md @@ -16,6 +16,9 @@ This example demonstrates how to use the ISP (image signal processor) to work wi - ISP GAMMA feature - ISP Color feature - ISP LSC feature +- ISP Crop feature (need to enable in `idf.py menuconfig`) + +Additionally, this example also implements **Dual Frame Buffer (Ping-Pong Buffering)**, which eliminates screen tearing for smooth video display ## Usage @@ -121,6 +124,21 @@ Remember to select the LCD screen model and set corresponding correct horizontal Available options for the camera sensor output horizontal/vertical resolution can be seen in ``menuconfig`` > ``Example Configuration``. Note that the horizontal resolution for the camera should be the same as the LCD screen horizontal resolution. +#### Optional: Image Cropping Configuration + +This example supports optional image cropping, which allows you to capture and display a specific region of the camera output. To enable this feature: + +1. Navigate to `menuconfig` > `Example Configuration` +2. Enable `Enable ISP Image Cropping` +3. Configure the crop region: + - `ISP Crop Top-Left Horizontal`: X coordinate of top-left corner + - `ISP Crop Top-Left Vertical`: Y coordinate of top-left corner + - `ISP Crop Bottom-Right Horizontal`: X coordinate of bottom-right corner + - `ISP Crop Bottom-Right Vertical`: Y coordinate of bottom-right corner + +**Note**: When cropping is enabled: +- The cropped image maintains its relative position on the screen +- A dedicated frame processing task handles the image transformation ### Build and Flash @@ -142,15 +160,23 @@ To exit the serial monitor, use `Ctrl` + `]`. If you see the following console output, your example should be running correctly: ``` -I (1085) main_task: Calling app_main() -I (1095) ili9881c: ID1: 0x98, ID2: 0x81, ID3: 0x5c -I (1125) gpio: GPIO[31]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 -I (1125) gpio: GPIO[34]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 -I (1295) ov5647: Detected Camera sensor PID=0x5647 with index 0 -I (1305) cam_dsi: fmt[0].name:MIPI_2lane_24Minput_RAW8_800x1280_50fps -I (1305) cam_dsi: fmt[1].name:MIPI_2lane_24Minput_RAW8_800x640_50fps -I (1315) cam_dsi: fmt[2].name:MIPI_2lane_24Minput_RAW8_800x800_50fps -I (1355) cam_dsi: Format in use:MIPI_2lane_24Minput_RAW8_800x640_50fps +I (1425) main_task: Calling app_main() +I (1425) example_dsi_init: Allocating DSI resources with 2 frame buffer(s) +I (1485) example_dsi_init: Frame buffer[0] allocated at: 0x48000a40 +I (1485) example_dsi_init: Frame buffer[1] allocated at: 0x481f4a80 +I (1485) isp_dsi: Original CSI resolution: 800x640 +I (1485) isp_dsi: Display resolution: 800x640, bits per pixel: 16 +I (1495) isp_dsi: frame_buffer_size: 2048000 +I (1495) isp_dsi: Frame buffers: fb0=0x48000a40, fb1=0x481f4a80 +I (1515) ov5647: Detected Camera sensor PID=0x5647 +I (1535) sensor_init: fmt[0].name:MIPI_2lane_24Minput_RAW8_800x1280_50fps +I (1535) sensor_init: fmt[1].name:MIPI_2lane_24Minput_RAW8_800x640_50fps +I (1535) sensor_init: fmt[2].name:MIPI_2lane_24Minput_RAW8_800x800_50fps +I (1535) sensor_init: fmt[3].name:MIPI_2lane_24Minput_RAW10_1920x1080_30fps +I (1545) sensor_init: fmt[4].name:MIPI_2lane_24Minput_RAW10_1280x960_binning_45fps +I (2025) sensor_init: Format in use:MIPI_2lane_24Minput_RAW8_800x640_50fps +I (2045) isp_dsi: ISP Crop not configured +I (2105) ili9881c: ID1: 0x98, ID2: 0x81, ID3: 0x5c ``` Below picture is from the video stream of OV5647 and ILI9881C. The camera module is auto-focused and calibrated by ESP on-chip ISP hardware. The edge is over-sharpened as example code configured. diff --git a/examples/peripherals/isp/multi_pipelines/main/Kconfig.projbuild b/examples/peripherals/isp/multi_pipelines/main/Kconfig.projbuild index 98a42e128a..5e4244b886 100644 --- a/examples/peripherals/isp/multi_pipelines/main/Kconfig.projbuild +++ b/examples/peripherals/isp/multi_pipelines/main/Kconfig.projbuild @@ -44,4 +44,57 @@ menu "Example Configuration" default 600 if EXAMPLE_MIPI_CSI_VRES_600 default 640 if EXAMPLE_MIPI_CSI_VRES_640 default 1280 if EXAMPLE_MIPI_CSI_VRES_1280 + + config EXAMPLE_ISP_CROP_ENABLE + depends on (ESP32P4_REV_MIN_FULL >= 300) + bool "Enable ISP crop functionality" + default n + help + Enable ISP crop functionality. When enabled, you can configure + the crop area for the ISP pipeline. + + menu "ISP Crop Configuration" + visible if EXAMPLE_ISP_CROP_ENABLE + + config EXAMPLE_ISP_CROP_TOP_LEFT_H + int "ISP crop top-left horizontal coordinate" + default 0 + range 0 799 if EXAMPLE_MIPI_CSI_HRES_800 + range 0 1023 if EXAMPLE_MIPI_CSI_HRES_1024 + help + Horizontal coordinate of the top-left corner for ISP crop. + Must be an even number and less than bottom-right horizontal coordinate. + + config EXAMPLE_ISP_CROP_TOP_LEFT_V + int "ISP crop top-left vertical coordinate" + default 0 + range 0 599 if EXAMPLE_MIPI_CSI_VRES_600 + range 0 639 if EXAMPLE_MIPI_CSI_VRES_640 + range 0 1279 if EXAMPLE_MIPI_CSI_VRES_1280 + help + Vertical coordinate of the top-left corner for ISP crop. + Must be an even number and less than bottom-right vertical coordinate. + + config EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H + int "ISP crop bottom-right horizontal coordinate" + default 799 if EXAMPLE_MIPI_CSI_HRES_800 + default 1023 if EXAMPLE_MIPI_CSI_HRES_1024 + range 1 799 if EXAMPLE_MIPI_CSI_HRES_800 + range 1 1023 if EXAMPLE_MIPI_CSI_HRES_1024 + help + Horizontal coordinate of the bottom-right corner for ISP crop. + Must be an odd number, greater than top-left horizontal coordinate, and not exceed display width. + + config EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V + int "ISP crop bottom-right vertical coordinate" + default 599 if EXAMPLE_MIPI_CSI_VRES_600 + default 639 if EXAMPLE_MIPI_CSI_VRES_640 + default 1279 if EXAMPLE_MIPI_CSI_VRES_1280 + range 1 599 if EXAMPLE_MIPI_CSI_VRES_600 + range 1 639 if EXAMPLE_MIPI_CSI_VRES_640 + range 1 1279 if EXAMPLE_MIPI_CSI_VRES_1280 + help + Vertical coordinate of the bottom-right corner for ISP crop. + Must be an odd number, greater than top-left vertical coordinate, and not exceed display height. + endmenu endmenu diff --git a/examples/peripherals/isp/multi_pipelines/main/example_config.h b/examples/peripherals/isp/multi_pipelines/main/example_config.h index 9c5482fe39..f4ca7636f0 100644 --- a/examples/peripherals/isp/multi_pipelines/main/example_config.h +++ b/examples/peripherals/isp/multi_pipelines/main/example_config.h @@ -11,6 +11,7 @@ extern "C" { #endif #define EXAMPLE_RGB565_BITS_PER_PIXEL 16 +#define EXAMPLE_RGB565_BYTES_PER_PIXEL (EXAMPLE_RGB565_BITS_PER_PIXEL / 8) #define EXAMPLE_MIPI_SCCB_FREQ (100000) #define EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS 200 //line_rate = pclk * 4 diff --git a/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c b/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c index 79ac257074..b84532617d 100644 --- a/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c +++ b/examples/peripherals/isp/multi_pipelines/main/isp_dsi_main.c @@ -33,6 +33,103 @@ static const char *TAG = "isp_dsi"; static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data); static bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data); +/*--------------------------------------------------------------- + Ping-Pong Buffer Management +---------------------------------------------------------------*/ +typedef struct { + void *fb0; // Frame buffer 0 + void *fb1; // Frame buffer 1 + void *csi_buffer; // Current buffer for CSI to write + void *dsi_buffer; // Current buffer for DSI to display + esp_lcd_panel_handle_t panel;// DPI panel handle + int h_res; // Horizontal resolution + int v_res; // Vertical resolution (full screen) +#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE + int crop_h_res; // Cropped horizontal resolution + int crop_v_res; // Cropped vertical resolution + void *pending_buffer; // Buffer pending to be displayed + SemaphoreHandle_t frame_ready_sem; // Semaphore to signal frame ready +#endif +} pingpong_buffer_ctx_t; + +#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE +/** + * @brief Process frame: Add blank areas to fill full screen resolution + * + * Algorithm: Fill from bottom to top to avoid overwriting crop data + * - Cropped image is placed at original position (relative to full frame) + * - Other areas are filled with white (0xFFFF for RGB565) + * + * Example: Original 100x100, crop (50,50) to (100,100) → shows at bottom-right + * + * @param buffer Frame buffer to process (contains cropped image at start) + * @param ctx Ping-pong buffer context + */ +static void process_frame_with_blanks(void *buffer, pingpong_buffer_ctx_t *ctx) +{ + if (ctx->crop_v_res == ctx->v_res) { + // No cropping, no need to process + return; + } + + uint16_t *fb = (uint16_t *)buffer; + + const int crop_left = CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_H; + const int crop_top = CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_V; + const int crop_right = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H; + const int crop_bottom = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V; + const int crop_width = crop_right - crop_left + 1; + + const int full_width = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES; + const int full_height = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES; + + // Helper macros for pixel indexing +#define SRC_PIXEL(x, y) fb[(y) * crop_width + (x)] +#define DST_PIXEL(x, y) fb[(y) * full_width + (x)] + + // ========== Step 1: Fill bottom blank region [crop_bottom+1, full_height) ========== + if (crop_bottom + 1 < full_height) { + memset(&DST_PIXEL(0, crop_bottom + 1), + 0xFF, + full_width * (full_height - crop_bottom - 1) * EXAMPLE_RGB565_BYTES_PER_PIXEL); + } + + // ========== Step 2: Process crop region [crop_top, crop_bottom] ========== + for (int y = crop_bottom; y >= crop_top; y--) { + int src_y = y - crop_top; // Corresponding row in cropped data (0-based) + + // Fill right blank region first (crop_right+1, full_width) + if (crop_right + 1 < full_width) { + memset(&DST_PIXEL(crop_right + 1, y), + 0xFF, + (full_width - crop_right - 1) * EXAMPLE_RGB565_BYTES_PER_PIXEL); + } + + // Copy crop data from source to destination + memcpy(&DST_PIXEL(crop_left, y), + &SRC_PIXEL(0, src_y), + crop_width * EXAMPLE_RGB565_BYTES_PER_PIXEL); + + // Fill left blank region [0, crop_left) + if (crop_left > 0) { + memset(&DST_PIXEL(0, y), + 0xFF, + crop_left * EXAMPLE_RGB565_BYTES_PER_PIXEL); + } + } + + // ========== Step 3: Fill top blank region [0, crop_top) ========== + if (crop_top > 0) { + memset(&DST_PIXEL(0, 0), + 0xFF, + full_width * crop_top * EXAMPLE_RGB565_BYTES_PER_PIXEL); + } + +#undef SRC_PIXEL +#undef DST_PIXEL +} +#endif + /*--------------------------------------------------------------- AF ---------------------------------------------------------------*/ @@ -185,13 +282,47 @@ static uint32_t s_gamma_correction_curve(uint32_t x) return pow((double)x / 256, 0.7) * 256; } +#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE +/*--------------------------------------------------------------- + Frame Processing Task +---------------------------------------------------------------*/ +static void frame_processing_task(void *arg) +{ + pingpong_buffer_ctx_t *ctx = (pingpong_buffer_ctx_t *)arg; + + while (1) { + // Wait for frame ready signal from ISR + if (xSemaphoreTake(ctx->frame_ready_sem, portMAX_DELAY) == pdTRUE) { + // Process the frame: add blank areas if needed + process_frame_with_blanks(ctx->pending_buffer, ctx); + + // Ping-Pong switch: swap CSI write buffer and DSI display buffer + void *temp = ctx->csi_buffer; + ctx->csi_buffer = ctx->dsi_buffer; + ctx->dsi_buffer = temp; + + // Trigger buffer switch by calling draw_bitmap + // DPI driver will detect which buffer we're using and switch to it + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(ctx->panel, + 0, 0, + ctx->h_res, + ctx->crop_v_res, + ctx->pending_buffer)); + + ESP_LOGD(TAG, "Frame displayed: %p", ctx->pending_buffer); + } + } +} +#endif // CONFIG_EXAMPLE_ISP_CROP_ENABLE + void app_main(void) { esp_err_t ret = ESP_FAIL; esp_lcd_dsi_bus_handle_t mipi_dsi_bus = NULL; esp_lcd_panel_io_handle_t mipi_dbi_io = NULL; esp_lcd_panel_handle_t mipi_dpi_panel = NULL; - void *frame_buffer = NULL; + void *fb0 = NULL; + void *fb1 = NULL; size_t frame_buffer_size = 0; //mipi ldo @@ -207,18 +338,54 @@ void app_main(void) * Sensor use RAW8 * ISP convert to RGB565 */ - //---------------DSI Init------------------// - example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &frame_buffer); + //---------------DSI Init with Dual Frame Buffers------------------// + example_dsi_alloc_config_t dsi_alloc_config = { + .num_fbs = 2, // Enable dual frame buffers + }; + example_dsi_resource_alloc(&dsi_alloc_config, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, &fb0, &fb1); //---------------Necessary variable config------------------// - frame_buffer_size = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BITS_PER_PIXEL / 8; + int display_h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES; + int display_v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES; - ESP_LOGD(TAG, "CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES: %d, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES: %d, bits per pixel: %d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, 8); - ESP_LOGD(TAG, "frame_buffer_size: %zu", frame_buffer_size); - ESP_LOGD(TAG, "frame_buffer: %p", frame_buffer); +#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE + // Use cropped resolution for frame buffer + display_h_res = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H - CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_H + 1; + display_v_res = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V - CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_V + 1; +#endif + + frame_buffer_size = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL; + + ESP_LOGI(TAG, "Original CSI resolution: %dx%d", CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES); + ESP_LOGI(TAG, "Display resolution: %dx%d, bits per pixel: %d", display_h_res, display_v_res, EXAMPLE_RGB565_BITS_PER_PIXEL); + ESP_LOGI(TAG, "Frame buffers: fb0=%p, fb1=%p", fb0, fb1); + + //---------------Ping-Pong Buffer Context------------------// + pingpong_buffer_ctx_t pp_ctx = { + .fb0 = fb0, + .fb1 = fb1, + .csi_buffer = fb0, // CSI starts writing to fb0 + .dsi_buffer = fb1, // DSI starts displaying fb1 + .panel = mipi_dpi_panel, + .h_res = CONFIG_EXAMPLE_MIPI_DSI_DISP_HRES, + .v_res = CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES, +#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE + .crop_h_res = display_h_res, + .crop_v_res = display_v_res, + .pending_buffer = NULL, + .frame_ready_sem = xSemaphoreCreateBinary(), +#endif + }; + +#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE + if (pp_ctx.frame_ready_sem == NULL) { + ESP_LOGE(TAG, "Failed to create frame ready semaphore"); + return; + } +#endif esp_cam_ctlr_trans_t new_trans = { - .buffer = frame_buffer, + .buffer = pp_ctx.csi_buffer, .buflen = frame_buffer_size, }; @@ -248,8 +415,8 @@ void app_main(void) //---------------CSI Init------------------// esp_cam_ctlr_csi_config_t csi_config = { .ctlr_id = 0, - .h_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES, - .v_res = CONFIG_EXAMPLE_MIPI_CSI_DISP_VRES, + .h_res = display_h_res, + .v_res = display_v_res, .lane_bit_rate_mbps = EXAMPLE_MIPI_CSI_LANE_BITRATE_MBPS, .input_data_color_type = CAM_CTLR_COLOR_RAW8, .output_data_color_type = CAM_CTLR_COLOR_RGB565, @@ -268,7 +435,7 @@ void app_main(void) .on_get_new_trans = s_camera_get_new_vb, .on_trans_finished = s_camera_get_finished_trans, }; - if (esp_cam_ctlr_register_event_callbacks(handle, &cbs, &new_trans) != ESP_OK) { + if (esp_cam_ctlr_register_event_callbacks(handle, &cbs, &pp_ctx) != ESP_OK) { ESP_LOGE(TAG, "ops register fail"); return; } @@ -422,6 +589,29 @@ void app_main(void) ESP_ERROR_CHECK(esp_isp_lsc_enable(isp_proc)); #endif +#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE + /*--------------------------------------------------------------- + CROP + ---------------------------------------------------------------*/ + esp_isp_crop_config_t crop_config = { + .window = { + .top_left = { + .x = CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_H, + .y = CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_V + }, + .btm_right = { + .x = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H, + .y = CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V + } + } + }; + ESP_ERROR_CHECK(esp_isp_crop_configure(isp_proc, &crop_config)); + ESP_ERROR_CHECK(esp_isp_crop_enable(isp_proc)); + ESP_LOGI(TAG, "ISP Crop enabled: (%d,%d) to (%d,%d)", + CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_H, CONFIG_EXAMPLE_ISP_CROP_TOP_LEFT_V, + CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_H, CONFIG_EXAMPLE_ISP_CROP_BOTTOM_RIGHT_V); +#endif + typedef struct af_task_param_t { isp_proc_handle_t isp_proc; esp_sccb_io_handle_t dw9714_io_handle; @@ -433,12 +623,20 @@ void app_main(void) }; xTaskCreatePinnedToCore(af_task, "af_task", 8192, &af_task_param, 5, NULL, 0); +#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE + //---------------Frame Processing Task------------------// + xTaskCreatePinnedToCore(frame_processing_task, "frame_proc", 4096, &pp_ctx, 6, NULL, 0); + ESP_LOGI(TAG, "Frame processing task created"); +#endif + //---------------DPI Reset------------------// example_dpi_panel_reset(mipi_dpi_panel); - //init to all white - memset(frame_buffer, 0xFF, frame_buffer_size); - esp_cache_msync((void *)frame_buffer, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + //init both frame buffers to white + memset(fb0, 0xFF, frame_buffer_size); + memset(fb1, 0xFF, frame_buffer_size); + esp_cache_msync((void *)fb0, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); + esp_cache_msync((void *)fb1, frame_buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M); if (esp_cam_ctlr_start(handle) != ESP_OK) { ESP_LOGE(TAG, "Driver start fail"); @@ -454,14 +652,30 @@ void app_main(void) static bool s_camera_get_new_vb(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data) { - esp_cam_ctlr_trans_t new_trans = *(esp_cam_ctlr_trans_t *)user_data; - trans->buffer = new_trans.buffer; - trans->buflen = new_trans.buflen; + pingpong_buffer_ctx_t *ctx = (pingpong_buffer_ctx_t *)user_data; + + // Provide the current CSI buffer for the next frame + trans->buffer = ctx->csi_buffer; + trans->buflen = CONFIG_EXAMPLE_MIPI_CSI_DISP_HRES * CONFIG_EXAMPLE_MIPI_DSI_DISP_VRES * EXAMPLE_RGB565_BYTES_PER_PIXEL; return false; } bool s_camera_get_finished_trans(esp_cam_ctlr_handle_t handle, esp_cam_ctlr_trans_t *trans, void *user_data) { + pingpong_buffer_ctx_t *ctx = (pingpong_buffer_ctx_t *)user_data; + +#ifdef CONFIG_EXAMPLE_ISP_CROP_ENABLE + BaseType_t high_task_wakeup = pdFALSE; + ctx->pending_buffer = trans->buffer; + xSemaphoreGiveFromISR(ctx->frame_ready_sem, &high_task_wakeup); + return (high_task_wakeup == pdTRUE); +#else + void *temp = ctx->csi_buffer; + ctx->csi_buffer = ctx->dsi_buffer; + ctx->dsi_buffer = temp; + + ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(ctx->panel, 0, 0, ctx->h_res, ctx->v_res, trans->buffer)); return false; +#endif } diff --git a/examples/peripherals/ppa/ppa_dsi/main/ppa_dsi_main.c b/examples/peripherals/ppa/ppa_dsi/main/ppa_dsi_main.c index 02d46d7fb7..04839b51a3 100644 --- a/examples/peripherals/ppa/ppa_dsi/main/ppa_dsi_main.c +++ b/examples/peripherals/ppa/ppa_dsi/main/ppa_dsi_main.c @@ -329,7 +329,7 @@ void app_main(void) ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); //---------------DSI Init------------------// - example_dsi_resource_alloc(&mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, NULL); + example_dsi_resource_alloc(NULL, &mipi_dsi_bus, &mipi_dbi_io, &mipi_dpi_panel, NULL, NULL); example_dpi_panel_reset(mipi_dpi_panel); example_dpi_panel_init(mipi_dpi_panel); From 2ce6e2298642cf167639a05e4275c4515f432779 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Thu, 6 Nov 2025 17:18:31 +0800 Subject: [PATCH 068/156] fix(intr_alloc): Fix ISR allocate methods in several drivers --- components/esp_driver_ledc/src/ledc.c | 10 +++++++++- components/esp_driver_sdio/src/sdio_slave.c | 19 ++++++++++++------- .../include/driver/sdmmc_host.h | 2 +- .../esp_driver_spi/src/gpspi/spi_common.c | 2 +- .../esp_driver_spi/src/gpspi/spi_slave.c | 2 +- components/esp_driver_uart/src/uart.c | 12 +++++++++--- components/hal/esp32/include/hal/ledc_ll.h | 15 ++++++++++++++- .../hal/esp32/include/hal/sdio_slave_ll.h | 13 +++++++++++++ components/hal/esp32/include/hal/uart_ll.h | 6 +++++- components/hal/esp32c2/include/hal/ledc_ll.h | 15 ++++++++++++++- components/hal/esp32c2/include/hal/uart_ll.h | 5 +++++ components/hal/esp32c3/include/hal/ledc_ll.h | 15 ++++++++++++++- components/hal/esp32c3/include/hal/uart_ll.h | 5 +++++ components/hal/esp32c5/include/hal/ledc_ll.h | 15 ++++++++++++++- .../hal/esp32c5/include/hal/sdio_slave_ll.h | 13 +++++++++++++ components/hal/esp32c5/include/hal/uart_ll.h | 5 +++++ components/hal/esp32c6/include/hal/ledc_ll.h | 15 ++++++++++++++- .../hal/esp32c6/include/hal/sdio_slave_ll.h | 13 +++++++++++++ components/hal/esp32c6/include/hal/spi_ll.h | 2 +- components/hal/esp32c6/include/hal/uart_ll.h | 5 +++++ components/hal/esp32c61/include/hal/ledc_ll.h | 15 ++++++++++++++- .../hal/esp32c61/include/hal/sdio_slave_ll.h | 14 ++++++++++++++ components/hal/esp32c61/include/hal/uart_ll.h | 5 +++++ components/hal/esp32h2/include/hal/ledc_ll.h | 15 ++++++++++++++- components/hal/esp32h2/include/hal/spi_ll.h | 2 +- components/hal/esp32h2/include/hal/uart_ll.h | 5 +++++ components/hal/esp32h21/include/hal/uart_ll.h | 5 +++++ components/hal/esp32h4/include/hal/uart_ll.h | 5 +++++ components/hal/esp32p4/include/hal/ledc_ll.h | 15 ++++++++++++++- components/hal/esp32p4/include/hal/uart_ll.h | 5 +++++ components/hal/esp32s2/include/hal/cache_ll.h | 3 ++- components/hal/esp32s2/include/hal/ledc_ll.h | 15 ++++++++++++++- components/hal/esp32s2/include/hal/uart_ll.h | 5 +++++ components/hal/esp32s3/include/hal/ledc_ll.h | 15 ++++++++++++++- components/hal/esp32s3/include/hal/uart_ll.h | 5 +++++ components/hal/include/hal/ledc_hal.h | 8 ++++++++ components/hal/include/hal/sdio_slave_hal.h | 8 ++++++++ components/hal/include/hal/spi_hal.h | 2 +- components/hal/include/hal/spi_slave_hal.h | 2 +- components/hal/include/hal/uart_hal.h | 10 ++++++++++ components/hal/ledc_hal_iram.c | 7 ++++++- components/hal/sdio_slave_hal.c | 5 +++++ components/hal/spi_hal.c | 2 +- 43 files changed, 330 insertions(+), 32 deletions(-) diff --git a/components/esp_driver_ledc/src/ledc.c b/components/esp_driver_ledc/src/ledc.c index 43216629fc..2143982537 100644 --- a/components/esp_driver_ledc/src/ledc.c +++ b/components/esp_driver_ledc/src/ledc.c @@ -1536,7 +1536,15 @@ esp_err_t ledc_fade_func_install(int intr_alloc_flags) { LEDC_CHECK(s_ledc_fade_isr_handle == NULL, "fade function already installed", ESP_ERR_INVALID_STATE); //OR intr_alloc_flags with ESP_INTR_FLAG_IRAM because the fade isr is in IRAM - return ledc_isr_register(ledc_fade_isr, NULL, intr_alloc_flags | ESP_INTR_FLAG_IRAM, &s_ledc_fade_isr_handle); + return esp_intr_alloc_intrstatus( + ETS_LEDC_INTR_SOURCE, + intr_alloc_flags | ESP_INTR_FLAG_IRAM, + (uint32_t)ledc_hal_get_fade_end_intr_addr(&(p_ledc_obj[0]->ledc_hal)), + LEDC_LL_FADE_END_INTR_MASK, + ledc_fade_isr, + NULL, + &s_ledc_fade_isr_handle + ); } void ledc_fade_func_uninstall(void) diff --git a/components/esp_driver_sdio/src/sdio_slave.c b/components/esp_driver_sdio/src/sdio_slave.c index c1256b069e..b5cbc62649 100644 --- a/components/esp_driver_sdio/src/sdio_slave.c +++ b/components/esp_driver_sdio/src/sdio_slave.c @@ -356,15 +356,20 @@ esp_err_t sdio_slave_initialize(sdio_slave_config_t *config) esp_err_t r; intr_handle_t intr_handle = NULL; const int flags = 0; - r = esp_intr_alloc(ETS_SLC0_INTR_SOURCE, flags, sdio_intr, NULL, &intr_handle); - if (r != ESP_OK) { - return r; - } r = init_context(config); - if (r != ESP_OK) { - return r; - } + SDIO_SLAVE_CHECK(r == ESP_OK, "context initialization failed", r); + + r = esp_intr_alloc_intrstatus( + ETS_SLC0_INTR_SOURCE, + flags, + (uint32_t)sdio_slave_hal_get_intr_status_reg(context.hal), + sdio_slave_ll_intr_status_mask, + sdio_intr, + NULL, + &intr_handle + ); + SDIO_SLAVE_CHECK(r == ESP_OK, "interrupt allocation failed", r); context.intr_handle = intr_handle; #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP diff --git a/components/esp_driver_sdmmc/include/driver/sdmmc_host.h b/components/esp_driver_sdmmc/include/driver/sdmmc_host.h index d6d3f856ac..1ed17fe499 100644 --- a/components/esp_driver_sdmmc/include/driver/sdmmc_host.h +++ b/components/esp_driver_sdmmc/include/driver/sdmmc_host.h @@ -15,7 +15,7 @@ #include "esp_err.h" #include "driver/sdmmc_types.h" #include "driver/sdmmc_default_configs.h" -#include "driver/gpio.h" +#include "soc/gpio_num.h" #ifdef __cplusplus extern "C" { diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index 92973a6694..2e8d82d73a 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -815,7 +815,7 @@ esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t * #elif SOC_GDMA_SUPPORTED SPI_CHECK(dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG); #endif - SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH | ESP_INTR_FLAG_EDGE | ESP_INTR_FLAG_INTRDISABLED)) == 0, "intr flag not allowed", ESP_ERR_INVALID_ARG); + SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH | ESP_INTR_FLAG_EDGE | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED)) == 0, "intr flag not allowed", ESP_ERR_INVALID_ARG); #ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM) == 0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_MASTER_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG); #endif diff --git a/components/esp_driver_spi/src/gpspi/spi_slave.c b/components/esp_driver_spi/src/gpspi/spi_slave.c index 8e328fbd2c..23efeeba50 100644 --- a/components/esp_driver_spi/src/gpspi/spi_slave.c +++ b/components/esp_driver_spi/src/gpspi/spi_slave.c @@ -162,7 +162,7 @@ esp_err_t spi_slave_initialize(spi_host_device_t host, const spi_bus_config_t *b #elif SOC_GDMA_SUPPORTED SPI_CHECK(dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG); #endif - SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH | ESP_INTR_FLAG_EDGE | ESP_INTR_FLAG_INTRDISABLED)) == 0, "intr flag not allowed", ESP_ERR_INVALID_ARG); + SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH | ESP_INTR_FLAG_EDGE | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_INTRDISABLED)) == 0, "intr flag not allowed", ESP_ERR_INVALID_ARG); #ifndef CONFIG_SPI_SLAVE_ISR_IN_IRAM SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM) == 0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG); #endif diff --git a/components/esp_driver_uart/src/uart.c b/components/esp_driver_uart/src/uart.c index d8eaa6ba0b..77715f82fd 100644 --- a/components/esp_driver_uart/src/uart.c +++ b/components/esp_driver_uart/src/uart.c @@ -1989,9 +1989,15 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_LL_INTR_MASK); uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_LL_INTR_MASK); - ret = esp_intr_alloc(uart_periph_signal[uart_num].irq, intr_alloc_flags, - uart_rx_intr_handler_default, p_uart_obj[uart_num], - &p_uart_obj[uart_num]->intr_handle); + ret = esp_intr_alloc_intrstatus( + uart_periph_signal[uart_num].irq, + intr_alloc_flags, + (uint32_t)uart_hal_get_intr_status_reg(&(uart_context[uart_num].hal)), + UART_LL_INTR_MASK, + uart_rx_intr_handler_default, + p_uart_obj[uart_num], + &p_uart_obj[uart_num]->intr_handle + ); ESP_GOTO_ON_ERROR(ret, err, UART_TAG, "Could not allocate an interrupt for UART"); // Make sure uart sclk at least exist first (following code touchs hardware, and requires sclk to be enabled) diff --git a/components/hal/esp32/include/hal/ledc_ll.h b/components/hal/esp32/include/hal/ledc_ll.h index a07812452d..af038d29a2 100644 --- a/components/hal/esp32/include/hal/ledc_ll.h +++ b/components/hal/esp32/include/hal/ledc_ll.h @@ -26,6 +26,8 @@ extern "C" { #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH0_V) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0xffffUL << LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S) #define LEDC_LL_GLOBAL_CLOCKS { \ LEDC_SLOW_CLK_APB, \ @@ -524,7 +526,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode - * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -536,6 +537,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32/include/hal/sdio_slave_ll.h b/components/hal/esp32/include/hal/sdio_slave_ll.h index 0c06500b64..ccf9eb23e4 100644 --- a/components/hal/esp32/include/hal/sdio_slave_ll.h +++ b/components/hal/esp32/include/hal/sdio_slave_ll.h @@ -37,6 +37,8 @@ extern "C" { #define sdio_slave_ll_get_host(ID) (&HOST) /// Get address of the only HINF registers for ESP32 #define sdio_slave_ll_get_hinf(ID) (&HINF) +/// Get the mask of the interrupt status. +#define sdio_slave_ll_intr_status_mask (0xff | SLC_SLC0_RX_DONE_INT_ST | SLC_SLC0_RX_EOF_INT_ST | SLC_SLC0_TX_DONE_INT_ST) /* * SLC2 DMA Desc struct, aka sdio_slave_ll_desc_t @@ -544,6 +546,17 @@ static inline void sdio_slave_ll_slvint_fetch_clear(slc_dev_t *slc, sdio_slave_l slc->slc0_int_clr.val = slv_int; } +/** + * Get the address of the interrupt status register. + * + * @param slc Address of the SLC registers + * @return Address of the interrupt status register + */ +static inline volatile void* sdio_slave_ll_get_intr_status_reg(slc_dev_t *slc) +{ + return &slc->slc0_int_st.val; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32/include/hal/uart_ll.h b/components/hal/esp32/include/hal/uart_ll.h index e7592bc5c4..005e97387c 100644 --- a/components/hal/esp32/include/hal/uart_ll.h +++ b/components/hal/esp32/include/hal/uart_ll.h @@ -37,7 +37,6 @@ extern "C" { #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask - // Define UART interrupts typedef enum { UART_INTR_RXFIFO_FULL = (0x1<<0), @@ -292,6 +291,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32c2/include/hal/ledc_ll.h b/components/hal/esp32c2/include/hal/ledc_ll.h index ba5cbcda86..1b496b9b99 100644 --- a/components/hal/esp32c2/include/hal/ledc_ll.h +++ b/components/hal/esp32c2/include/hal/ledc_ll.h @@ -26,6 +26,8 @@ extern "C" { #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_CH0_V) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0x3fUL << LEDC_DUTY_CHNG_END_CH0_INT_ENA_S) #define LEDC_LL_GLOBAL_CLOCKS { \ LEDC_SLOW_CLK_PLL_DIV, \ @@ -498,7 +500,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode - * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -510,6 +511,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32c2/include/hal/uart_ll.h b/components/hal/esp32c2/include/hal/uart_ll.h index d5c709b5ee..90b084c393 100644 --- a/components/hal/esp32c2/include/hal/uart_ll.h +++ b/components/hal/esp32c2/include/hal/uart_ll.h @@ -302,6 +302,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32c3/include/hal/ledc_ll.h b/components/hal/esp32c3/include/hal/ledc_ll.h index ed6544dfde..45333a7d5b 100644 --- a/components/hal/esp32c3/include/hal/ledc_ll.h +++ b/components/hal/esp32c3/include/hal/ledc_ll.h @@ -27,6 +27,8 @@ extern "C" { #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH0_V) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0x3fUL << LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S) #define LEDC_LL_GLOBAL_CLOCKS { \ LEDC_SLOW_CLK_APB, \ @@ -499,7 +501,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode - * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -511,6 +512,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32c3/include/hal/uart_ll.h b/components/hal/esp32c3/include/hal/uart_ll.h index 06bad83cdc..54d24ed6e4 100644 --- a/components/hal/esp32c3/include/hal/uart_ll.h +++ b/components/hal/esp32c3/include/hal/uart_ll.h @@ -307,6 +307,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32c5/include/hal/ledc_ll.h b/components/hal/esp32c5/include/hal/ledc_ll.h index 3e237c6801..349556b847 100644 --- a/components/hal/esp32c5/include/hal/ledc_ll.h +++ b/components/hal/esp32c5/include/hal/ledc_ll.h @@ -30,6 +30,8 @@ extern "C" { #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0x3fUL << LEDC_DUTY_CHNG_END_CH0_INT_ENA_S) /** * @brief Enable peripheral register clock @@ -504,7 +506,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -516,6 +517,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32c5/include/hal/sdio_slave_ll.h b/components/hal/esp32c5/include/hal/sdio_slave_ll.h index c02033ecea..069bf2ee10 100644 --- a/components/hal/esp32c5/include/hal/sdio_slave_ll.h +++ b/components/hal/esp32c5/include/hal/sdio_slave_ll.h @@ -37,6 +37,8 @@ extern "C" { #define sdio_slave_ll_get_host(ID) (&HOST) /// Get address of the only HINF registers #define sdio_slave_ll_get_hinf(ID) (&HINF) +/// Get the mask of the interrupt status. +#define sdio_slave_ll_intr_status_mask (0xff | SDIO_SLC0_RX_DONE_INT_ST | SDIO_SLC0_RX_EOF_INT_ST | SDIO_SLC0_TX_DONE_INT_ST) /* * SLC2 DMA Desc struct, aka sdio_slave_ll_desc_t @@ -533,6 +535,17 @@ static inline void sdio_slave_ll_slvint_fetch_clear(slc_dev_t *slc, sdio_slave_l slc->slc_slc0int_clr.val = slv_int; } +/** + * Get the address of the interrupt status register. + * + * @param slc Address of the SLC registers + * @return Address of the interrupt status register + */ +static inline volatile void* sdio_slave_ll_get_intr_status_reg(slc_dev_t *slc) +{ + return &slc->slc_slc0int_st.val; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c5/include/hal/uart_ll.h b/components/hal/esp32c5/include/hal/uart_ll.h index 22d5b0eb5d..77408fc748 100644 --- a/components/hal/esp32c5/include/hal/uart_ll.h +++ b/components/hal/esp32c5/include/hal/uart_ll.h @@ -526,6 +526,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32c6/include/hal/ledc_ll.h b/components/hal/esp32c6/include/hal/ledc_ll.h index e6a0c73e3f..0e36bdc9ae 100644 --- a/components/hal/esp32c6/include/hal/ledc_ll.h +++ b/components/hal/esp32c6/include/hal/ledc_ll.h @@ -31,6 +31,8 @@ extern "C" { #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0x3fUL << LEDC_DUTY_CHNG_END_CH0_INT_ENA_S) #define LEDC_LL_GLOBAL_CLK_DEFAULT LEDC_SLOW_CLK_RC_FAST @@ -625,7 +627,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -637,6 +638,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32c6/include/hal/sdio_slave_ll.h b/components/hal/esp32c6/include/hal/sdio_slave_ll.h index 24b592893a..1276518a89 100644 --- a/components/hal/esp32c6/include/hal/sdio_slave_ll.h +++ b/components/hal/esp32c6/include/hal/sdio_slave_ll.h @@ -37,6 +37,8 @@ extern "C" { #define sdio_slave_ll_get_host(ID) (&HOST) /// Get address of the only HINF registers #define sdio_slave_ll_get_hinf(ID) (&HINF) +/// Get the mask of the interrupt status. +#define sdio_slave_ll_intr_status_mask (0xff | SDIO_SLC0_RX_DONE_INT_ST | SDIO_SLC0_RX_EOF_INT_ST | SDIO_SLC0_TX_DONE_INT_ST) /* * SLC2 DMA Desc struct, aka sdio_slave_ll_desc_t @@ -533,6 +535,17 @@ static inline void sdio_slave_ll_slvint_fetch_clear(slc_dev_t *slc, sdio_slave_l slc->slc0int_clr.val = slv_int; } +/** + * Get the address of the interrupt status register. + * + * @param slc Address of the SLC registers + * @return Address of the interrupt status register + */ +static inline volatile void* sdio_slave_ll_get_intr_status_reg(slc_dev_t *slc) +{ + return &slc->slc0int_st.val; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/spi_ll.h b/components/hal/esp32c6/include/hal/spi_ll.h index c52ec2f26c..c55b9e2283 100644 --- a/components/hal/esp32c6/include/hal/spi_ll.h +++ b/components/hal/esp32c6/include/hal/spi_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/hal/esp32c6/include/hal/uart_ll.h b/components/hal/esp32c6/include/hal/uart_ll.h index c4c62999e2..60d353e416 100644 --- a/components/hal/esp32c6/include/hal/uart_ll.h +++ b/components/hal/esp32c6/include/hal/uart_ll.h @@ -507,6 +507,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32c61/include/hal/ledc_ll.h b/components/hal/esp32c61/include/hal/ledc_ll.h index 4cd0f760ae..0d49cda7ae 100644 --- a/components/hal/esp32c61/include/hal/ledc_ll.h +++ b/components/hal/esp32c61/include/hal/ledc_ll.h @@ -30,6 +30,8 @@ extern "C" { #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0x3fUL << LEDC_DUTY_CHNG_END_CH0_INT_ENA_S) /** * @brief Enable peripheral register clock @@ -504,7 +506,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -516,6 +517,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32c61/include/hal/sdio_slave_ll.h b/components/hal/esp32c61/include/hal/sdio_slave_ll.h index fb746c8b4f..f11023260b 100644 --- a/components/hal/esp32c61/include/hal/sdio_slave_ll.h +++ b/components/hal/esp32c61/include/hal/sdio_slave_ll.h @@ -37,6 +37,9 @@ extern "C" { #define sdio_slave_ll_get_host(ID) (&HOST) /// Get address of the only HINF registers #define sdio_slave_ll_get_hinf(ID) (&HINF) +/// Get the mask of the interrupt status. +#define sdio_slave_ll_intr_status_mask (0xff | SDIO_SLC0_RX_DONE_INT_ST | SDIO_SLC0_RX_EOF_INT_ST | SDIO_SLC0_TX_DONE_INT_ST) + /* * SLC2 DMA Desc struct, aka sdio_slave_ll_desc_t @@ -533,6 +536,17 @@ static inline void sdio_slave_ll_slvint_fetch_clear(slc_dev_t *slc, sdio_slave_l slc->slc_slc0int_clr.val = slv_int; } +/** + * Get the address of the interrupt status register. + * + * @param slc Address of the SLC registers + * @return Address of the interrupt status register + */ +static inline volatile void* sdio_slave_ll_get_intr_status_reg(slc_dev_t *slc) +{ + return &slc->slc_slc0int_st.val; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c61/include/hal/uart_ll.h b/components/hal/esp32c61/include/hal/uart_ll.h index 4ca98ecc91..e8b426abb3 100644 --- a/components/hal/esp32c61/include/hal/uart_ll.h +++ b/components/hal/esp32c61/include/hal/uart_ll.h @@ -354,6 +354,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32h2/include/hal/ledc_ll.h b/components/hal/esp32h2/include/hal/ledc_ll.h index 8351003001..76c95fe97b 100644 --- a/components/hal/esp32h2/include/hal/ledc_ll.h +++ b/components/hal/esp32h2/include/hal/ledc_ll.h @@ -31,6 +31,8 @@ extern "C" { #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0x3fUL << LEDC_DUTY_CHNG_END_CH0_INT_ENA_S) /** * @brief Enable peripheral register clock @@ -623,7 +625,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -635,6 +636,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32h2/include/hal/spi_ll.h b/components/hal/esp32h2/include/hal/spi_ll.h index fade1a565e..ec5219583e 100644 --- a/components/hal/esp32h2/include/hal/spi_ll.h +++ b/components/hal/esp32h2/include/hal/spi_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/hal/esp32h2/include/hal/uart_ll.h b/components/hal/esp32h2/include/hal/uart_ll.h index 2b9cb2479b..f507999fd0 100644 --- a/components/hal/esp32h2/include/hal/uart_ll.h +++ b/components/hal/esp32h2/include/hal/uart_ll.h @@ -333,6 +333,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32h21/include/hal/uart_ll.h b/components/hal/esp32h21/include/hal/uart_ll.h index 24df5176b7..89cd5293c3 100644 --- a/components/hal/esp32h21/include/hal/uart_ll.h +++ b/components/hal/esp32h21/include/hal/uart_ll.h @@ -332,6 +332,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32h4/include/hal/uart_ll.h b/components/hal/esp32h4/include/hal/uart_ll.h index e4f68c70bb..e2ba4e3f67 100644 --- a/components/hal/esp32h4/include/hal/uart_ll.h +++ b/components/hal/esp32h4/include/hal/uart_ll.h @@ -351,6 +351,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32p4/include/hal/ledc_ll.h b/components/hal/esp32p4/include/hal/ledc_ll.h index 0876a928f0..8c2380af61 100644 --- a/components/hal/esp32p4/include/hal/ledc_ll.h +++ b/components/hal/esp32p4/include/hal/ledc_ll.h @@ -30,6 +30,8 @@ extern "C" { #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) #define LEDC_LL_GLOBAL_CLOCKS SOC_LEDC_CLKS +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0xffUL << LEDC_DUTY_CHNG_END_CH0_INT_ENA_S) /** * @brief Enable peripheral register clock @@ -517,7 +519,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, low-speed mode only - * @param channel_num LEDC channel index (0-5), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -529,6 +530,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32p4/include/hal/uart_ll.h b/components/hal/esp32p4/include/hal/uart_ll.h index ec2a776fee..ca6529303c 100644 --- a/components/hal/esp32p4/include/hal/uart_ll.h +++ b/components/hal/esp32p4/include/hal/uart_ll.h @@ -628,6 +628,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32s2/include/hal/cache_ll.h b/components/hal/esp32s2/include/hal/cache_ll.h index 0bccb5d3d4..6f64818145 100644 --- a/components/hal/esp32s2/include/hal/cache_ll.h +++ b/components/hal/esp32s2/include/hal/cache_ll.h @@ -282,7 +282,8 @@ static inline void cache_ll_resume_cache(uint32_t cache_level, cache_type_t type * @return true: enabled; false: disabled */ __attribute__((always_inline)) -static inline bool cache_ll_l1_is_icache_enabled(uint32_t cache_id){ +static inline bool cache_ll_l1_is_icache_enabled(uint32_t cache_id) +{ HAL_ASSERT(cache_id <= CACHE_LL_ID_ALL); bool enabled; diff --git a/components/hal/esp32s2/include/hal/ledc_ll.h b/components/hal/esp32s2/include/hal/ledc_ll.h index 5ddcb5ab87..c9d947090a 100644 --- a/components/hal/esp32s2/include/hal/ledc_ll.h +++ b/components/hal/esp32s2/include/hal/ledc_ll.h @@ -27,6 +27,8 @@ extern "C" { #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH0_V) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0xffUL << LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S) #define LEDC_LL_GLOBAL_CLOCKS { \ LEDC_SLOW_CLK_APB, \ @@ -538,7 +540,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode - * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -550,6 +551,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32s2/include/hal/uart_ll.h b/components/hal/esp32s2/include/hal/uart_ll.h index 963706c2a7..3bfc9d6a58 100644 --- a/components/hal/esp32s2/include/hal/uart_ll.h +++ b/components/hal/esp32s2/include/hal/uart_ll.h @@ -280,6 +280,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) return hw->int_st.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Clear the UART interrupt status based on the given mask. * diff --git a/components/hal/esp32s3/include/hal/ledc_ll.h b/components/hal/esp32s3/include/hal/ledc_ll.h index 8557ad3645..3c7706b46c 100644 --- a/components/hal/esp32s3/include/hal/ledc_ll.h +++ b/components/hal/esp32s3/include/hal/ledc_ll.h @@ -27,6 +27,8 @@ extern "C" { #define LEDC_LL_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH0_V) #define LEDC_LL_FRACTIONAL_BITS (8) #define LEDC_LL_FRACTIONAL_MAX ((1 << LEDC_LL_FRACTIONAL_BITS) - 1) +/// Get the mask of the fade end interrupt status register. +#define LEDC_LL_FADE_END_INTR_MASK (0xffUL << LEDC_DUTY_CHNG_END_LSCH0_INT_ENA_S) #define LEDC_LL_GLOBAL_CLOCKS { \ LEDC_SLOW_CLK_APB, \ @@ -499,7 +501,6 @@ static inline void ledc_ll_set_fade_end_intr(ledc_dev_t *hw, ledc_mode_t speed_m * * @param hw Beginning address of the peripheral registers * @param speed_mode LEDC speed_mode, high-speed mode or low-speed mode - * @param channel_num LEDC channel index (0-7), select from ledc_channel_t * @param intr_status The fade end interrupt status * * @return None @@ -511,6 +512,18 @@ static inline void ledc_ll_get_fade_end_intr_status(ledc_dev_t *hw, ledc_mode_t *intr_status = (value >> int_en_base) & 0xff; } +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hw Beginning address of the peripheral registers + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_ll_get_fade_end_intr_addr(ledc_dev_t *hw) +{ + return &hw->int_st.val; +} + + /** * @brief Clear fade end interrupt status * diff --git a/components/hal/esp32s3/include/hal/uart_ll.h b/components/hal/esp32s3/include/hal/uart_ll.h index 816e8103fe..0ab5c961f5 100644 --- a/components/hal/esp32s3/include/hal/uart_ll.h +++ b/components/hal/esp32s3/include/hal/uart_ll.h @@ -337,6 +337,11 @@ FORCE_INLINE_ATTR uint32_t uart_ll_get_intr_ena_status(uart_dev_t *hw) return hw->int_ena.val; } +FORCE_INLINE_ATTR volatile void* uart_ll_get_intr_status_reg(uart_dev_t *hw) +{ + return &hw->int_st.val; +} + /** * @brief Read the UART rxfifo. * diff --git a/components/hal/include/hal/ledc_hal.h b/components/hal/include/hal/ledc_hal.h index 18ac920a2d..04d9ba0f9f 100644 --- a/components/hal/include/hal/ledc_hal.h +++ b/components/hal/include/hal/ledc_hal.h @@ -396,6 +396,14 @@ void ledc_hal_get_fade_end_intr_status(ledc_hal_context_t *hal, uint32_t *intr_s */ void ledc_hal_clear_fade_end_intr_status(ledc_hal_context_t *hal, ledc_channel_t channel_num); +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hal Context of the HAL layer + * @return Pointer to the fade end interrupt status register. + */ +volatile void* ledc_hal_get_fade_end_intr_addr(ledc_hal_context_t *hal); + /** * @brief Get clock config of LEDC timer * diff --git a/components/hal/include/hal/sdio_slave_hal.h b/components/hal/include/hal/sdio_slave_hal.h index bfdbe9e9be..94588c26af 100644 --- a/components/hal/include/hal/sdio_slave_hal.h +++ b/components/hal/include/hal/sdio_slave_hal.h @@ -532,6 +532,14 @@ uint8_t sdio_slave_hal_host_get_reg(sdio_slave_context_t *hal, int pos); */ void sdio_slave_hal_host_set_reg(sdio_slave_context_t *hal, int pos, uint8_t reg); +/** + * Get the address of the interrupt status register. + * + * @param hal Context of the HAL layer. + * @return Address of the interrupt status register + */ +volatile void* sdio_slave_hal_get_intr_status_reg(sdio_slave_context_t *hal); + #endif // SOC_SDIO_SLAVE_SUPPORTED #ifdef __cplusplus diff --git a/components/hal/include/hal/spi_hal.h b/components/hal/include/hal/spi_hal.h index 1b7a80dbf5..c9d2e136e8 100644 --- a/components/hal/include/hal/spi_hal.h +++ b/components/hal/include/hal/spi_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/hal/include/hal/spi_slave_hal.h b/components/hal/include/hal/spi_slave_hal.h index dc20208508..563e2a704c 100644 --- a/components/hal/include/hal/spi_slave_hal.h +++ b/components/hal/include/hal/spi_slave_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/hal/include/hal/uart_hal.h b/components/hal/include/hal/uart_hal.h index 4c8497cd97..868b17846b 100644 --- a/components/hal/include/hal/uart_hal.h +++ b/components/hal/include/hal/uart_hal.h @@ -106,6 +106,16 @@ typedef struct { */ #define uart_hal_get_intr_ena_status(hal) uart_ll_get_intr_ena_status((hal)->dev) +/** + * @brief Get the pointer to the UART interrupt status register + * + * @param hal Context of the HAL layer + * + * @return UART interrupt status register + */ +#define uart_hal_get_intr_status_reg(hal) uart_ll_get_intr_status_reg((hal)->dev) + + /** * @brief Get the UART pattern char configuration * diff --git a/components/hal/ledc_hal_iram.c b/components/hal/ledc_hal_iram.c index 34884c78e7..3a6279982c 100644 --- a/components/hal/ledc_hal_iram.c +++ b/components/hal/ledc_hal_iram.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -75,3 +75,8 @@ void ledc_hal_clear_fade_end_intr_status(ledc_hal_context_t *hal, ledc_channel_t { ledc_ll_clear_fade_end_intr_status(hal->dev, hal->speed_mode, channel_num); } + +volatile void* ledc_hal_get_fade_end_intr_addr(ledc_hal_context_t *hal) +{ + return ledc_ll_get_fade_end_intr_addr(hal->dev); +} diff --git a/components/hal/sdio_slave_hal.c b/components/hal/sdio_slave_hal.c index 1c48fe18d9..798efc2c2a 100644 --- a/components/hal/sdio_slave_hal.c +++ b/components/hal/sdio_slave_hal.c @@ -721,3 +721,8 @@ void sdio_slave_hal_slvint_fetch_clear(sdio_slave_context_t *hal, sdio_slave_ll_ { sdio_slave_ll_slvint_fetch_clear(hal->slc, out_int_mask); } + +volatile void* sdio_slave_hal_get_intr_status_reg(sdio_slave_context_t *hal) +{ + return sdio_slave_ll_get_intr_status_reg(hal->slc); +} diff --git a/components/hal/spi_hal.c b/components/hal/spi_hal.c index c1865ab3af..1e65366369 100644 --- a/components/hal/spi_hal.c +++ b/components/hal/spi_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ From b3d80b2e5d4a9e19f335366aa777189aba92d4ae Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Wed, 19 Nov 2025 11:59:51 +0800 Subject: [PATCH 069/156] fix(ledc): fix potential null dereference issue & add test case --- components/esp_driver_ledc/src/ledc.c | 11 +++++- .../test_apps/ledc/main/test_ledc.c | 39 +++++++++++++++++++ components/hal/include/hal/ledc_hal.h | 19 +++++---- components/hal/ledc_hal_iram.c | 5 --- 4 files changed, 60 insertions(+), 14 deletions(-) diff --git a/components/esp_driver_ledc/src/ledc.c b/components/esp_driver_ledc/src/ledc.c index 2143982537..b10830b915 100644 --- a/components/esp_driver_ledc/src/ledc.c +++ b/components/esp_driver_ledc/src/ledc.c @@ -1535,11 +1535,20 @@ exit: esp_err_t ledc_fade_func_install(int intr_alloc_flags) { LEDC_CHECK(s_ledc_fade_isr_handle == NULL, "fade function already installed", ESP_ERR_INVALID_STATE); + + ledc_mode_t speed_mode = LEDC_SPEED_MODE_MAX; + for (int i = 0; i < LEDC_SPEED_MODE_MAX; i++) { + if (p_ledc_obj[i] != NULL) { + speed_mode = i; + break; + } + } + //OR intr_alloc_flags with ESP_INTR_FLAG_IRAM because the fade isr is in IRAM return esp_intr_alloc_intrstatus( ETS_LEDC_INTR_SOURCE, intr_alloc_flags | ESP_INTR_FLAG_IRAM, - (uint32_t)ledc_hal_get_fade_end_intr_addr(&(p_ledc_obj[0]->ledc_hal)), + (uint32_t)ledc_hal_get_fade_end_intr_addr(&(p_ledc_obj[speed_mode]->ledc_hal)), LEDC_LL_FADE_END_INTR_MASK, ledc_fade_isr, NULL, diff --git a/components/esp_driver_ledc/test_apps/ledc/main/test_ledc.c b/components/esp_driver_ledc/test_apps/ledc/main/test_ledc.c index ebbbc982f3..5c5952be24 100644 --- a/components/esp_driver_ledc/test_apps/ledc/main/test_ledc.c +++ b/components/esp_driver_ledc/test_apps/ledc/main/test_ledc.c @@ -258,6 +258,45 @@ TEST_CASE("LEDC fade with step", "[ledc]") ledc_fade_func_uninstall(); } +#if SOC_LEDC_SUPPORT_HS_MODE +TEST_CASE("LEDC fade install with low speed mode only", "[ledc]") +{ + // This test verifies that ledc_fade_func_install works correctly when only + // LEDC_LOW_SPEED_MODE is initialized, without initializing LEDC_HIGH_SPEED_MODE. + // This tests the fix for NULL pointer dereference issue. + + // Only initialize low speed mode, do NOT initialize high speed mode + ledc_channel_config_t ledc_ch_config = initialize_channel_config(); + ledc_ch_config.speed_mode = LEDC_LOW_SPEED_MODE; + ledc_ch_config.duty = 0; + ledc_ch_config.channel = LEDC_CHANNEL_0; + ledc_ch_config.timer_sel = LEDC_TIMER_0; + + ledc_timer_config_t ledc_time_config = create_default_timer_config(); + ledc_time_config.speed_mode = LEDC_LOW_SPEED_MODE; + ledc_time_config.timer_num = LEDC_TIMER_0; + + // Initialize only low speed mode + TEST_ESP_OK(ledc_channel_config(&ledc_ch_config)); + TEST_ESP_OK(ledc_timer_config(&ledc_time_config)); + vTaskDelay(5 / portTICK_PERIOD_MS); + TEST_ESP_OK(ledc_fade_func_install(0)); + + // Verify that fade functionality works correctly with low speed mode + TEST_ESP_OK(ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 4000, 200)); + TEST_ESP_OK(ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, LEDC_FADE_WAIT_DONE)); + TEST_ASSERT_EQUAL_INT32(4000, ledc_get_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0)); + + // Test fade down + TEST_ESP_OK(ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0, 200)); + TEST_ESP_OK(ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, LEDC_FADE_WAIT_DONE)); + TEST_ASSERT_EQUAL_INT32(0, ledc_get_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0)); + + // Cleanup + ledc_fade_func_uninstall(); +} +#endif // SOC_LEDC_SUPPORT_HS_MODE + TEST_CASE("LEDC fast switching duty with fade_wait_done", "[ledc]") { const ledc_mode_t test_speed_mode = TEST_SPEED_MODE; diff --git a/components/hal/include/hal/ledc_hal.h b/components/hal/include/hal/ledc_hal.h index 04d9ba0f9f..c8cafc8449 100644 --- a/components/hal/include/hal/ledc_hal.h +++ b/components/hal/include/hal/ledc_hal.h @@ -396,14 +396,6 @@ void ledc_hal_get_fade_end_intr_status(ledc_hal_context_t *hal, uint32_t *intr_s */ void ledc_hal_clear_fade_end_intr_status(ledc_hal_context_t *hal, ledc_channel_t channel_num); -/** - * @brief Get the address of the fade end interrupt status register. - * - * @param hal Context of the HAL layer - * @return Pointer to the fade end interrupt status register. - */ -volatile void* ledc_hal_get_fade_end_intr_addr(ledc_hal_context_t *hal); - /** * @brief Get clock config of LEDC timer * @@ -415,6 +407,17 @@ volatile void* ledc_hal_get_fade_end_intr_addr(ledc_hal_context_t *hal); */ void ledc_hal_get_clk_cfg(ledc_hal_context_t *hal, ledc_timer_t timer_sel, ledc_clk_cfg_t *clk_cfg); +/** + * @brief Get the address of the fade end interrupt status register. + * + * @param hal Context of the HAL layer + * @return Pointer to the fade end interrupt status register. + */ +static inline volatile void* ledc_hal_get_fade_end_intr_addr(ledc_hal_context_t *hal) +{ + return ledc_ll_get_fade_end_intr_addr(hal->dev); +} + #endif //#if SOC_LEDC_SUPPORTED #ifdef __cplusplus diff --git a/components/hal/ledc_hal_iram.c b/components/hal/ledc_hal_iram.c index 3a6279982c..804473132c 100644 --- a/components/hal/ledc_hal_iram.c +++ b/components/hal/ledc_hal_iram.c @@ -75,8 +75,3 @@ void ledc_hal_clear_fade_end_intr_status(ledc_hal_context_t *hal, ledc_channel_t { ledc_ll_clear_fade_end_intr_status(hal->dev, hal->speed_mode, channel_num); } - -volatile void* ledc_hal_get_fade_end_intr_addr(ledc_hal_context_t *hal) -{ - return ledc_ll_get_fade_end_intr_addr(hal->dev); -} From b70e8ae90374a59d427de37844ee9979c8e2f98d Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 15 Dec 2025 19:29:20 +0800 Subject: [PATCH 070/156] fix(bt/bluedroid): fixed possible access to NULL in l2c_fcr_clone_buf --- components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c b/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c index 1da2459d6e..4d3c262013 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c @@ -352,6 +352,10 @@ BT_HDR *l2c_fcr_clone_buf (BT_HDR *p_buf, UINT16 new_offset, UINT16 no_of_bytes) buf_size += sizeof(uint32_t); #endif BT_HDR *p_buf2 = (BT_HDR *)osi_malloc(buf_size); + if (!p_buf2) { + L2CAP_TRACE_ERROR ("l2c_fcr_clone_buf() malloc failed"); + return NULL; + } p_buf2->offset = new_offset; p_buf2->len = no_of_bytes; @@ -989,7 +993,7 @@ static void process_s_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word) #endif if (ctrl_word & L2CAP_FCR_P_BIT) { - p_fcrb->rej_sent = FALSE; /* After checkpoint, we can send anoher REJ */ + p_fcrb->rej_sent = FALSE; /* After checkpoint, we can send another REJ */ p_fcrb->send_f_rsp = TRUE; /* Set a flag in case an I-frame is pending */ } @@ -1160,7 +1164,7 @@ static void process_i_frame (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_word, B return; } - /* Seq number is the next expected. Clear possible reject exception in case it occured */ + /* Seq number is the next expected. Clear possible reject exception in case it occurred */ p_fcrb->rej_sent = p_fcrb->srej_sent = FALSE; /* Adjust the next_seq, so that if the upper layer sends more data in the callback @@ -1839,7 +1843,7 @@ void l2c_fcr_adj_monitor_retran_timeout (tL2C_CCB *p_ccb) /* adjust our monitor/retran timeout */ if (p_ccb->out_cfg_fcr_present) { /* - ** if we requestd ERTM or accepted ERTM + ** if we requested ERTM or accepted ERTM ** We may accept ERTM even if we didn't request ERTM, in case of requesting STREAM */ if ((p_ccb->our_cfg.fcr.mode == L2CAP_FCR_ERTM_MODE) @@ -1860,7 +1864,7 @@ void l2c_fcr_adj_monitor_retran_timeout (tL2C_CCB *p_ccb) ** ** Function l2c_fcr_adj_our_rsp_options ** -** Description Overrides any neccesary FCR options passed in from +** Description Overrides any necessary FCR options passed in from ** L2CA_ConfigRsp based on our FCR options. ** Only makes adjustments if channel is in ERTM mode. ** @@ -1937,7 +1941,7 @@ BOOLEAN l2c_fcr_renegotiate_chan(tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) /* Try another supported mode if available based on our last attempted channel */ switch (p_ccb->our_cfg.fcr.mode) { - /* Our Streaming mode request was unnacceptable; try ERTM or Basic */ + /* Our Streaming mode request was unacceptable; try ERTM or Basic */ case L2CAP_FCR_STREAM_MODE: /* Peer wants ERTM and we support it */ if ( (peer_mode == L2CAP_FCR_ERTM_MODE) && (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM) ) { From 80c1fc8676b4761dea58835d955245e79c2634e8 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Mon, 15 Dec 2025 15:42:02 +0800 Subject: [PATCH 071/156] fix(jpeg): Fix check in com marker --- components/esp_driver_jpeg/jpeg_parse_marker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_driver_jpeg/jpeg_parse_marker.c b/components/esp_driver_jpeg/jpeg_parse_marker.c index e26bdf218a..5dd410fe21 100644 --- a/components/esp_driver_jpeg/jpeg_parse_marker.c +++ b/components/esp_driver_jpeg/jpeg_parse_marker.c @@ -60,7 +60,7 @@ esp_err_t jpeg_parse_com_marker(jpeg_dec_header_info_t *header_info) uint16_t skip_num = jpeg_get_bytes(header_info, 2); ESP_RETURN_ON_FALSE(skip_num >= 2, ESP_ERR_INVALID_ARG, TAG, "Invalid COM marker length: %"PRIu32, skip_num); uint32_t bytes_to_skip = skip_num - 2; - ESP_RETURN_ON_FALSE(header_info->header_size >= bytes_to_skip, ESP_ERR_INVALID_ARG, TAG, "COM marker data underflow for header_size: %"PRIu32, header_info->header_size); + ESP_RETURN_ON_FALSE(header_info->buffer_left >= bytes_to_skip, ESP_ERR_INVALID_ARG, TAG, "COM marker data underflow for header_size: %"PRIu32, header_info->buffer_left); header_info->buffer_offset += bytes_to_skip; header_info->header_size += bytes_to_skip; header_info->buffer_left -= bytes_to_skip; From 38a0beb65900b3f23079bd7da7fce8857e05277d Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Mon, 15 Dec 2025 17:38:52 +0800 Subject: [PATCH 072/156] feat(jpeg_decoder): Add decode to yuv420 since esp32p4 version3 --- components/esp_driver_jpeg/jpeg_decode.c | 24 ++++++++++++++++++++++- components/esp_driver_jpeg/jpeg_param.c | 10 +++++----- components/esp_driver_jpeg/jpeg_private.h | 1 + 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/components/esp_driver_jpeg/jpeg_decode.c b/components/esp_driver_jpeg/jpeg_decode.c index c0121b1876..718e5cffd7 100644 --- a/components/esp_driver_jpeg/jpeg_decode.c +++ b/components/esp_driver_jpeg/jpeg_decode.c @@ -382,6 +382,11 @@ static esp_err_t jpeg_dec_config_dma_descriptor(jpeg_decoder_handle_t decoder_en case JPEG_DECODE_OUT_FORMAT_YUV444: best_hb_idx = JPEG_DEC_YUV444_HB; break; +#if !(CONFIG_ESP_REV_MIN_FULL < 300 && CONFIG_IDF_TARGET_ESP32P4) // Invisible for unsupported chips + case JPEG_DECODE_OUT_FORMAT_YUV420: + best_hb_idx = JPEG_DEC_YUV420_HB; + break; +#endif default: ESP_LOGE(TAG, "wrong, we don't support decode to such format."); return ESP_ERR_NOT_SUPPORTED; @@ -468,7 +473,17 @@ static void jpeg_dec_config_dma_csc(jpeg_decoder_handle_t decoder_engine, dma2d_ } else if (decoder_engine->sample_method == JPEG_DOWN_SAMPLING_YUV420) { rx_csc_option = DMA2D_CSC_RX_YUV420_TO_YUV444; } - } else { + } +#if !(CONFIG_ESP_REV_MIN_FULL < 300 && CONFIG_IDF_TARGET_ESP32P4) // Invisible for unsupported chips + else if (decoder_engine->output_format == JPEG_DECODE_OUT_FORMAT_YUV420) { + if (decoder_engine->sample_method == JPEG_DOWN_SAMPLING_YUV422) { + rx_csc_option = DMA2D_CSC_RX_YUV422_TO_YUV420; + } else if (decoder_engine->sample_method == JPEG_DOWN_SAMPLING_YUV444) { + rx_csc_option = DMA2D_CSC_RX_YUV444_TO_YUV420; + } + } +#endif + else { rx_csc_option = DMA2D_CSC_RX_NONE; } @@ -565,6 +580,7 @@ static bool jpeg_dec_transaction_on_picked(uint32_t channel_num, const dma2d_tra static esp_err_t jpeg_color_space_support_check(jpeg_decoder_handle_t decoder_engine) { +#if !(CONFIG_ESP_REV_MIN_FULL < 300 && CONFIG_IDF_TARGET_ESP32P4) // Invisible for unsupported chips if (decoder_engine->sample_method == JPEG_DOWN_SAMPLING_YUV444) { if (decoder_engine->output_format == JPEG_DECODE_OUT_FORMAT_YUV422 || decoder_engine->output_format == JPEG_DECODE_OUT_FORMAT_YUV420) { ESP_LOGE(TAG, "Detected YUV444 but want to convert to YUV422/YUV420, which is not supported"); @@ -581,6 +597,12 @@ static esp_err_t jpeg_color_space_support_check(jpeg_decoder_handle_t decoder_en return ESP_ERR_INVALID_ARG; } } +#else + if (decoder_engine->sample_method != JPEG_DOWN_SAMPLING_YUV422) { + ESP_LOGE(TAG, "Detected YUV444/YUV420 but want to convert to YUV422, which is not supported"); + return ESP_ERR_INVALID_ARG; + } +#endif return ESP_OK; } diff --git a/components/esp_driver_jpeg/jpeg_param.c b/components/esp_driver_jpeg/jpeg_param.c index 380c2c614e..9d05a3202f 100644 --- a/components/esp_driver_jpeg/jpeg_param.c +++ b/components/esp_driver_jpeg/jpeg_param.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -40,10 +40,10 @@ const uint8_t zigzag_arr[64] = { * data stream during the decoding process. */ const uint32_t dec_hb_tbl[JPEG_DOWN_SAMPLING_NUM][JPEG_DEC_BEST_HB_MAX] = { - {40, 40, 40, 32, 0}, - {64, 32, 32, 64, 0}, - {48, 32, 32, 48, 0}, - {96, 0, 0, 0, 96}, + {40, 40, 40, 32, 0, 32}, + {64, 32, 32, 64, 0, 32}, + {48, 32, 32, 48, 0, 48}, + {96, 0, 0, 0, 96, 0}, }; /** diff --git a/components/esp_driver_jpeg/jpeg_private.h b/components/esp_driver_jpeg/jpeg_private.h index 56345cfd05..def879b887 100644 --- a/components/esp_driver_jpeg/jpeg_private.h +++ b/components/esp_driver_jpeg/jpeg_private.h @@ -61,6 +61,7 @@ typedef enum { JPEG_DEC_RGB888_HB = 2, /*!< output RGB888 format */ JPEG_DEC_RGB565_HB = 3, /*!< output RGB565 format */ JPEG_DEC_GRAY_HB = 4, /*!< output the gray picture */ + JPEG_DEC_YUV420_HB = 5, /*!< output YUV420 format */ JPEG_DEC_BEST_HB_MAX, /*!< Max value of output formats */ } jpeg_dec_format_hb_t; From 0540c85140c2c06c0cbecc8843277ea676d5c4a9 Mon Sep 17 00:00:00 2001 From: Rahul Tank Date: Tue, 2 Dec 2025 15:37:01 +0530 Subject: [PATCH 073/156] fix(protocomm): Add security checks for buffer overflow and incorrect length handling --- .../protocomm/src/transports/protocomm_ble.c | 106 ++++++++++++++++-- .../src/transports/protocomm_nimble.c | 63 +++++++++-- 2 files changed, 147 insertions(+), 22 deletions(-) diff --git a/components/protocomm/src/transports/protocomm_ble.c b/components/protocomm/src/transports/protocomm_ble.c index 740775acec..87ef813ae1 100644 --- a/components/protocomm/src/transports/protocomm_ble.c +++ b/components/protocomm/src/transports/protocomm_ble.c @@ -1,10 +1,11 @@ /* - * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include #include #include @@ -71,6 +72,21 @@ typedef struct _protocomm_ble { static _protocomm_ble_internal_t *protoble_internal; +static bool protocomm_ble_transport_active(void) +{ + return (protoble_internal != NULL) && (protoble_internal->pc_ble != NULL); +} + +static void protocomm_ble_reset_prepare_write(void) +{ + if (prepare_write_env.prepare_buf) { + free(prepare_write_env.prepare_buf); + prepare_write_env.prepare_buf = NULL; + } + prepare_write_env.prepare_len = 0; + prepare_write_env.handle = 0; +} + // config adv data static esp_ble_adv_data_t adv_config = { .set_scan_rsp = false, @@ -121,6 +137,9 @@ static const uint16_t *uuid128_to_16(const uint8_t *uuid128) static const char *handle_to_handler(uint16_t handle) { + if (protoble_internal == NULL) { + return NULL; + } const uint8_t *uuid128 = simple_ble_get_uuid128(handle); if (!uuid128) { return NULL; @@ -140,6 +159,18 @@ static void transport_simple_ble_read(esp_gatts_cb_event_t event, esp_gatt_if_t static uint16_t max_read_len = 0; esp_gatt_status_t status = ESP_OK; + if (!protocomm_ble_transport_active()) { + read_len = 0; + max_read_len = 0; + read_buf = NULL; + esp_err_t err = esp_ble_gatts_send_response(gatts_if, param->read.conn_id, + param->read.trans_id, ESP_GATT_ERROR, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Send response error in read"); + } + return; + } + ESP_LOGD(TAG, "Inside read w/ session - %d on param %d %d", param->read.conn_id, param->read.handle, read_len); if (!read_len && !param->read.offset) { @@ -206,7 +237,8 @@ static esp_err_t prepare_write_event_env(esp_gatt_if_t gatts_if, memcpy(prepare_write_env.prepare_buf + param->write.offset, param->write.value, param->write.len); - prepare_write_env.prepare_len += param->write.len; + int next_len = param->write.offset + param->write.len; + prepare_write_env.prepare_len = MAX(prepare_write_env.prepare_len, next_len); prepare_write_env.handle = param->write.handle; } @@ -254,6 +286,17 @@ static void transport_simple_ble_write(esp_gatts_cb_event_t event, esp_gatt_if_t ESP_LOGD(TAG, "Inside write with session - %d on attr handle = %d \nlen = %d, is_prep = %d", param->write.conn_id, param->write.handle, param->write.len, param->write.is_prep); + if (!protocomm_ble_transport_active()) { + ESP_LOGW(TAG, "Ignoring write on inactive protocomm transport"); + protocomm_ble_reset_prepare_write(); + if (param->write.need_rsp) { + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, + param->write.trans_id, ESP_GATT_ERROR, NULL); + } + esp_ble_gatts_close(gatts_if, param->write.conn_id); + return; + } + if (param->write.is_prep) { ret = prepare_write_event_env(gatts_if, param); if (ret != ESP_OK) { @@ -298,6 +341,15 @@ static void transport_simple_ble_exec_write(esp_gatts_cb_event_t event, esp_gatt ssize_t outlen = 0; ESP_LOGD(TAG, "Inside exec_write w/ session - %d", param->exec_write.conn_id); + if (!protocomm_ble_transport_active()) { + ESP_LOGW(TAG, "Ignoring exec write on inactive protocomm transport"); + protocomm_ble_reset_prepare_write(); + esp_ble_gatts_send_response(gatts_if, param->exec_write.conn_id, + param->exec_write.trans_id, ESP_GATT_ERROR, NULL); + esp_ble_gatts_close(gatts_if, param->exec_write.conn_id); + return; + } + if ((param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) && prepare_write_env.prepare_buf) { @@ -336,12 +388,20 @@ static void transport_simple_ble_disconnect(esp_gatts_cb_event_t event, esp_gatt esp_err_t ret; ESP_LOGD(TAG, "Inside disconnect w/ session - %d", param->disconnect.conn_id); + /* Drop any staged prepare-write data when a connection ends */ + protocomm_ble_reset_prepare_write(); + /* Ignore BLE events received after protocomm layer is stopped */ if (protoble_internal == NULL) { ESP_LOGI(TAG,"Protocomm layer has already stopped"); return; } + if (!protocomm_ble_transport_active()) { + ESP_LOGD(TAG, "Protocomm BLE inactive, ignoring disconnect"); + return; + } + if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->close_transport_session) { ret = protoble_internal->pc_ble->sec->close_transport_session(protoble_internal->pc_ble->sec_inst, @@ -368,12 +428,20 @@ static void transport_simple_ble_connect(esp_gatts_cb_event_t event, esp_gatt_if esp_err_t ret; ESP_LOGD(TAG, "Inside BLE connect w/ conn_id - %d", param->connect.conn_id); + /* Start each connection with a clean prepare-write buffer */ + protocomm_ble_reset_prepare_write(); + /* Ignore BLE events received after protocomm layer is stopped */ if (protoble_internal == NULL) { ESP_LOGI(TAG,"Protocomm layer has already stopped"); return; } + if (!protocomm_ble_transport_active()) { + ESP_LOGD(TAG, "Protocomm BLE inactive, ignoring connect"); + return; + } + if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->new_transport_session) { ret = protoble_internal->pc_ble->sec->new_transport_session(protoble_internal->pc_ble->sec_inst, @@ -396,6 +464,9 @@ static void transport_simple_ble_connect(esp_gatts_cb_event_t event, esp_gatt_if static void transport_simple_ble_set_mtu(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + if (!protocomm_ble_transport_active()) { + return; + } protoble_internal->gatt_mtu = param->mtu.mtu; return; } @@ -485,6 +556,7 @@ static ssize_t populate_gatt_db(esp_gatts_attr_db_t **gatt_db_generated) static void protocomm_ble_cleanup(void) { + protocomm_ble_reset_prepare_write(); if (protoble_internal) { if (protoble_internal->g_nu_lookup) { for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) { @@ -637,20 +709,29 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con esp_err_t protocomm_ble_stop(protocomm_t *pc) { - if ((pc != NULL) && - (protoble_internal != NULL ) && - (pc == protoble_internal->pc_ble)) { - esp_err_t ret = ESP_OK; + if ((pc == NULL) || + (protoble_internal == NULL ) || + (pc != protoble_internal->pc_ble)) { + return ESP_ERR_INVALID_ARG; + } + esp_err_t ret = ESP_OK; + bool ble_callbacks_active = true; uint8_t protocomm_keep_ble_on = get_keep_ble_on(); + + protoble_internal->pc_ble = NULL; + if (protocomm_keep_ble_on) { #ifdef CONFIG_ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP /* Keep BT stack on, but terminate the connection after provisioning */ - ret = simple_ble_disconnect(); + ret = simple_ble_disconnect(); if (ret) { ESP_LOGE(TAG, "BLE disconnect failed"); - } - simple_ble_deinit(); + } + simple_ble_deinit(); + ble_callbacks_active = false; +#else + ESP_LOGD(TAG, "Keeping BLE stack running after protocomm stop"); #endif // CONFIG_ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP } else { @@ -661,10 +742,13 @@ esp_err_t protocomm_ble_stop(protocomm_t *pc) ESP_LOGE(TAG, "BLE stop failed"); } simple_ble_deinit(); + ble_callbacks_active = false; } + protocomm_ble_reset_prepare_write(); + + if (!ble_callbacks_active) { protocomm_ble_cleanup(); - return ret; } - return ESP_ERR_INVALID_ARG; + return ret; } diff --git a/components/protocomm/src/transports/protocomm_nimble.c b/components/protocomm/src/transports/protocomm_nimble.c index fea2516a5a..04f8e22326 100644 --- a/components/protocomm/src/transports/protocomm_nimble.c +++ b/components/protocomm/src/transports/protocomm_nimble.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -73,6 +74,11 @@ typedef struct _protocomm_ble { } _protocomm_ble_internal_t; static _protocomm_ble_internal_t *protoble_internal; + +static bool protocomm_ble_transport_active(void) +{ + return (protoble_internal != NULL) && (protoble_internal->pc_ble != NULL); +} static struct ble_gap_adv_params adv_params; static char *protocomm_ble_device_name; static struct ble_hs_adv_fields adv_data, resp_data; @@ -285,6 +291,9 @@ simple_ble_gap_event(struct ble_gap_event *event, void *arg) /* Gets `g_nu_lookup name handler` from 128 bit UUID */ static const char *uuid128_to_handler(uint8_t *uuid) { + if (!protocomm_ble_transport_active()) { + return NULL; + } /* Use it to convert 128 bit UUID to 16 bit UUID.*/ uint8_t *uuid16 = uuid + 12; for (int i = 0; i < protoble_internal->g_nu_lookup_count; i++) { @@ -303,6 +312,11 @@ static int gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) { + if (!protocomm_ble_transport_active()) { + ESP_LOGW(TAG, "Ignoring descriptor access on inactive protocomm transport"); + return BLE_ATT_ERR_UNLIKELY; + } + if (ctxt->op != BLE_GATT_ACCESS_OP_READ_DSC) { ESP_LOGE(TAG, "Invalid operation on Read-only Descriptor"); return BLE_ATT_ERR_UNLIKELY; @@ -331,6 +345,11 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle, uint16_t data_len = 0; uint16_t data_buf_len = 0; + if (!protocomm_ble_transport_active()) { + ESP_LOGW(TAG, "Ignoring characteristic access on inactive protocomm transport"); + return BLE_ATT_ERR_UNLIKELY; + } + switch (ctxt->op) { case BLE_GATT_ACCESS_OP_READ_CHR: ESP_LOGD(TAG, "Read attempted for characteristic UUID = %s, attr_handle = %d", @@ -595,6 +614,11 @@ static void transport_simple_ble_disconnect(struct ble_gap_event *event, void *a return; } + if (!protocomm_ble_transport_active()) { + ESP_LOGD(TAG, "Protocomm BLE inactive, ignoring disconnect"); + return; + } + if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->close_transport_session) { ret = @@ -628,6 +652,11 @@ static void transport_simple_ble_connect(struct ble_gap_event *event, void *arg) return; } + if (!protocomm_ble_transport_active()) { + ESP_LOGD(TAG, "Protocomm BLE inactive, ignoring connect"); + return; + } + if (protoble_internal->pc_ble->sec && protoble_internal->pc_ble->sec->new_transport_session) { ret = @@ -651,6 +680,9 @@ static void transport_simple_ble_connect(struct ble_gap_event *event, void *arg) static void transport_simple_ble_set_mtu(struct ble_gap_event *event, void *arg) { + if (!protocomm_ble_transport_active()) { + return; + } protoble_internal->gatt_mtu = event->mtu.value; return; } @@ -1042,16 +1074,21 @@ esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *con esp_err_t protocomm_ble_stop(protocomm_t *pc) { ESP_LOGD(TAG, "protocomm_ble_stop called here..."); - if ((pc != NULL) && - (protoble_internal != NULL ) && - (pc == protoble_internal->pc_ble)) { - esp_err_t ret = ESP_OK; + if ((pc == NULL) || + (protoble_internal == NULL ) || + (pc != protoble_internal->pc_ble)) { + return ESP_ERR_INVALID_ARG; + } - esp_err_t rc = ble_gap_adv_stop(); - if (rc) { - ESP_LOGD(TAG, "Error in stopping advertisement with err code = %d", - rc); - } + esp_err_t ret = ESP_OK; + bool ble_callbacks_active = true; + esp_err_t rc = ble_gap_adv_stop(); + if (rc) { + ESP_LOGD(TAG, "Error in stopping advertisement with err code = %d", + rc); + } + + protoble_internal->pc_ble = NULL; if (ble_cfg_p->keep_ble_on) { #ifdef CONFIG_ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP @@ -1061,6 +1098,9 @@ esp_err_t protocomm_ble_stop(protocomm_t *pc) ESP_LOGI(TAG, "Error in terminating connection rc = %d",rc); } free_gatt_ble_misc_memory(ble_cfg_p); + ble_callbacks_active = false; +#else + ESP_LOGD(TAG, "Keeping BLE stack running after protocomm stop"); #endif // CONFIG_ESP_PROTOCOMM_DISCONNECT_AFTER_BLE_STOP } else { @@ -1070,10 +1110,11 @@ esp_err_t protocomm_ble_stop(protocomm_t *pc) nimble_port_deinit(); } free_gatt_ble_misc_memory(ble_cfg_p); + ble_callbacks_active = false; } + if (!ble_callbacks_active) { protocomm_ble_cleanup(); - return ret; } - return ESP_ERR_INVALID_ARG; + return ret; } From 2501b4403fd2ba59d493a4554b6aa55e508fc4f6 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Tue, 16 Dec 2025 09:07:08 +0000 Subject: [PATCH 074/156] feat(tools): update openocd version to v0.12.0-esp32-20251215 --- tools/tools.json | 50 ++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/tools/tools.json b/tools/tools.json index cf94ce86e9..25f8594505 100644 --- a/tools/tools.json +++ b/tools/tools.json @@ -672,46 +672,46 @@ "versions": [ { "linux-amd64": { - "sha256": "766293bd7a08900d3536f87a0a7ade960f07266f16e4147f95ca5ce4e15d4c5d", - "size": 2489724, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-linux-amd64-0.12.0-esp32-20250707.tar.gz" + "sha256": "5e6ff40aeca23bdd203cde04d60bc808c0e6bff110eadcbce3d602618c880531", + "size": 2547606, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-linux-amd64-0.12.0-esp32-20251215.tar.gz" }, "linux-arm64": { - "sha256": "34b6883c372444b49950893b2fc0101aefd10d404a88ef72c97e80199f8544d3", - "size": 2371243, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-linux-arm64-0.12.0-esp32-20250707.tar.gz" + "sha256": "29f98e2f90cd37924b714562b876a471d444a8f2aec428c6760e82bbf3b54cca", + "size": 2399117, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-linux-arm64-0.12.0-esp32-20251215.tar.gz" }, "linux-armel": { - "sha256": "fd48492cf3ee16577c661fdccc14c349d34a9ab93aac5039ddf72332d4f4b70b", - "size": 2517680, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-linux-armel-0.12.0-esp32-20250707.tar.gz" + "sha256": "25de2b2dd0f5b437f5d5540c505eb9d0fbb971256ab13acd19642f8acdbd5cee", + "size": 2554256, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-linux-armel-0.12.0-esp32-20251215.tar.gz" }, "linux-armhf": { - "sha256": "a468cc108578a1f4553ac0502c814d47791ef79f5997a31e941908fa5119de9c", - "size": 2353427, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-linux-armhf-0.12.0-esp32-20250707.tar.gz" + "sha256": "2a2e6240a688ec91eee054140cc4967afceadeb8660f23f4b55a3936f65720a8", + "size": 2392746, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-linux-armhf-0.12.0-esp32-20251215.tar.gz" }, "macos": { - "sha256": "6267be53892a76d535938a1b044b685adc7d292f090447e8a3e3d0f0996474d1", - "size": 2585348, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-macos-0.12.0-esp32-20250707.tar.gz" + "sha256": "956dd02ccf35116d565be2b148e041bd47c135e551a1f5097eae756d7d4dd079", + "size": 2710467, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-macos-0.12.0-esp32-20251215.tar.gz" }, "macos-arm64": { - "sha256": "150e938ac48a6ee031ddbc8b31043bc7f2073ab2ee4896b658918d35899673c3", - "size": 2628741, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-macos-arm64-0.12.0-esp32-20250707.tar.gz" + "sha256": "e6414c8db2ab09b687eaf765b1e69a92aecdcfe44e073d6f47ff829777e2e823", + "size": 2535504, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-macos-arm64-0.12.0-esp32-20251215.tar.gz" }, - "name": "v0.12.0-esp32-20250707", + "name": "v0.12.0-esp32-20251215", "status": "recommended", "win32": { - "sha256": "666274b04af7f36b430b6d063006051c37b8635b5175735ad5af07a1fbc6f486", - "size": 3034680, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-win32-0.12.0-esp32-20250707.zip" + "sha256": "032a3791c256c974bceced073dc8cf0e18c07a75f39592110cbe71fc8de914b2", + "size": 3109352, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-win32-0.12.0-esp32-20251215.zip" }, "win64": { - "sha256": "5186ba3f7ee29fb6ab68a4ed7bb417211bad76ecdcdf9280a9187ebfd549a3c1", - "size": 3034680, - "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20250707/openocd-esp32-win64-0.12.0-esp32-20250707.zip" + "sha256": "d406be70d26098ced57eefcf636c4b4c184cd8c151204a459bb6ccbe4aa47eca", + "size": 3109355, + "url": "https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20251215/openocd-esp32-win64-0.12.0-esp32-20251215.zip" } } ] From 78f8c22d0efb4dfadd725f032edb8e47b8ea98e0 Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Mon, 17 Nov 2025 14:38:03 +0100 Subject: [PATCH 075/156] change(freertos): add task count and pointer width to OpenOCD debug table --- .../freertos/esp_additions/freertos_tasks_c_additions.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/freertos/esp_additions/freertos_tasks_c_additions.h b/components/freertos/esp_additions/freertos_tasks_c_additions.h index 5ed38208ee..b59262f3af 100644 --- a/components/freertos/esp_additions/freertos_tasks_c_additions.h +++ b/components/freertos/esp_additions/freertos_tasks_c_additions.h @@ -1122,6 +1122,8 @@ void * pvTaskGetCurrentTCBForCore( BaseType_t xCoreID ) ESP_FREERTOS_DEBUG_LIST_END_PREV, ESP_FREERTOS_DEBUG_LIST_ITEM_PREV, ESP_FREERTOS_DEBUG_LIST_ITEM_OWNER, + ESP_FREERTOS_DEBUG_TASK_COUNT_WIDTH, + ESP_FREERTOS_DEBUG_PTR_WIDTH, /* New entries must be inserted here */ ESP_FREERTOS_DEBUG_TABLE_END, }; @@ -1141,7 +1143,9 @@ void * pvTaskGetCurrentTCBForCore( BaseType_t xCoreID ) offsetof( List_t, xListEnd ), /* list_end_offset */ offsetof( List_t, xListEnd.pxPrevious ), /* list_next_offset */ offsetof( ListItem_t, pxPrevious ), /* list_elem_next_offset */ - offsetof( ListItem_t, pvOwner ) /* list_elem_content_offset */ + offsetof( ListItem_t, pvOwner ), /* list_elem_content_offset */ + sizeof( UBaseType_t ), /* task_count_width */ + sizeof( void * ) /* ptr_width */ }; #endif /* CONFIG_FREERTOS_DEBUG_OCDAWARE */ From 1a3e2da8568e6a75f3214f4e2ff6b2c5e3228e2a Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Wed, 17 Dec 2025 10:45:33 +0800 Subject: [PATCH 076/156] fix(jpeg): Fix jpeg color space check --- components/esp_driver_jpeg/jpeg_decode.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/esp_driver_jpeg/jpeg_decode.c b/components/esp_driver_jpeg/jpeg_decode.c index 718e5cffd7..290d6a0677 100644 --- a/components/esp_driver_jpeg/jpeg_decode.c +++ b/components/esp_driver_jpeg/jpeg_decode.c @@ -580,7 +580,7 @@ static bool jpeg_dec_transaction_on_picked(uint32_t channel_num, const dma2d_tra static esp_err_t jpeg_color_space_support_check(jpeg_decoder_handle_t decoder_engine) { -#if !(CONFIG_ESP_REV_MIN_FULL < 300 && CONFIG_IDF_TARGET_ESP32P4) // Invisible for unsupported chips +#if (CONFIG_ESP_REV_MIN_FULL < 300 && CONFIG_IDF_TARGET_ESP32P4) // For P4 less than 3.0 if (decoder_engine->sample_method == JPEG_DOWN_SAMPLING_YUV444) { if (decoder_engine->output_format == JPEG_DECODE_OUT_FORMAT_YUV422 || decoder_engine->output_format == JPEG_DECODE_OUT_FORMAT_YUV420) { ESP_LOGE(TAG, "Detected YUV444 but want to convert to YUV422/YUV420, which is not supported"); @@ -598,9 +598,11 @@ static esp_err_t jpeg_color_space_support_check(jpeg_decoder_handle_t decoder_en } } #else - if (decoder_engine->sample_method != JPEG_DOWN_SAMPLING_YUV422) { - ESP_LOGE(TAG, "Detected YUV444/YUV420 but want to convert to YUV422, which is not supported"); - return ESP_ERR_INVALID_ARG; + if (decoder_engine->sample_method == JPEG_DOWN_SAMPLING_YUV420 || decoder_engine->sample_method == JPEG_DOWN_SAMPLING_YUV444) { + if (decoder_engine->output_format == JPEG_DECODE_OUT_FORMAT_YUV422) { + ESP_LOGE(TAG, "Detected YUV444/YUV420 but want to convert to YUV422, which is not supported"); + return ESP_ERR_INVALID_ARG; + } } #endif return ESP_OK; From 5d8104a6a29b23024ce1794e82ea05d2dfed3ede Mon Sep 17 00:00:00 2001 From: zhuanghang Date: Fri, 28 Nov 2025 20:32:58 +0800 Subject: [PATCH 077/156] feat(802.15.4): Update the 'ieee802154_get_recent_rssi' API to obtain real-time RSSI --- components/ieee802154/driver/esp_ieee802154_dev.c | 3 ++- components/openthread/src/port/esp_openthread_radio.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index a6d7bdec93..0f167bdaca 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -44,6 +44,7 @@ static bool s_rf_closed = true; #define CCA_DETECTION_TIME 8 extern void ieee802154_txon_delay_set(void); +extern uint32_t bt_bb_get_cur_rx_info(void); IEEE802154_STATIC volatile ieee802154_state_t s_ieee802154_state; static uint8_t *s_tx_frame = NULL; @@ -167,7 +168,7 @@ static IEEE802154_NOINLINE void ieee802154_rx_frame_info_update(void) int8_t ieee802154_get_recent_rssi(void) { - return s_rx_frame_info[s_recent_rx_frame_info_index].rssi; + return (int8_t)(bt_bb_get_cur_rx_info() & 0xff); } uint8_t ieee802154_get_recent_lqi(void) diff --git a/components/openthread/src/port/esp_openthread_radio.c b/components/openthread/src/port/esp_openthread_radio.c index 3fd8675677..c5d32fa09f 100644 --- a/components/openthread/src/port/esp_openthread_radio.c +++ b/components/openthread/src/port/esp_openthread_radio.c @@ -661,8 +661,8 @@ esp_err_t IRAM_ATTR esp_ieee802154_enh_ack_generator(uint8_t *frame, esp_ieee802 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE otMacFrameGetSrcAddr(&ot_frame, &mac_addr); - link_metrics_data_len = otLinkMetricsEnhAckGenData(&mac_addr, esp_ieee802154_get_recent_lqi(), - esp_ieee802154_get_recent_rssi(), link_metrics_data); + link_metrics_data_len = otLinkMetricsEnhAckGenData(&mac_addr, frame_info->lqi, + frame_info->rssi, link_metrics_data); if (link_metrics_data_len > 0) { offset += otMacFrameGenerateEnhAckProbingIe(ack_ie_data, link_metrics_data, link_metrics_data_len); } From 7e93257ed1f2b3ea5fb6940684b4dfc20218920c Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Thu, 18 Dec 2025 17:13:38 +0800 Subject: [PATCH 078/156] fix(ble): added missed spin lock initialization (cherry picked from commit 069262e513e822da1901ecfa0023e684b457516d) Co-authored-by: Zhou Xiao --- components/bt/common/ble_log/src/ble_log_lbm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/components/bt/common/ble_log/src/ble_log_lbm.c b/components/bt/common/ble_log/src/ble_log_lbm.c index 5078f2bad7..5a0a125b43 100644 --- a/components/bt/common/ble_log/src/ble_log_lbm.c +++ b/components/bt/common/ble_log/src/ble_log_lbm.c @@ -198,6 +198,7 @@ bool ble_log_lbm_init(void) /* Initialize lock types for spin pool */ for (int i = 0; i < BLE_LOG_LBM_SPIN_MAX; i++) { lbm_ctx->spin_pool[i].lock_type = BLE_LOG_LBM_LOCK_SPIN; + portMUX_INITIALIZE(&(lbm_ctx->spin_pool[i].spin_lock)); } #if CONFIG_BLE_LOG_LL_ENABLED From 943b853746f06cf65158a5a222097102d7ef6676 Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Mon, 3 Nov 2025 14:00:06 +0530 Subject: [PATCH 079/156] Revert "fix: add check to ensure OTA buffer size for 16-byte aligned" This reverts commit 873fd18c5a47a9494ad20d0912c3616ab6cd4411. --- components/app_update/include/esp_ota_ops.h | 4 ---- components/esp_https_ota/src/esp_https_ota.c | 9 --------- 2 files changed, 13 deletions(-) diff --git a/components/app_update/include/esp_ota_ops.h b/components/app_update/include/esp_ota_ops.h index 1a92da1f1e..8ae4cdd315 100644 --- a/components/app_update/include/esp_ota_ops.h +++ b/components/app_update/include/esp_ota_ops.h @@ -113,10 +113,6 @@ esp_err_t esp_ota_begin(const esp_partition_t* partition, size_t image_size, esp * Unlike esp_ota_begin(), this function does not erase the partition which receives the OTA update, but rather expects that part of the image * has already been written correctly, and it resumes writing from the given offset. * - * @note When flash encryption is enabled, data writes must be 16-byte aligned. - * Any leftover (non-aligned) data is temporarily cached and may be lost after reboot. - * Therefore, during resumption, ensure that image offset is always 16-byte aligned. - * * @param partition Pointer to info for the partition which is receiving the OTA update. Required. * @param erase_size Specifies how much flash memory to erase before resuming OTA, depending on whether a sequential write or a bulk erase is being used. * @param image_offset Offset from where to resume the OTA process. Should be set to the number of bytes already written. diff --git a/components/esp_https_ota/src/esp_https_ota.c b/components/esp_https_ota/src/esp_https_ota.c index 7f0e2e5617..f4fe1a8868 100644 --- a/components/esp_https_ota/src/esp_https_ota.c +++ b/components/esp_https_ota/src/esp_https_ota.c @@ -14,7 +14,6 @@ #include #include #include "esp_check.h" -#include "esp_flash_encrypt.h" #include "hal/efuse_hal.h" ESP_EVENT_DEFINE_BASE(ESP_HTTPS_OTA_EVENT); @@ -499,14 +498,6 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http } const int alloc_size = MAX(ota_config->http_config->buffer_size, DEFAULT_OTA_BUF_SIZE); - if (ota_config->ota_resumption) { - if (esp_flash_encryption_enabled() && (alloc_size & 0xFU) != 0) { - // For FE case the flash is written in multiples of 16 bytes - ESP_LOGE(TAG, "Buffer size must be multiple of 16 bytes for FE and ota resumption case"); - goto http_cleanup; - } - } - if (ota_config->buffer_caps != 0) { https_ota_handle->ota_upgrade_buf = (char *)heap_caps_malloc(alloc_size, ota_config->buffer_caps); } else { From 88fe9e436d403e8243db8fe55c4ef55bf5d8827b Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Tue, 21 Oct 2025 12:56:56 +0530 Subject: [PATCH 080/156] fix(esp_https_ota): align OTA resumption offset to 16-byte boundary --- components/esp_https_ota/src/esp_https_ota.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/esp_https_ota/src/esp_https_ota.c b/components/esp_https_ota/src/esp_https_ota.c index f4fe1a8868..bdfbdeaee4 100644 --- a/components/esp_https_ota/src/esp_https_ota.c +++ b/components/esp_https_ota/src/esp_https_ota.c @@ -14,6 +14,7 @@ #include #include #include "esp_check.h" +#include "esp_flash_encrypt.h" #include "hal/efuse_hal.h" ESP_EVENT_DEFINE_BASE(ESP_HTTPS_OTA_EVENT); @@ -344,8 +345,9 @@ esp_err_t esp_https_ota_begin(const esp_https_ota_config_t *ota_config, esp_http if (ota_config->ota_resumption) { // We allow resumption only if we have minimum buffer size already written to flash if (ota_config->ota_image_bytes_written >= DEFAULT_OTA_BUF_SIZE) { - ESP_LOGI(TAG, "Valid OTA resumption case, offset %d", ota_config->ota_image_bytes_written); - https_ota_handle->binary_file_len = ota_config->ota_image_bytes_written; + // For FE case the flash is written in multiples of 16 bytes. So, we need to align the offset to 16 bytes. + https_ota_handle->binary_file_len = esp_flash_encryption_enabled() ? (ota_config->ota_image_bytes_written & ~0xF) : ota_config->ota_image_bytes_written; + ESP_LOGD(TAG, "Resuming OTA from offset: %d", https_ota_handle->binary_file_len); } } From ab8f49823b305ef3e5507a05ad3a1eb85ac892cd Mon Sep 17 00:00:00 2001 From: "nilesh.kale" Date: Wed, 5 Nov 2025 17:38:51 +0530 Subject: [PATCH 081/156] feat: added testcase to check ota resumption if FE is enabled This commit also added config option to set default buffer size for OTA. This testcase mainly checks if OTA resumption fails if data written is not 16 byte aligned when Flash Encryption is enabled. --- .../advanced_https_ota/main/Kconfig.projbuild | 7 ++ .../main/advanced_https_ota_example.c | 1 + .../advanced_https_ota/pytest_advanced_ota.py | 69 +++++++++++++++++++ .../sdkconfig.ci.ota_resumption_flash_enc | 37 ++++++++++ 4 files changed, 114 insertions(+) create mode 100644 examples/system/ota/advanced_https_ota/sdkconfig.ci.ota_resumption_flash_enc diff --git a/examples/system/ota/advanced_https_ota/main/Kconfig.projbuild b/examples/system/ota/advanced_https_ota/main/Kconfig.projbuild index 7bc48c99fc..1b5813e272 100644 --- a/examples/system/ota/advanced_https_ota/main/Kconfig.projbuild +++ b/examples/system/ota/advanced_https_ota/main/Kconfig.projbuild @@ -53,4 +53,11 @@ menu "Example Configuration" This option allows one to configure the OTA process to resume downloading the OTA image from where it left off in case of an error or reboot. + config EXAMPLE_OTA_BUF_SIZE + int "OTA buffer size" + default 1024 + range 1024 65536 + help + Buffer size for OTA data transfers in bytes. + endmenu diff --git a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c index 9664133d4f..dbae02c6f8 100644 --- a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c +++ b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c @@ -227,6 +227,7 @@ void advanced_ota_example_task(void *pvParameter) #ifdef CONFIG_EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD .save_client_session = true, #endif + .buffer_size = CONFIG_EXAMPLE_OTA_BUF_SIZE, }; #ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL_FROM_STDIN diff --git a/examples/system/ota/advanced_https_ota/pytest_advanced_ota.py b/examples/system/ota/advanced_https_ota/pytest_advanced_ota.py index 04acfeb497..11183d9891 100644 --- a/examples/system/ota/advanced_https_ota/pytest_advanced_ota.py +++ b/examples/system/ota/advanced_https_ota/pytest_advanced_ota.py @@ -281,6 +281,75 @@ def test_examples_protocol_advanced_https_ota_example_ota_resumption(dut: Dut) - thread1.terminate() +@pytest.mark.flash_encryption_ota +@pytest.mark.parametrize('config', ['ota_resumption_flash_enc'], indirect=True) +@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True) +@idf_parametrize('target', ['esp32'], indirect=['target']) +def test_examples_protocol_advanced_https_ota_example_ota_resumption_flash_enc(dut: Dut) -> None: + """ + This is a positive test case, which stops the download midway and resumes downloading again with + flash encryption enabled. + steps: | + 1. join AP/Ethernet + 2. Fetch OTA image over HTTPS + 3. Reboot with the new OTA image + """ + # Number of iterations to validate OTA + server_port = 8001 + bin_name = 'advanced_https_ota.bin' + + # For flash encryption, we need to manually erase and flash + dut.serial.erase_flash() + dut.serial.flash() + + # Erase NVS partition + dut.serial.erase_partition(NVS_PARTITION) + + # Start server + thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', server_port)) + thread1.daemon = True + thread1.start() + try: + # start test + dut.expect('Loaded app from partition at offset', timeout=30) + + try: + ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode() + print(f'Connected to AP/Ethernet with IP: {ip_address}') + except pexpect.exceptions.TIMEOUT: + raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet') + + dut.expect('Starting Advanced OTA example', timeout=30) + host_ip = get_host_ip4_by_dest_ip(ip_address) + + print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)) + dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name) + dut.expect('Starting OTA...', timeout=60) + + restart_device_with_random_delay(dut, 5, 15) + + # Validate that the device restarts correctly + dut.expect('Loaded app from partition at offset', timeout=180) + + try: + ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=60)[1].decode() + print(f'Connected to AP/Ethernet with IP: {ip_address}') + except pexpect.exceptions.TIMEOUT: + raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet') + + dut.expect('Starting Advanced OTA example', timeout=30) + host_ip = get_host_ip4_by_dest_ip(ip_address) + + print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)) + dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name) + dut.expect('Starting OTA...', timeout=60) + + dut.expect('upgrade successful. Rebooting ...', timeout=150) + + finally: + thread1.terminate() + + @pytest.mark.ethernet_ota @idf_parametrize('target', ['esp32'], indirect=['target']) def test_examples_protocol_advanced_https_ota_example_truncated_bin(dut: Dut) -> None: diff --git a/examples/system/ota/advanced_https_ota/sdkconfig.ci.ota_resumption_flash_enc b/examples/system/ota/advanced_https_ota/sdkconfig.ci.ota_resumption_flash_enc new file mode 100644 index 0000000000..7cf6ae8fef --- /dev/null +++ b/examples/system/ota/advanced_https_ota/sdkconfig.ci.ota_resumption_flash_enc @@ -0,0 +1,37 @@ +CONFIG_EXAMPLE_FIRMWARE_UPGRADE_URL="FROM_STDIN" +CONFIG_EXAMPLE_SKIP_COMMON_NAME_CHECK=y +CONFIG_EXAMPLE_SKIP_VERSION_CHECK=y +CONFIG_EXAMPLE_OTA_RECV_TIMEOUT=15000 +CONFIG_EXAMPLE_ENABLE_OTA_RESUMPTION=y + +CONFIG_EXAMPLE_CONNECT_ETHERNET=y +CONFIG_EXAMPLE_CONNECT_WIFI=n +CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y +CONFIG_EXAMPLE_ETH_PHY_IP101=y +CONFIG_EXAMPLE_ETH_MDC_GPIO=23 +CONFIG_EXAMPLE_ETH_MDIO_GPIO=18 +CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5 +CONFIG_EXAMPLE_ETH_PHY_ADDR=1 +CONFIG_MBEDTLS_TLS_CLIENT_ONLY=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_EXAMPLE_CONNECT_IPV6=y +CONFIG_EXAMPLE_ETHERNET_EMAC_TASK_STACK_SIZE=3072 +CONFIG_EXAMPLE_CONNECT_IPV6=n +CONFIG_PARTITION_TABLE_OFFSET=0xd000 + +# Default settings for testing this example in CI. +# This configuration is not secure, don't use it in production! +# See Flash Encryption API Guide for more details. + +CONFIG_SECURE_FLASH_ENC_ENABLED=y +CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT=y +CONFIG_SECURE_BOOT_ALLOW_ROM_BASIC=y +CONFIG_SECURE_BOOT_ALLOW_JTAG=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_ENC=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_DEC=y +CONFIG_SECURE_FLASH_UART_BOOTLOADER_ALLOW_CACHE=y +CONFIG_SECURE_FLASH_REQUIRE_ALREADY_ENABLED=y +CONFIG_NVS_ENCRYPTION=n # this test combination is only for flash encryption and ota resumption use-case and hence disabling it. + +# Custom OTA buffer size configuration +CONFIG_EXAMPLE_OTA_BUF_SIZE=2047 From e7e0be698a1566ce259a186d6391f0286923d7d7 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 13:08:24 +0800 Subject: [PATCH 082/156] fix(bt/blurdoird): enable bitpool snity checks --- .../bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c index 553b4eddd4..cb5ed04947 100644 --- a/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c +++ b/components/bt/host/bluedroid/external/sbc/decoder/srce/decoder-sbc.c @@ -305,7 +305,6 @@ OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, return OI_CODEC_SBC_CHECKSUM_MISMATCH; } -#ifdef OI_DEBUG /* * Make sure the bitpool values are sane. */ @@ -317,7 +316,6 @@ OI_STATUS OI_CODEC_SBC_DecodeFrame(OI_CODEC_SBC_DECODER_CONTEXT *context, ERROR(("Bitpool too large: %d (must be <= %ld)", context->common.frameInfo.bitpool, OI_SBC_MaxBitpool(&context->common.frameInfo))); return OI_STATUS_INVALID_PARAMETERS; } -#endif /* * Now decode the SBC data. Partial decode is not yet implemented for an SBC From 33af3a0aa6547ac238e928e5eaf3b37901bc1710 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 14:10:21 +0800 Subject: [PATCH 083/156] fix(bt/blurdoird): check Classic key before cross-key derivation --- components/bt/host/bluedroid/stack/smp/smp_act.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/stack/smp/smp_act.c b/components/bt/host/bluedroid/stack/smp/smp_act.c index a41fbdd1b1..e67634c4c5 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_act.c +++ b/components/bt/host/bluedroid/stack/smp/smp_act.c @@ -1345,7 +1345,14 @@ void smp_key_distribution(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) /* state check to prevent re-entrant */ if (smp_get_state() == SMP_STATE_BOND_PENDING) { if (p_cb->derive_lk) { - smp_derive_link_key_from_long_term_key(p_cb, NULL); + tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(p_cb->pairing_bda); + if (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) && + (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED)) { + SMP_TRACE_DEBUG("%s BREDR key is higher security than existing LE keys, " + "don't derive LK from LTK", __func__); + } else { + smp_derive_link_key_from_long_term_key(p_cb, NULL); + } p_cb->derive_lk = FALSE; } From 1ba8aaaff82481bca1700d7f3daba5acdd7d7581 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 14:17:24 +0800 Subject: [PATCH 084/156] fix(bt/bluedroid): check event ID if of register notification from remote to avoid OOB write --- components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c b/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c index a5fed6b2b0..cae87a2a9e 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_pars_tg.c @@ -242,7 +242,11 @@ static tAVRC_STS avrc_pars_vendor_cmd(tAVRC_MSG_VENDOR *p_msg, tAVRC_COMMAND *p_ status = AVRC_STS_INTERNAL_ERR; } else { BE_STREAM_TO_UINT8 (p_result->reg_notif.event_id, p); - BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p); + if (AVRC_IS_VALID_EVENT_ID(p_result->reg_notif.event_id)) { + BE_STREAM_TO_UINT32 (p_result->reg_notif.param, p); + } else { + status = AVRC_STS_BAD_PARAM; + } } break; From 0f1c203e12bd65f4a2cbf1635ebbe5787b4a28ec Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 14:31:04 +0800 Subject: [PATCH 085/156] fix(bt/bluedroid): make sure SDP only start discovery once --- components/bt/host/bluedroid/bta/hf_ag/bta_ag_sdp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sdp.c b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sdp.c index d35ad4f7c1..0b02557b08 100644 --- a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sdp.c +++ b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sdp.c @@ -404,6 +404,11 @@ void bta_ag_do_disc(tBTA_AG_SCB *p_scb, tBTA_SERVICE_MASK service) return; } + if (p_scb->p_disc_db) { + APPL_TRACE_ERROR("Discovery already in progress... returning."); + return; + } + /* allocate buffer for sdp database */ p_scb->p_disc_db = (tSDP_DISCOVERY_DB *) osi_malloc(BTA_AG_DISC_BUF_SIZE); if(p_scb->p_disc_db) { From 9095d1cd2579a440a95a48744b452e0b19a2060c Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 14:36:33 +0800 Subject: [PATCH 086/156] fix(bt/bluedroid): use osi_calloc to zero reserved fields in AVRCP --- components/bt/host/bluedroid/stack/avrc/avrc_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_api.c b/components/bt/host/bluedroid/stack/avrc/avrc_api.c index f7e31022d0..62a7f8a6ca 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_api.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_api.c @@ -200,7 +200,7 @@ static void avrc_send_continue_frag(UINT8 handle, UINT8 label) if (p_pkt->len > AVRC_MAX_CTRL_DATA_LEN) { int offset_len = MAX(AVCT_MSG_OFFSET, p_pkt->offset); p_pkt_old = p_fcb->p_fmsg; - p_pkt = (BT_HDR *)osi_malloc((UINT16)(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE)); + p_pkt = (BT_HDR *)osi_calloc((UINT16)(AVRC_PACKET_LEN + offset_len + BT_HDR_SIZE)); if (p_pkt) { p_pkt->len = AVRC_MAX_CTRL_DATA_LEN; p_pkt->offset = AVCT_MSG_OFFSET; From 0fc2109ec7943c0d8eb8b39fb5bb39cd037ea32a Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 14:42:53 +0800 Subject: [PATCH 087/156] fix(bt/bluedroid): ignore AVCT commands that are too long --- components/bt/host/bluedroid/stack/avrc/avrc_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_api.c b/components/bt/host/bluedroid/stack/avrc/avrc_api.c index 62a7f8a6ca..8f9646408f 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_api.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_api.c @@ -526,7 +526,7 @@ static void avrc_msg_cback(UINT8 handle, UINT8 label, UINT8 cr, tAVRC_MSG_VENDOR *p_msg = &msg.vendor; if (cr == AVCT_CMD && - (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < sizeof(p_pkt->len))) { + (p_pkt->layer_specific & AVCT_DATA_CTRL && AVRC_PACKET_LEN < p_pkt->len)) { /* Ignore the invalid AV/C command frame */ #if (BT_USE_TRACES == TRUE) p_drop_msg = "dropped - too long AV/C cmd frame size"; From 5b7c17cfc76782d358f18c61cb11891aa13df7f7 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 15:06:06 +0800 Subject: [PATCH 088/156] fix(bt/bluedroid): reject device with same address in legacy paring --- components/bt/host/bluedroid/stack/btm/btm_sec.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/bt/host/bluedroid/stack/btm/btm_sec.c b/components/bt/host/bluedroid/stack/btm/btm_sec.c index ab66eb4214..d77ccde225 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/host/bluedroid/stack/btm/btm_sec.c @@ -5044,6 +5044,12 @@ void btm_sec_pin_code_request (UINT8 *p_bda) btm_pair_state_descr(btm_cb.pairing_state), (p_bda[0] << 8) + p_bda[1], (p_bda[2] << 24) + (p_bda[3] << 16) + (p_bda[4] << 8) + p_bda[5] ); #endif ///BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE + const bt_bdaddr_t *local_bd_addr = controller_get_interface()->get_address(); + if (!memcmp(p_bda, local_bd_addr, BD_ADDR_LEN)) { + BTM_TRACE_WARNING("btm_sec_pin_code_request() rejected device with same address\n"); + btsnd_hcic_pin_code_neg_reply(p_bda); + return; + } if (btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) { if ( (memcmp (p_bda, btm_cb.pairing_bda, BD_ADDR_LEN) == 0) && (btm_cb.pairing_state == BTM_PAIR_STATE_WAIT_AUTH_COMPLETE) ) { From 70f82a5607793379788e0cf7a6e9602533bf8fe3 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 15:24:59 +0800 Subject: [PATCH 089/156] fix(bt/bluedroid): fixed Use-After-Free in btm_sec_[dis]connected --- components/bt/host/bluedroid/stack/btm/btm_sec.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_sec.c b/components/bt/host/bluedroid/stack/btm/btm_sec.c index d77ccde225..8ac25d0971 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/host/bluedroid/stack/btm/btm_sec.c @@ -4278,7 +4278,6 @@ static void btm_sec_connect_after_reject_timeout (TIMER_LIST_ENT *p_tle) #if (SMP_INCLUDED == TRUE) void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode) { - tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); UINT8 res; UINT8 sec_dev_rec_status; BOOLEAN is_pairing_device = FALSE; @@ -4287,6 +4286,8 @@ void btm_sec_connected (UINT8 *bda, UINT16 handle, UINT8 status, UINT8 enc_mode) btm_acl_resubmit_page(); + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev (bda); + /* Commenting out trace due to obf/compilation problems. */ #if (BT_USE_TRACES == TRUE && SMP_INCLUDED == TRUE) @@ -4609,7 +4610,6 @@ tBTM_STATUS btm_sec_disconnect (UINT16 handle, UINT8 reason) *******************************************************************************/ BOOLEAN btm_sec_disconnected (UINT16 handle, UINT8 reason) { - tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); UINT8 old_pairing_flags = btm_cb.pairing_flags; int result = HCI_ERR_AUTH_FAILURE; tBTM_SEC_CALLBACK *p_callback = NULL; @@ -4622,6 +4622,8 @@ BOOLEAN btm_sec_disconnected (UINT16 handle, UINT8 reason) btm_acl_resubmit_page(); #endif + tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev_by_handle (handle); + if (!p_dev_rec) { return FALSE; } From 15e0c748e5189cb94573ed351b3e99f69ad3053f Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 15:43:43 +0800 Subject: [PATCH 090/156] fix(bt/bluedroid): fixed p_data null dereference in l2c_csm_open --- .../bt/host/bluedroid/stack/l2cap/l2c_csm.c | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c b/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c index 9abe72e285..fc5f5b0700 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c @@ -695,7 +695,7 @@ static void l2c_csm_config (tL2C_CCB *p_ccb, UINT16 event, void *p_data) l2cu_process_peer_cfg_rsp (p_ccb, p_cfg); if (p_cfg->result != L2CAP_CFG_PENDING) { - /* TBD: When config options grow beyong minimum MTU (48 bytes) + /* TBD: When config options grow beyond minimum MTU (48 bytes) * logic needs to be added to handle responses with * continuation bit set in flags field. * 1. Send additional config request out until C-bit is cleared in response @@ -885,7 +885,7 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) tL2CAP_CFG_INFO *p_cfg; tL2C_CHNL_STATE tempstate; UINT8 tempcfgdone; - UINT8 cfg_result; + UINT8 cfg_result = L2CAP_PEER_CFG_DISCONNECT; #if (BT_TRACE_VERBOSE == TRUE) L2CAP_TRACE_EVENT ("L2CAP - LCID: 0x%04x st: OPEN evt: %s", @@ -931,7 +931,11 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); - if ((cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg)) == L2CAP_PEER_CFG_OK) { + if (p_cfg) { + cfg_result = l2cu_process_peer_cfg_req (p_ccb, p_cfg); + } + + if (cfg_result == L2CAP_PEER_CFG_OK) { (*p_ccb->p_rcb->api.pL2CA_ConfigInd_Cb)(p_ccb->local_cid, p_cfg); } @@ -968,7 +972,7 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) break; case L2CEVT_L2CAP_DATA: /* Peer data packet rcvd */ - if ((p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb)) { + if (p_data && (p_ccb->p_rcb) && (p_ccb->p_rcb->api.pL2CA_DataInd_Cb)) { (*p_ccb->p_rcb->api.pL2CA_DataInd_Cb)(p_ccb->local_cid, (BT_HDR *)p_data); } break; @@ -988,16 +992,20 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) break; case L2CEVT_L2CA_DATA_WRITE: /* Upper layer data to send */ - l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data); - l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + if (p_data) { + l2c_enqueue_peer_data (p_ccb, (BT_HDR *)p_data); + l2c_link_check_send_pkts (p_ccb->p_lcb, NULL, NULL); + } break; case L2CEVT_L2CA_CONFIG_REQ: /* Upper layer config req */ - p_ccb->chnl_state = CST_CONFIG; - p_ccb->config_done &= ~CFG_DONE_MASK; - l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); - l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); - btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + if (p_data) { + p_ccb->chnl_state = CST_CONFIG; + p_ccb->config_done &= ~CFG_DONE_MASK; + l2cu_process_our_cfg_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); + l2cu_send_peer_config_req (p_ccb, (tL2CAP_CFG_INFO *)p_data); + btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_CFG_TIMEOUT); + } break; case L2CEVT_TIMEOUT: From f15fe75f246baadffd7d787d6f1b0ab953580bf4 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 16:10:32 +0800 Subject: [PATCH 091/156] fix(bt/bluedroid): fixed a potential overflow about the media payload offset This variable is uint16_t, and is possible to overflow when the length of headder extension is larger. Here we compare with the data length to prevent any exceptions. --- .../host/bluedroid/stack/avdt/avdt_scb_act.c | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c b/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c index c87e044fbc..baf489df5e 100644 --- a/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c +++ b/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c @@ -252,10 +252,16 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) UINT16 offset; UINT16 ex_len; UINT8 pad_len = 0; + uint16_t len = p_data->p_pkt->len; p = p_start = (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset; /* parse media packet header */ + offset = 12; // AVDT_MSG_PRS_OCTET1(1) + AVDT_MSG_PRS_M_PT(1) + UINT16(2) + UINT32(4) + 4 + if (len < offset) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, offset); + goto length_error; + } AVDT_MSG_PRS_OCTET1(p, o_v, o_p, o_x, o_cc); AVDT_MSG_PRS_M_PT(p, m_pt, marker); BE_STREAM_TO_UINT16(seq, p); @@ -265,10 +271,16 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) UNUSED(o_v); /* skip over any csrc's in packet */ + offset += o_cc * 4; p += o_cc * 4; /* check for and skip over extension header */ if (o_x) { + offset += 4; + if (len < offset) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, offset); + goto length_error; + } p += 2; BE_STREAM_TO_UINT16(ex_len, p); p += ex_len * 4; @@ -276,18 +288,20 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) /* save our new offset */ offset = (UINT16) (p - p_start); + if (len <= offset) { + goto length_error; + } /* adjust length for any padding at end of packet */ if (o_p) { /* padding length in last byte of packet */ - pad_len = *(p_start + p_data->p_pkt->len); + pad_len = *(p_start + len - 1); } /* do sanity check */ - if ((offset > p_data->p_pkt->len) || ((pad_len + offset) > p_data->p_pkt->len)) { + if (pad_len >= len - offset) { AVDT_TRACE_WARNING("Got bad media packet"); - osi_free(p_data->p_pkt); - p_data->p_pkt = NULL; + goto length_error; } /* adjust offset and length and send it up */ else { @@ -303,18 +317,22 @@ void avdt_scb_hdl_pkt_no_frag(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) #if AVDT_MULTIPLEXING == TRUE if ((p_scb->cs.p_media_cback != NULL) && (p_scb->p_media_buf != NULL) - && (p_scb->media_buf_len > p_data->p_pkt->len)) { + && (p_scb->media_buf_len > len)) { /* media buffer enough length is assigned by application. Lets use it*/ memcpy(p_scb->p_media_buf, (UINT8 *)(p_data->p_pkt + 1) + p_data->p_pkt->offset, - p_data->p_pkt->len); + len); (*p_scb->cs.p_media_cback)(avdt_scb_to_hdl(p_scb), p_scb->p_media_buf, p_scb->media_buf_len, time_stamp, seq, m_pt, marker); } #endif - osi_free(p_data->p_pkt); - p_data->p_pkt = NULL; + goto length_error; } } + return; + +length_error: + osi_free(p_data->p_pkt); + p_data->p_pkt = NULL; } #if AVDT_REPORTING == TRUE @@ -624,7 +642,7 @@ void avdt_scb_hdl_pkt(tAVDT_SCB *p_scb, tAVDT_SCB_EVT *p_data) #endif #if AVDT_MULTIPLEXING == TRUE - /* select right function in dependance of is fragmentation supported or not */ + /* select right function in dependence of is fragmentation supported or not */ if ( 0 != (p_scb->curr_cfg.psc_mask & AVDT_PSC_MUX)) { avdt_scb_hdl_pkt_frag(p_scb, p_data); } else From 4cb6ccc6f6c2c6b955d567734325b8baf952a474 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 16:31:43 +0800 Subject: [PATCH 092/156] fix(bt/bluedroid): fixed potential OOB read in the reporting handler Thanks to Luigino Camastra and Pavel Kohout from Aisle Research as co-reporters for discovering and reporting this issue. --- .../host/bluedroid/stack/avdt/avdt_scb_act.c | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c b/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c index baf489df5e..5fae98eed8 100644 --- a/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c +++ b/components/bt/host/bluedroid/stack/avdt/avdt_scb_act.c @@ -351,13 +351,18 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) UINT8 *p_start = p; UINT32 ssrc; UINT8 o_v, o_p, o_cc; + UINT32 min_len = 0; AVDT_REPORT_TYPE pt; - tAVDT_REPORT_DATA report, *p_rpt; + tAVDT_REPORT_DATA report; AVDT_TRACE_DEBUG( "avdt_scb_hdl_report"); if (p_scb->cs.p_report_cback) { - p_rpt = &report; /* parse report packet header */ + min_len += 8; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } AVDT_MSG_PRS_RPT_OCTET1(p, o_v, o_p, o_cc); pt = *p++; p += 2; @@ -370,6 +375,11 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) switch (pt) { case AVDT_RTCP_PT_SR: /* the packet type - SR (Sender Report) */ + min_len += 20; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } BE_STREAM_TO_UINT32(report.sr.ntp_sec, p); BE_STREAM_TO_UINT32(report.sr.ntp_frac, p); BE_STREAM_TO_UINT32(report.sr.rtp_time, p); @@ -378,6 +388,11 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) break; case AVDT_RTCP_PT_RR: /* the packet type - RR (Receiver Report) */ + min_len += 20; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } report.rr.frag_lost = *p; BE_STREAM_TO_UINT32(report.rr.packet_lost, p); report.rr.packet_lost &= 0xFFFFFF; @@ -388,11 +403,32 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) break; case AVDT_RTCP_PT_SDES: /* the packet type - SDES (Source Description) */ - if (*p == AVDT_RTCP_SDES_CNAME) { - p_rpt = (tAVDT_REPORT_DATA *)(p + 2); + min_len += 1; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } + uint8_t sdes_type; + BE_STREAM_TO_UINT8(sdes_type, p); + if (sdes_type == AVDT_RTCP_SDES_CNAME) { + min_len += 1; + if (len < min_len) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } + uint8_t name_length; + BE_STREAM_TO_UINT8(name_length, p);\ + if ((name_length > len - min_len) || (name_length > AVDT_MAX_CNAME_SIZE)) { + result = AVDT_BAD_PARAMS; + } else { + BE_STREAM_TO_ARRAY(p, &(report.cname[0]), name_length); + } } else { - AVDT_TRACE_WARNING( " - SDES SSRC=0x%08x sc=%d %d len=%d %s\n", - ssrc, o_cc, *p, *(p + 1), p + 2); + if (len < min_len + 1) { + AVDT_TRACE_WARNING("hdl packet length %u too short: must be at least %u", len, min_len); + goto avdt_scb_hdl_report_exit; + } + AVDT_TRACE_WARNING( " - SDES SSRC=0x%08x sc=%d %d len=%d\n", ssrc, o_cc, sdes_type, *p); result = AVDT_BUSY; } break; @@ -403,10 +439,12 @@ UINT8 *avdt_scb_hdl_report(tAVDT_SCB *p_scb, UINT8 *p, UINT16 len) } if (result == AVDT_SUCCESS) { - (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, p_rpt); + (*p_scb->cs.p_report_cback)(avdt_scb_to_hdl(p_scb), pt, &report); } } + +avdt_scb_hdl_report_exit: p_start += len; return p_start; } From 173747750d565de0ba1d2d73eaeae206a747e456 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 17:09:31 +0800 Subject: [PATCH 093/156] fix(bt/bluedroid): fixed potential OOB read in the avrc_pars_vendor_rsp --- .../host/bluedroid/stack/avrc/avrc_pars_ct.c | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c b/components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c index 72f2651397..80874aa397 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_pars_ct.c @@ -55,13 +55,27 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p if (p_msg->p_vendor_data == NULL) { return AVRC_STS_INTERNAL_ERR; } + if (p_msg->vendor_len < 4) { + AVRC_TRACE_WARNING("message length %u too short: must be at least 4", p_msg->vendor_len); + return AVRC_STS_INTERNAL_ERR; + } p = p_msg->p_vendor_data; BE_STREAM_TO_UINT8 (p_result->pdu, p); p++; /* skip the reserved/packe_type byte */ BE_STREAM_TO_UINT16 (len, p); AVRC_TRACE_DEBUG("avrc_pars_vendor_rsp() ctype:0x%x pdu:0x%x, len:%d/0x%x", p_msg->hdr.ctype, p_result->pdu, len, len); + + if (p_msg->vendor_len < len + 4) { + AVRC_TRACE_WARNING("message length %u too short: must be at least %u", p_msg->vendor_len, len + 4); + return AVRC_STS_INTERNAL_ERR; + } + if (p_msg->hdr.ctype == AVRC_RSP_REJ) { + if (len < 1) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 1", len); + return AVRC_STS_INTERNAL_ERR; + } p_result->rsp.status = *p; return p_result->rsp.status; } @@ -82,10 +96,18 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p case AVRC_PDU_REGISTER_NOTIFICATION: /* 0x31 */ #if (AVRC_ADV_CTRL_INCLUDED == TRUE) + if (len < 1) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 1", len); + return AVRC_STS_INTERNAL_ERR; + } BE_STREAM_TO_UINT8 (eventid, p); if (AVRC_EVT_VOLUME_CHANGE == eventid && (AVRC_RSP_CHANGED == p_msg->hdr.ctype || AVRC_RSP_INTERIM == p_msg->hdr.ctype || AVRC_RSP_REJ == p_msg->hdr.ctype || AVRC_RSP_NOT_IMPL == p_msg->hdr.ctype)) { + if (len < 2) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 2", len); + return AVRC_STS_INTERNAL_ERR; + } p_result->reg_notif.status = p_msg->hdr.ctype; p_result->reg_notif.event_id = eventid; BE_STREAM_TO_UINT8 (p_result->reg_notif.param.volume, p); @@ -95,18 +117,30 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p break; #endif /* (AVRC_ADV_CTRL_INCLUDED == TRUE) */ case AVRC_PDU_GET_CAPABILITIES: /* 0x10 */ + if (len < 2) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 2", len); + return AVRC_STS_INTERNAL_ERR; + } BE_STREAM_TO_UINT8 (p_result->get_caps.capability_id, p); BE_STREAM_TO_UINT8 (p_result->get_caps.count, p); if (p_result->get_caps.capability_id == AVRC_CAP_EVENTS_SUPPORTED) { if (p_result->get_caps.count > AVRC_CAP_MAX_NUM_EVT_ID) { status = AVRC_STS_INTERNAL_ERR; } else { + if (len < 2 + p_result->get_caps.count) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least %d", len, 2 + p_result->get_caps.count); + return AVRC_STS_INTERNAL_ERR; + } BE_STREAM_TO_ARRAY(p, p_result->get_caps.param.event_id, p_result->get_caps.count); } } else if (p_result->get_caps.capability_id == AVRC_CAP_COMPANY_ID) { if (p_result->get_caps.count > AVRC_CAP_MAX_NUM_COMP_ID) { status = AVRC_STS_INTERNAL_ERR; } else { + if (len < 2 + p_result->get_caps.count * 6) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least %d", len, 2 + p_result->get_caps.count * 6); + return AVRC_STS_INTERNAL_ERR; + } for (int i = 0; i < p_result->get_caps.count; ++i) { BE_STREAM_TO_UINT24(p_result->get_caps.param.company_id[i], p); } @@ -115,6 +149,10 @@ static tAVRC_STS avrc_pars_vendor_rsp(tAVRC_MSG_VENDOR *p_msg, tAVRC_RESPONSE *p break; case AVRC_PDU_GET_PLAY_STATUS: if (p_msg->hdr.ctype == AVRC_RSP_IMPL_STBL) { + if (len < 9) { + AVRC_TRACE_WARNING("invalid message length %u: must be at least 9", len); + return AVRC_STS_INTERNAL_ERR; + } BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p); BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p); BE_STREAM_TO_UINT8(p_result->get_play_status.play_status, p); From 158519cf8ca84f60c34afcfcd45df57c7a0d26d1 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 17:34:17 +0800 Subject: [PATCH 094/156] fix(bt/bluedroid): added boundary check when reading SDP attribute response packet --- .../host/bluedroid/stack/sdp/sdp_discovery.c | 77 +++++++++++++++---- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c index e1ffdf7261..3f4cc2931f 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c @@ -45,9 +45,9 @@ /* L O C A L F U N C T I O N P R O T O T Y P E S */ /********************************************************************************/ #if SDP_CLIENT_ENABLED == TRUE -static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); -static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); -static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply); +static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end); +static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end); +static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end); static UINT8 *save_attr_seq (tCONN_CB *p_ccb, UINT8 *p, UINT8 *p_msg_end); static tSDP_DISC_REC *add_record (tSDP_DISCOVERY_DB *p_db, BD_ADDR p_bda); static UINT8 *add_attr (UINT8 *p, UINT8 *p_end, tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_rec, @@ -189,7 +189,7 @@ void sdp_disc_connected (tCONN_CB *p_ccb) if (p_ccb->is_attr_search) { p_ccb->disc_state = SDP_DISC_WAIT_SEARCH_ATTR; - process_service_search_attr_rsp (p_ccb, NULL); + process_service_search_attr_rsp (p_ccb, NULL, NULL); } else { /* First step is to get a list of the handles from the server. */ /* We are not searching for a specific attribute, so we will */ @@ -213,7 +213,7 @@ void sdp_disc_connected (tCONN_CB *p_ccb) *******************************************************************************/ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) { - UINT8 *p, rsp_pdu; + UINT8 *p, *p_end, rsp_pdu; BOOLEAN invalid_pdu = TRUE; #if (SDP_DEBUG_RAW == TRUE) @@ -225,7 +225,12 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) /* Got a reply!! Check what we got back */ p = (UINT8 *)(p_msg + 1) + p_msg->offset; + p_end = p + p_msg->len; + if (p_msg->len < 1) { + sdp_disconnect(p_ccb, SDP_GENERIC_ERROR); + return; + } BE_STREAM_TO_UINT8 (rsp_pdu, p); p_msg->len--; @@ -233,21 +238,21 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) switch (rsp_pdu) { case SDP_PDU_SERVICE_SEARCH_RSP: if (p_ccb->disc_state == SDP_DISC_WAIT_HANDLES) { - process_service_search_rsp (p_ccb, p); + process_service_search_rsp (p_ccb, p, p_end); invalid_pdu = FALSE; } break; case SDP_PDU_SERVICE_ATTR_RSP: if (p_ccb->disc_state == SDP_DISC_WAIT_ATTR) { - process_service_attr_rsp (p_ccb, p); + process_service_attr_rsp (p_ccb, p, p_end); invalid_pdu = FALSE; } break; case SDP_PDU_SERVICE_SEARCH_ATTR_RSP: if (p_ccb->disc_state == SDP_DISC_WAIT_SEARCH_ATTR) { - process_service_search_attr_rsp (p_ccb, p); + process_service_search_attr_rsp (p_ccb, p, p_end); invalid_pdu = FALSE; } break; @@ -269,12 +274,17 @@ void sdp_disc_server_rsp (tCONN_CB *p_ccb, BT_HDR *p_msg) ** Returns void ** *******************************************************************************/ -static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end) { UINT16 xx; UINT16 total, cur_handles, orig; UINT8 cont_len; + if (p_reply + 8 > p_reply_end) { + sdp_disconnect (p_ccb, SDP_GENERIC_ERROR); + return; + } + /* Skip transaction, and param len */ p_reply += 4; BE_STREAM_TO_UINT16 (total, p_reply); @@ -296,6 +306,11 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) p_ccb->num_handles = sdp_cb.max_recs_per_search; } + if (p_reply + ((p_ccb->num_handles - orig) * 4) + 1 > p_reply_end) { + sdp_disconnect(p_ccb, SDP_GENERIC_ERROR); + return; + } + for (xx = orig; xx < p_ccb->num_handles; xx++) { BE_STREAM_TO_UINT32 (p_ccb->handles[xx], p_reply); } @@ -306,6 +321,10 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) sdp_disconnect (p_ccb, SDP_INVALID_CONT_STATE); return; } + if (p_reply + cont_len > p_reply_end) { + sdp_disconnect(p_ccb, SDP_INVALID_CONT_STATE); + return; + } /* stay in the same state */ sdp_snd_service_search_req(p_ccb, cont_len, p_reply); } else { @@ -313,7 +332,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) p_ccb->disc_state = SDP_DISC_WAIT_ATTR; /* Kick off the first attribute request */ - process_service_attr_rsp (p_ccb, NULL); + process_service_attr_rsp (p_ccb, NULL, NULL); } } @@ -392,7 +411,7 @@ static void sdp_copy_raw_data (tCONN_CB *p_ccb, BOOLEAN offset) ** Returns void ** *******************************************************************************/ -static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end) { UINT8 *p_start, *p_param_len; UINT16 param_len, list_byte_count; @@ -411,6 +430,11 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* Skip transaction ID and length */ p_reply += 4; + if (p_reply + 2 > p_reply_end) { + sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + BE_STREAM_TO_UINT16 (list_byte_count, p_reply); #if (SDP_DEBUG_RAW == TRUE) SDP_TRACE_WARNING("list_byte_count:%d\n", list_byte_count); @@ -426,6 +450,12 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d\n", p_ccb->list_len, list_byte_count); #endif + + if (p_reply + list_byte_count + 1 /* continuation */ > p_reply_end) { + sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + if (p_ccb->rsp_list == NULL) { p_ccb->rsp_list = (UINT8 *)osi_malloc (SDP_MAX_LIST_BYTE_COUNT); if (p_ccb->rsp_list == NULL) { @@ -502,8 +532,10 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* Was this a continuation request ? */ if (cont_request_needed) { - memcpy (p, p_reply, *p_reply + 1); - p += *p_reply + 1; + if (p_reply + *p_reply + 1 <= p_reply_end) { + memcpy (p, p_reply, *p_reply + 1); + p += *p_reply + 1; + } } else { UINT8_TO_BE_STREAM (p, 0); } @@ -537,7 +569,7 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) ** Returns void ** *******************************************************************************/ -static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) +static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_reply_end) { UINT8 *p, *p_start, *p_end, *p_param_len; UINT8 type; @@ -557,6 +589,11 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* Skip transaction ID and length */ p_reply += 4; + if (p_reply + 2 > p_reply_end) { + sdp_disconnect (p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + BE_STREAM_TO_UINT16 (lists_byte_count, p_reply); #if (SDP_DEBUG_RAW == TRUE) SDP_TRACE_WARNING("lists_byte_count:%d\n", lists_byte_count); @@ -572,6 +609,12 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) SDP_TRACE_WARNING("list_len: %d, list_byte_count: %d\n", p_ccb->list_len, lists_byte_count); #endif + + if (p_reply + lists_byte_count + 1 /* continuation */ > p_reply_end) { + sdp_disconnect(p_ccb, SDP_INVALID_PDU_SIZE); + return; + } + if (p_ccb->rsp_list == NULL) { p_ccb->rsp_list = (UINT8 *)osi_malloc (SDP_MAX_LIST_BYTE_COUNT); if (p_ccb->rsp_list == NULL) { @@ -643,8 +686,10 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply) /* No continuation for first request */ if (p_reply) { - memcpy (p, p_reply, *p_reply + 1); - p += *p_reply + 1; + if (p_reply + *p_reply + 1 <= p_reply_end) { + memcpy (p, p_reply, *p_reply + 1); + p += *p_reply + 1; + } } else { UINT8_TO_BE_STREAM (p, 0); } From 019516284f9805292f4a0c248208ff158fad1b67 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 17:36:48 +0800 Subject: [PATCH 095/156] fix(bt/bluedroid): fixed OOB write in bta_hf_client_handle_cind_list_item --- .../bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c index adf3d609d0..3247021596 100644 --- a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c +++ b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c @@ -362,6 +362,10 @@ static void bta_hf_client_handle_cind_list_item(char *name, UINT32 min, UINT32 m APPL_TRACE_DEBUG("%s %u.%s <%u:%u>", __FUNCTION__, index, name, min, max); + if (index >= BTA_HF_CLIENT_AT_INDICATOR_COUNT) { + return; + } + /* look for a matching indicator on list of supported ones */ for (i = 0; i < BTA_HF_CLIENT_AT_SUPPORTED_INDICATOR_COUNT; i++) { if (strcmp(name, BTA_HF_CLIENT_INDICATOR_SERVICE) == 0) { @@ -1018,7 +1022,7 @@ static char *bta_hf_client_parse_clcc(char *buffer) } } - /* Skip any remaing param,as they are not defined by BT HFP spec */ + /* Skip any remaining param,as they are not defined by BT HFP spec */ AT_SKIP_REST(buffer); AT_CHECK_RN(buffer); @@ -1571,7 +1575,7 @@ void bta_hf_client_send_at_xapl(char *information, UINT32 features) *vendorID: A string representation of the hex value of the vendor ID from the manufacturer, without the 0x prefix. *productID: A string representation of the hex value of the product ID from the manufacturer, without the 0x prefix. *version: The revision of the software. - *Fatures: A base-10 representation of a bit field. Available features are: + *Features: A base-10 representation of a bit field. Available features are: *Bit 0 = reserved *Bit 1 = The accessory supports battery reporting (reserved only for battery operated accessories). *Bit 2 = The accessory is docked or powered (reserved only for battery operated accessories). From 6a497ad92191b9d9decff4260eecb1613852a335 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 17:45:00 +0800 Subject: [PATCH 096/156] fix(bt/bluedroid): fixed OOB read in AT_SKIP_RESET --- components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c index 3247021596..1e3c3b0089 100644 --- a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c +++ b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c @@ -595,7 +595,7 @@ while (*buf == ' ') buf++; buf += sizeof("\r\n") - 1; /* skip rest of AT string up to */ -#define AT_SKIP_REST(buf) while(*buf != '\r') buf++; +#define AT_SKIP_REST(buf) while((*buf != '\r') && (*buf != '\0')) buf++; static char *bta_hf_client_parse_ok(char *buffer) { From 4df287c536e1a882834253769c0a3ec4f041f39b Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 17:49:59 +0800 Subject: [PATCH 097/156] fix(bt/bluedroid): added length check when copy AVDTP packet --- components/bt/host/bluedroid/stack/avct/avct_lcb_act.c | 5 +++++ components/bt/host/bluedroid/stack/avdt/avdt_msg.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/components/bt/host/bluedroid/stack/avct/avct_lcb_act.c b/components/bt/host/bluedroid/stack/avct/avct_lcb_act.c index b83219dceb..98dbaed809 100644 --- a/components/bt/host/bluedroid/stack/avct/avct_lcb_act.c +++ b/components/bt/host/bluedroid/stack/avct/avct_lcb_act.c @@ -86,6 +86,11 @@ static BT_HDR *avct_lcb_msg_asmbl(tAVCT_LCB *p_lcb, BT_HDR *p_buf) AVCT_TRACE_WARNING("Got start during reassembly"); } osi_free(p_lcb->p_rx_msg); + p_lcb->p_rx_msg = NULL; + if (sizeof(BT_HDR) + p_buf->offset + p_buf->len > BT_DEFAULT_BUFFER_SIZE) { + osi_free(p_buf); + return NULL; + } /* Allocate bigger buffer for reassembly. As lower layers are * not aware of possible packet size after reassembly they * would have allocated smaller buffer. diff --git a/components/bt/host/bluedroid/stack/avdt/avdt_msg.c b/components/bt/host/bluedroid/stack/avdt/avdt_msg.c index a049eee925..676c05a492 100644 --- a/components/bt/host/bluedroid/stack/avdt/avdt_msg.c +++ b/components/bt/host/bluedroid/stack/avdt/avdt_msg.c @@ -1314,6 +1314,10 @@ BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf) * not aware of possible packet size after reassembly, they * would have allocated smaller buffer. */ + if (sizeof(BT_HDR) + p_buf->offset + p_buf->len > BT_DEFAULT_BUFFER_SIZE) { + osi_free(p_buf); + return NULL; + } p_ccb->p_rx_msg = (BT_HDR *)osi_malloc(BT_DEFAULT_BUFFER_SIZE); memcpy(p_ccb->p_rx_msg, p_buf, sizeof(BT_HDR) + p_buf->offset + p_buf->len); From be25062b0db669661d76741ca283146b27c9fb13 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 18:02:07 +0800 Subject: [PATCH 098/156] fix(bt/bluedroid): fixed OOB read in SDP server continuation length --- .../bt/host/bluedroid/stack/sdp/sdp_server.c | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_server.c b/components/bt/host/bluedroid/stack/sdp/sdp_server.c index d6f98197d0..43e3664baf 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_server.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_server.c @@ -179,7 +179,6 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, tSDP_RECORD *p_rec = NULL; BT_HDR *p_buf; BOOLEAN is_cont = FALSE; - UNUSED(p_req_end); p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq); @@ -214,6 +213,10 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, } /* Check if this is a continuation request */ + if (p_req + 1 > p_req_end) { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); + return; + } if (*p_req) { if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, @@ -351,6 +354,10 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, } /* Check if this is a continuation request */ + if (p_req + 1 > p_req_end) { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); + return; + } if (*p_req) { /* Free and reallocate buffer */ if (p_ccb->rsp_list) { @@ -565,7 +572,7 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, /* Extract the UUID sequence to search for */ p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq); - if ((!p_req) || (!uid_seq.num_uids)) { + if ((!p_req) || (!uid_seq.num_uids) || (p_req + 2 > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST); return; } @@ -586,7 +593,16 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ; + if (max_list_len < 4) { + sdpu_build_n_send_error (p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL); + return; + } + /* Check if this is a continuation request */ + if (p_req + 1 > p_req_end) { + sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); + return; + } if (*p_req) { /* Free and reallocate buffer */ if (p_ccb->rsp_list) { @@ -600,7 +616,7 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, return; } - if (*p_req++ != SDP_CONTINUATION_LEN) { + if ((*p_req++ != SDP_CONTINUATION_LEN) || (p_req + 2 > p_req_end)) { sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN); return; } From 11eea1b4de8f4b3943295e4998b1fa8e27bfee71 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 18:12:20 +0800 Subject: [PATCH 099/156] fix(bt/bluedroid): added negative length check in process_service_search_rsp --- components/bt/host/bluedroid/stack/sdp/sdp_discovery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c index 3f4cc2931f..82ef1548da 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c @@ -292,7 +292,7 @@ static void process_service_search_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 * orig = p_ccb->num_handles; p_ccb->num_handles += cur_handles; - if (p_ccb->num_handles == 0) { + if ((p_ccb->num_handles == 0) || (p_ccb->num_handles < orig)) { SDP_TRACE_WARNING ("SDP - Rcvd ServiceSearchRsp, no matches\n"); sdp_disconnect (p_ccb, SDP_NO_RECS_MATCH); return; From 56756b1b5dedf1451c304e2f9603bdb3b3a1fa1b Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 18:39:25 +0800 Subject: [PATCH 100/156] fix(bt/bluedroid): fixed buffer overflow in BRSF --- .../bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c index 1e3c3b0089..29276fdb3d 100644 --- a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c +++ b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c @@ -1378,6 +1378,11 @@ void bta_hf_client_at_parse(char *buf, unsigned int len) osi_free(tmp_buff); } + /* prevent buffer overflow in cases where LEN exceeds available buffer space */ + if (len > BTA_HF_CLIENT_AT_PARSER_MAX_LEN - bta_hf_client_cb.scb.at_cb.offset) { + return; + } + memcpy(bta_hf_client_cb.scb.at_cb.buf + bta_hf_client_cb.scb.at_cb.offset, buf, len); bta_hf_client_cb.scb.at_cb.offset += len; From 3ec5f615aec0410da7db3527ca6d2c40dcd748c8 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 18:47:37 +0800 Subject: [PATCH 101/156] fix(bt/bluedroid): report failure when not able to connect to AVRCP --- .../bt/host/bluedroid/bta/av/bta_av_act.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/components/bt/host/bluedroid/bta/av/bta_av_act.c b/components/bt/host/bluedroid/bta/av/bta_av_act.c index 23c1638bca..4feb33e242 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_act.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_act.c @@ -1693,12 +1693,23 @@ void bta_av_rc_disc_done(tBTA_AV_DATA *p_data) p_lcb = bta_av_find_lcb(p_scb->peer_addr, BTA_AV_LCB_FIND); if (p_lcb) { rc_handle = bta_av_rc_create(p_cb, AVCT_INT, (UINT8)(p_scb->hdi + 1), p_lcb->lidx); - p_cb->rcb[rc_handle].peer_features = peer_features; - p_cb->rcb[rc_handle].peer_ct_features = peer_ct_features; - p_cb->rcb[rc_handle].peer_tg_features = peer_tg_features; + if (rc_handle < BTA_AV_NUM_RCB) { + p_cb->rcb[rc_handle].peer_features = peer_features; + p_cb->rcb[rc_handle].peer_ct_features = peer_ct_features; + p_cb->rcb[rc_handle].peer_tg_features = peer_tg_features; #if BTA_AV_CA_INCLUDED - p_cb->rcb[rc_handle].cover_art_l2cap_psm = obex_l2cap_psm; + p_cb->rcb[rc_handle].cover_art_l2cap_psm = obex_l2cap_psm; #endif + } else { + /* cannot create valid rc_handle for current device. report failure */ + APPL_TRACE_ERROR("%s: no link resources available", __func__); + p_scb->use_rc = FALSE; + bdcpy(rc_open.peer_addr, p_scb->peer_addr); + rc_open.peer_features = 0; + rc_open.sdp_disc_done = FALSE; + rc_open.status = BTA_AV_FAIL_SDP; + (*p_cb->p_cback)(BTA_AV_RC_OPEN_EVT, (tBTA_AV *) &rc_open); + } } #if (BT_USE_TRACES == TRUE || BT_TRACE_APPL == TRUE) else { From 5a2b29fe821261fe5ed2bfbfdb5fdcb4188ab15e Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 18:55:55 +0800 Subject: [PATCH 102/156] fix(bt/bluedroid): fixed an OOB write in SDP_AddAttribute --- components/bt/host/bluedroid/stack/sdp/sdp_db.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_db.c b/components/bt/host/bluedroid/stack/sdp/sdp_db.c index f9f2f738c6..06f934d4a3 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_db.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_db.c @@ -415,6 +415,10 @@ BOOLEAN SDP_AddAttribute (UINT32 handle, UINT16 attr_id, UINT8 attr_type, tSDP_RECORD *p_rec = NULL; list_node_t *p_node= NULL; + if (!p_val) { + return FALSE; + } + #if (BT_TRACE_VERBOSE == TRUE) if (sdp_cb.trace_level >= BT_TRACE_LEVEL_DEBUG) { if ((attr_type == UINT_DESC_TYPE) || @@ -448,6 +452,12 @@ BOOLEAN SDP_AddAttribute (UINT32 handle, UINT16 attr_id, UINT8 attr_type, if (p_rec->record_handle == handle) { tSDP_ATTRIBUTE *p_attr = &p_rec->attribute[0]; + // error out early, no need to look up + if (p_rec->free_pad_ptr >= SDP_MAX_PAD_LEN) { + SDP_TRACE_ERROR("the free pad for SDP record with handle %d is full, skip adding the attribute", handle); + return (FALSE); + } + /* Found the record. Now, see if the attribute already exists */ for (xx = 0; xx < p_rec->num_attributes; xx++, p_attr++) { /* The attribute exists. replace it */ From a73e2e4d6c9eabd557cd9f5ebf03fbc7b31dcc6a Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 19:10:42 +0800 Subject: [PATCH 103/156] fix(bt/bluedroid): fixed an OOB bug in btm_read_local_oob_complete --- .../bluedroid/stack/btm/btm_ble_privacy.c | 1 + .../bt/host/bluedroid/stack/btm/btm_sec.c | 19 +++++++++++++++++-- .../bluedroid/stack/btm/include/btm_int.h | 4 ++-- .../bt/host/bluedroid/stack/btu/btu_hcif.c | 2 +- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c index 39784bb11a..84c8f7613c 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_privacy.c @@ -227,6 +227,7 @@ void btm_ble_update_resolving_list(BD_ADDR pseudo_bda, BOOLEAN add) void btm_ble_clear_resolving_list_complete(UINT8 *p, UINT16 evt_len) { UINT8 status = 0; + STREAM_TO_UINT8(status, p); BTM_TRACE_DEBUG("%s status=%d", __func__, status); diff --git a/components/bt/host/bluedroid/stack/btm/btm_sec.c b/components/bt/host/bluedroid/stack/btm/btm_sec.c index 8ac25d0971..e1d4f11fa7 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/host/bluedroid/stack/btm/btm_sec.c @@ -3792,13 +3792,27 @@ void btm_rem_oob_req (UINT8 *p) ** Returns void ** *******************************************************************************/ -void btm_read_local_oob_complete (UINT8 *p) +void btm_read_local_oob_complete (UINT8 *p, UINT16 evt_len) { tBTM_SP_LOC_OOB evt_data; - UINT8 status = *p++; + UINT8 status; + + if (evt_len < 1) { + BTM_TRACE_ERROR("%s malformatted event packet, too short", __func__); + evt_data.status = BTM_ERR_PROCESSING; + goto err_out; + } + + STREAM_TO_UINT8(status, p); BTM_TRACE_EVENT ("btm_read_local_oob_complete:%d\n", status); if (status == HCI_SUCCESS) { + if (evt_len < 1 + 32) { + BTM_TRACE_ERROR("%s malformatted event packet, too short", __func__); + evt_data.status = BTM_ERR_PROCESSING; + goto err_out; + } + evt_data.status = BTM_SUCCESS; STREAM_TO_ARRAY16(evt_data.c, p); STREAM_TO_ARRAY16(evt_data.r, p); @@ -3806,6 +3820,7 @@ void btm_read_local_oob_complete (UINT8 *p) evt_data.status = BTM_ERR_PROCESSING; } +err_out: if (btm_cb.api.p_sp_callback) { (*btm_cb.api.p_sp_callback) (BTM_SP_LOC_OOB_EVT, (tBTM_SP_EVT_DATA *)&evt_data); } diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h index d5b69c6818..68fcee6bc2 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -1259,10 +1259,10 @@ tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda); #if BTM_OOB_INCLUDED == TRUE void btm_rem_oob_req (UINT8 *p); -void btm_read_local_oob_complete (UINT8 *p); +void btm_read_local_oob_complete (UINT8 *p, UINT16 evt_len); #else #define btm_rem_oob_req(p) -#define btm_read_local_oob_complete(p) +#define btm_read_local_oob_complete(p, evt_len) #endif void btm_acl_resubmit_page (void); diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index eb2995b958..061da23524 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1168,7 +1168,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l #endif // #if (CLASSIC_BT_INCLUDED == TRUE) case HCI_READ_LOCAL_OOB_DATA: #if BTM_OOB_INCLUDED == TRUE && SMP_INCLUDED == TRUE - btm_read_local_oob_complete(p); + btm_read_local_oob_complete(p, evt_len); #endif break; From 08a593d80128312fdc6e3ae5d7335b6dc93b7d0d Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 19:15:35 +0800 Subject: [PATCH 104/156] fix(bt/bluedroid): fixed an OOB bug in btm_create_conn_cancel_complete --- components/bt/host/bluedroid/stack/btm/btm_sec.c | 9 +++++++-- components/bt/host/bluedroid/stack/btm/include/btm_int.h | 2 +- components/bt/host/bluedroid/stack/btu/btu_hcif.c | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_sec.c b/components/bt/host/bluedroid/stack/btm/btm_sec.c index e1d4f11fa7..35337e40a3 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_sec.c +++ b/components/bt/host/bluedroid/stack/btm/btm_sec.c @@ -2753,11 +2753,16 @@ static void btm_sec_bond_cancel_complete (void) ** Returns void ** *******************************************************************************/ -void btm_create_conn_cancel_complete (UINT8 *p) +void btm_create_conn_cancel_complete (UINT8 *p, UINT16 evt_len) { UINT8 status; - STREAM_TO_UINT8 (status, p); + if (evt_len >= 1) { + STREAM_TO_UINT8 (status, p); + } else { + BTM_TRACE_ERROR("%s malformatted event packet, too short", __func__); + status = BTM_ERR_PROCESSING; + } //BTM_TRACE_EVENT ("btm_create_conn_cancel_complete(): in State: %s status:%d\n", // btm_pair_state_descr(btm_cb.pairing_state), status); diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h index 68fcee6bc2..5e402df5f9 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -1215,7 +1215,7 @@ tBTM_STATUS btm_sec_mx_access_request (BD_ADDR bd_addr, UINT16 psm, BOOLEAN is_ UINT32 mx_proto_id, UINT32 mx_chan_id, tBTM_SEC_CALLBACK *p_callback, void *p_ref_data); void btm_sec_conn_req (UINT8 *bda, UINT8 *dc); -void btm_create_conn_cancel_complete (UINT8 *p); +void btm_create_conn_cancel_complete (UINT8 *p, UINT16 evt_len); void btm_read_linq_tx_power_complete (UINT8 *p); void btm_sec_init (UINT8 sec_mode); diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index 061da23524..d6ba0897b3 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1163,7 +1163,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l break; #if (CLASSIC_BT_INCLUDED == TRUE) case HCI_CREATE_CONNECTION_CANCEL: - btm_create_conn_cancel_complete(p); + btm_create_conn_cancel_complete(p, evt_len); break; #endif // #if (CLASSIC_BT_INCLUDED == TRUE) case HCI_READ_LOCAL_OOB_DATA: From 04219e5fd4764fc73744e334f7b9ebb20afb22ee Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 13 Oct 2025 09:18:24 +0800 Subject: [PATCH 105/156] fix(bt/bluedroid): fixed an OOB bug in btm_read_tx_power_complete --- .../bt/host/bluedroid/stack/btm/btm_acl.c | 19 ++++++++++++++++++- .../bluedroid/stack/btm/include/btm_int.h | 2 +- .../bt/host/bluedroid/stack/btu/btu_hcif.c | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_acl.c b/components/bt/host/bluedroid/stack/btm/btm_acl.c index fdce6261ff..6af6036e37 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_acl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_acl.c @@ -2300,7 +2300,7 @@ void BTM_BleGetPeriodicAdvListSize(uint8_t *size) ** Returns void ** *******************************************************************************/ -void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble) +void btm_read_tx_power_complete (UINT8 *p, UINT16 evt_len, BOOLEAN is_ble) { tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_tx_power_cmpl_cb; tBTM_TX_POWER_RESULTS results; @@ -2313,12 +2313,23 @@ void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble) btm_cb.devcb.p_tx_power_cmpl_cb = NULL; if (p_cb) { + if (evt_len < 1) { + BTM_TRACE_ERROR("Bogus event packet, too short\n"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } + STREAM_TO_UINT8 (results.hci_status, p); if (results.hci_status == HCI_SUCCESS) { results.status = BTM_SUCCESS; if (!is_ble) { + if (evt_len < 1 + 3) { + BTM_TRACE_ERROR("Bogus event packet, too short\n"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } STREAM_TO_UINT16 (handle, p); STREAM_TO_UINT8 (results.tx_power, p); @@ -2330,6 +2341,11 @@ void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble) } #if BLE_INCLUDED == TRUE else { + if (evt_len < 1 + 1) { + BTM_TRACE_ERROR("Bogus event packet, too short\n"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } STREAM_TO_UINT8 (results.tx_power, p); memcpy(results.rem_bda, btm_cb.devcb.read_tx_pwr_addr, BD_ADDR_LEN); } @@ -2340,6 +2356,7 @@ void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble) results.status = BTM_ERR_PROCESSING; } +err_out: (*p_cb)(&results); } } diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h index 5e402df5f9..4bd359cfd0 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -1073,7 +1073,7 @@ tACL_CONN *btm_handle_to_acl (UINT16 hci_handle); void btm_read_link_policy_complete (UINT8 *p); void btm_read_rssi_complete (UINT8 *p); void btm_read_channel_map_complete (UINT8 *p); -void btm_read_tx_power_complete (UINT8 *p, BOOLEAN is_ble); +void btm_read_tx_power_complete (UINT8 *p, UINT16 evt_len, BOOLEAN is_ble); void btm_acl_pkt_types_changed(UINT8 status, UINT16 handle, UINT16 pkt_types); void btm_read_link_quality_complete (UINT8 *p); tBTM_STATUS btm_set_packet_types (tACL_CONN *p, UINT16 pkt_types); diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index d6ba0897b3..715960054c 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1158,7 +1158,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l break; case HCI_READ_TRANSMIT_POWER_LEVEL: #if (BLE_HOST_READ_TX_POWER_EN == TRUE) - btm_read_tx_power_complete(p, FALSE); + btm_read_tx_power_complete(p, evt_len, FALSE); #endif // #if (BLE_HOST_READ_TX_POWER_EN == TRUE) break; #if (CLASSIC_BT_INCLUDED == TRUE) @@ -1240,7 +1240,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l case HCI_BLE_READ_ADV_CHNL_TX_POWER: #if (BLE_HOST_READ_TX_POWER_EN == TRUE) - btm_read_tx_power_complete(p, TRUE); + btm_read_tx_power_complete(p, evt_len, TRUE); #endif // #if (BLE_HOST_READ_TX_POWER_EN == TRUE) break; #if (BLE_42_ADV_EN == TRUE) From 514bcb41a23d8d82bd17ed4b23bc7a4b9d59c996 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 13 Oct 2025 09:21:34 +0800 Subject: [PATCH 106/156] fix(bt/bluedroid): fixed an OOB bug in btm_delete_stored_link_key_complete --- components/bt/host/bluedroid/stack/btm/btm_devctl.c | 8 +++++++- components/bt/host/bluedroid/stack/btm/include/btm_int.h | 2 +- components/bt/host/bluedroid/stack/btu/btu_hcif.c | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_devctl.c b/components/bt/host/bluedroid/stack/btm/btm_devctl.c index 2250c78bd4..63c26e881e 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_devctl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_devctl.c @@ -1203,7 +1203,7 @@ tBTM_STATUS BTM_DeleteStoredLinkKey(BD_ADDR bd_addr, tBTM_CMPL_CB *p_cb) ** Returns void ** *******************************************************************************/ -void btm_delete_stored_link_key_complete (UINT8 *p) +void btm_delete_stored_link_key_complete (UINT8 *p, UINT16 evt_len) { tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_stored_link_key_cmpl_cb; tBTM_DELETE_STORED_LINK_KEY_COMPLETE result; @@ -1215,10 +1215,16 @@ void btm_delete_stored_link_key_complete (UINT8 *p) /* Set the call back event to indicate command complete */ result.event = BTM_CB_EVT_DELETE_STORED_LINK_KEYS; + if (evt_len < 3) { + BTM_TRACE_ERROR("Malformatted event packet, too short"); + result.status = BTM_ERR_PROCESSING; + goto err_out; + } /* Extract the result fields from the HCI event */ STREAM_TO_UINT8 (result.status, p); STREAM_TO_UINT16 (result.num_keys, p); +err_out: /* Call the call back and pass the result */ (*p_cb)(&result); } diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h index 4bd359cfd0..58c9a0aa92 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -1178,7 +1178,7 @@ void btm_vsc_complete (UINT8 *p, UINT16 cc_opcode, UINT16 evt_len, tBTM_CMPL_CB *p_vsc_cplt_cback); void btm_inq_db_reset (void); void btm_vendor_specific_evt (UINT8 *p, UINT8 evt_len); -void btm_delete_stored_link_key_complete (UINT8 *p); +void btm_delete_stored_link_key_complete (UINT8 *p, UINT16 evt_len); void btm_report_device_status (tBTM_DEV_STATUS status); void btm_set_afh_channels_complete (UINT8 *p); void btm_ble_set_channels_complete (UINT8 *p); diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index 715960054c..9ee72e600e 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1140,7 +1140,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l break; case HCI_DELETE_STORED_LINK_KEY: - btm_delete_stored_link_key_complete (p); + btm_delete_stored_link_key_complete (p, evt_len); break; case HCI_GET_LINK_QUALITY: From f7c0f92556c67248202f220b873dfa1f277d1b72 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 13 Oct 2025 09:24:08 +0800 Subject: [PATCH 107/156] fix(bt/bluedroid): fixed an OOB bug in btm_read_rssi_complete --- components/bt/host/bluedroid/stack/btm/btm_acl.c | 13 ++++++++++++- .../bt/host/bluedroid/stack/btm/include/btm_int.h | 2 +- components/bt/host/bluedroid/stack/btu/btu_hcif.c | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/components/bt/host/bluedroid/stack/btm/btm_acl.c b/components/bt/host/bluedroid/stack/btm/btm_acl.c index 6af6036e37..72154ea7e8 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_acl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_acl.c @@ -2428,7 +2428,7 @@ void btm_read_channel_map_complete(UINT8 *p) ** Returns void ** *******************************************************************************/ -void btm_read_rssi_complete (UINT8 *p) +void btm_read_rssi_complete (UINT8 *p, UINT16 evt_len) { tBTM_CMPL_CB *p_cb = btm_cb.devcb.p_rssi_cmpl_cb; tBTM_RSSI_RESULTS results; @@ -2441,11 +2441,21 @@ void btm_read_rssi_complete (UINT8 *p) btm_cb.devcb.p_rssi_cmpl_cb = NULL; if (p_cb) { + if (evt_len < 1) { + BTM_TRACE_ERROR("Bogus event packet, too short"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } STREAM_TO_UINT8 (results.hci_status, p); if (results.hci_status == HCI_SUCCESS) { results.status = BTM_SUCCESS; + if (evt_len < 1 + 3) { + BTM_TRACE_ERROR("Bogus event packet, too short"); + results.status = BTM_ERR_PROCESSING; + goto err_out; + } STREAM_TO_UINT16 (handle, p); STREAM_TO_UINT8 (results.rssi, p); @@ -2461,6 +2471,7 @@ void btm_read_rssi_complete (UINT8 *p) results.status = BTM_ERR_PROCESSING; } +err_out: (*p_cb)(&results); } } diff --git a/components/bt/host/bluedroid/stack/btm/include/btm_int.h b/components/bt/host/bluedroid/stack/btm/include/btm_int.h index 58c9a0aa92..e1036b9174 100644 --- a/components/bt/host/bluedroid/stack/btm/include/btm_int.h +++ b/components/bt/host/bluedroid/stack/btm/include/btm_int.h @@ -1071,7 +1071,7 @@ void btm_cont_rswitch (tACL_CONN *p, tACL_CONN *btm_handle_to_acl (UINT16 hci_handle); void btm_read_link_policy_complete (UINT8 *p); -void btm_read_rssi_complete (UINT8 *p); +void btm_read_rssi_complete (UINT8 *p, UINT16 evt_len); void btm_read_channel_map_complete (UINT8 *p); void btm_read_tx_power_complete (UINT8 *p, UINT16 evt_len, BOOLEAN is_ble); void btm_acl_pkt_types_changed(UINT8 status, UINT16 handle, UINT16 pkt_types); diff --git a/components/bt/host/bluedroid/stack/btu/btu_hcif.c b/components/bt/host/bluedroid/stack/btu/btu_hcif.c index 9ee72e600e..7ab658588a 100644 --- a/components/bt/host/bluedroid/stack/btu/btu_hcif.c +++ b/components/bt/host/bluedroid/stack/btu/btu_hcif.c @@ -1151,7 +1151,7 @@ static void btu_hcif_hdl_command_complete (UINT16 opcode, UINT8 *p, UINT16 evt_l btm_read_local_name_complete (p, evt_len); break; case HCI_READ_RSSI: - btm_read_rssi_complete (p); + btm_read_rssi_complete (p, evt_len); break; case HCI_BLE_READ_CHNL_MAP: btm_read_channel_map_complete (p); From 5872a8cccb8f23637a0cdf52a31aee44b799077a Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 13 Oct 2025 09:58:57 +0800 Subject: [PATCH 108/156] fix(bt/bluedroid): fixed an OOB bug in bta_av_setconfig_rej --- components/bt/host/bluedroid/bta/av/bta_av_aact.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/bt/host/bluedroid/bta/av/bta_av_aact.c b/components/bt/host/bluedroid/bta/av/bta_av_aact.c index e75fe818c3..2e4f5ec078 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_aact.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_aact.c @@ -1954,13 +1954,17 @@ void bta_av_getcap_results (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) void bta_av_setconfig_rej (tBTA_AV_SCB *p_scb, tBTA_AV_DATA *p_data) { tBTA_AV_REJECT reject; - UINT8 avdt_handle = p_data->ci_setconfig.avdt_handle; + UINT8 err_code = p_data->ci_setconfig.err_code; - bta_av_adjust_seps_idx(p_scb, avdt_handle); + if (err_code == AVDT_SUCCESS) { + err_code = AVDT_ERR_UNSUP_CFG; + } + + bta_av_adjust_seps_idx(p_scb, p_scb->avdt_handle); APPL_TRACE_DEBUG("bta_av_setconfig_rej: sep_idx: %d", p_scb->sep_idx); - AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, p_data->ci_setconfig.err_code, 0); + AVDT_ConfigRsp(p_scb->avdt_handle, p_scb->avdt_label, err_code, 0); - bdcpy(reject.bd_addr, p_data->str_msg.bd_addr); + bdcpy(reject.bd_addr, p_scb->peer_addr); reject.hndl = p_scb->hndl; (*bta_av_cb.p_cback)(BTA_AV_REJECT_EVT, (tBTA_AV *) &reject); } From fa22e34f5699da36b24f401777f0cc5aa53191df Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 13 Oct 2025 10:08:06 +0800 Subject: [PATCH 109/156] fix(bt/bluedroid): fixed an integer overflow bug in avdt_msg_asmbl --- components/bt/host/bluedroid/stack/avdt/avdt_msg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/stack/avdt/avdt_msg.c b/components/bt/host/bluedroid/stack/avdt/avdt_msg.c index 676c05a492..74b7b79184 100644 --- a/components/bt/host/bluedroid/stack/avdt/avdt_msg.c +++ b/components/bt/host/bluedroid/stack/avdt/avdt_msg.c @@ -1279,7 +1279,7 @@ BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf) UINT8 *p; UINT8 pkt_type; BT_HDR *p_ret; - UINT16 buf_len; + size_t buf_len; /* parse the message header */ p = (UINT8 *)(p_buf + 1) + p_buf->offset; @@ -1355,7 +1355,7 @@ BT_HDR *avdt_msg_asmbl(tAVDT_CCB *p_ccb, BT_HDR *p_buf) p_buf->len -= AVDT_LEN_TYPE_CONT; /* verify length */ - if ((p_ccb->p_rx_msg->offset + p_buf->len) > buf_len) { + if (((size_t)p_ccb->p_rx_msg->offset + (size_t)p_buf->len) > buf_len) { /* won't fit; free everything */ AVDT_TRACE_WARNING("%s: Fragmented message too big!", __func__); osi_free(p_ccb->p_rx_msg); From 991486fa022d20f9edcd95c460f13f8b47b2707c Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Mon, 13 Oct 2025 10:24:09 +0800 Subject: [PATCH 110/156] fix(bt/bluedroid): fixed an integer overflow bug in attp_build_read_multi_cmd --- components/bt/host/bluedroid/stack/gatt/att_protocol.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/bt/host/bluedroid/stack/gatt/att_protocol.c b/components/bt/host/bluedroid/stack/gatt/att_protocol.c index 9b3a2507a3..ea7776e4c7 100644 --- a/components/bt/host/bluedroid/stack/gatt/att_protocol.c +++ b/components/bt/host/bluedroid/stack/gatt/att_protocol.c @@ -200,7 +200,8 @@ BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_ BT_HDR *attp_build_read_multi_cmd(UINT8 op_code, UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle) { BT_HDR *p_buf = NULL; - UINT8 *p, i = 0; + UINT8 *p; + UINT16 i = 0; if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET))) != NULL) { p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET; From 8fe4c3599421a37abb36d14da59891e46fb9b101 Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Sat, 11 Oct 2025 18:36:07 +0800 Subject: [PATCH 111/156] fix(bt/bluedroid): drop connection when atttempting to disable encryption --- components/bt/host/bluedroid/stack/btm/btm_acl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/bt/host/bluedroid/stack/btm/btm_acl.c b/components/bt/host/bluedroid/stack/btm/btm_acl.c index 72154ea7e8..6350f4ba26 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_acl.c +++ b/components/bt/host/bluedroid/stack/btm/btm_acl.c @@ -792,6 +792,11 @@ void btm_acl_encrypt_change (UINT16 handle, UINT8 status, UINT8 encr_enable) if (p == NULL) { return; } + /* if we are trying to drop encryption on an encrypted connection, drop the connection */ + if (!encr_enable && (p->encrypt_state == BTM_ACL_ENCRYPT_STATE_ENCRYPT_ON)) { + btm_sec_disconnect(handle, HCI_ERR_HOST_REJECT_SECURITY); + return; + } /* Process Role Switch if active */ if (p->switch_role_state == BTM_ACL_SWKEY_STATE_ENCRYPTION_OFF) { /* if encryption turn off failed we still will try to switch role */ From cf5a568dc0b5dd03328b951e698cc63ee1961d1e Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Thu, 11 Dec 2025 12:11:47 +0800 Subject: [PATCH 112/156] fix(bt/bluedroid): fixed possible OOB read in smp_br_data_received --- components/bt/host/bluedroid/stack/smp/smp_l2c.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/bt/host/bluedroid/stack/smp/smp_l2c.c b/components/bt/host/bluedroid/stack/smp/smp_l2c.c index 1f3db502e2..c109b9d002 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_l2c.c +++ b/components/bt/host/bluedroid/stack/smp/smp_l2c.c @@ -320,6 +320,12 @@ static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) UINT8 cmd ; SMP_TRACE_EVENT ("SMDBG l2c %s\n", __func__); + if (p_buf->len < 1) { + SMP_TRACE_WARNING( "Bogus l2cap packet, too short"); + osi_free(p_buf); + return; + } + STREAM_TO_UINT8(cmd, p); /* sanity check */ @@ -331,6 +337,11 @@ static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) /* reject the pairing request if there is an on-going SMP pairing */ if (SMP_OPCODE_PAIRING_REQ == cmd) { + if (p_buf->len != smp_cmd_size_per_spec[cmd]) { + SMP_TRACE_WARNING( "Ignore received command 0x%02x with invalid length %d", cmd, p_buf->len); + osi_free(p_buf); + return; + } if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) { p_cb->role = HCI_ROLE_SLAVE; p_cb->smp_over_br = TRUE; From 66b2214a0d0eaacd6b690fe0add7c3893c51539a Mon Sep 17 00:00:00 2001 From: Jin Cheng Date: Fri, 10 Oct 2025 17:46:18 +0800 Subject: [PATCH 113/156] fix(bt/bluedroid): cleaned the code according to the tool cppcheck --- .../bt/host/bluedroid/bta/av/bta_av_act.c | 18 ++++++++-------- .../bt/host/bluedroid/bta/dm/bta_dm_act.c | 2 +- .../host/bluedroid/bta/gatt/bta_gattc_act.c | 2 +- .../bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c | 6 ------ .../bta/hf_client/bta_hf_client_at.c | 2 +- .../bt/host/bluedroid/bta/jv/bta_jv_act.c | 4 +++- .../bt/host/bluedroid/bta/jv/bta_jv_api.c | 2 +- components/bt/host/bluedroid/bta/sys/utl.c | 2 +- .../btc/profile/esp/ble_button/button_pro.c | 18 ++++++++-------- .../esp/wechat_AirSync/wx_airsync_prf.c | 10 ++++----- .../btc/profile/std/gap/btc_gap_bt.c | 10 ++++----- .../btc/profile/std/l2cap/btc_l2cap.c | 4 ++-- .../btc/profile/std/pba/btc_pba_client.c | 2 +- .../bluedroid/btc/profile/std/spp/btc_spp.c | 4 ++-- components/bt/host/bluedroid/hci/hci_hal_h4.c | 2 +- .../bt/host/bluedroid/stack/avdt/avdt_scb.c | 4 ++-- .../bt/host/bluedroid/stack/btm/btm_ble.c | 2 +- .../bluedroid/stack/btm/btm_ble_adv_filter.c | 5 ++--- .../bt/host/bluedroid/stack/btm/btm_ble_gap.c | 5 ++--- .../bt/host/bluedroid/stack/btm/btm_inq.c | 2 +- .../bt/host/bluedroid/stack/btm/btm_pm.c | 4 +--- .../bt/host/bluedroid/stack/l2cap/l2c_csm.c | 2 +- .../bt/host/bluedroid/stack/rfcomm/port_api.c | 21 +++++++++---------- .../bt/host/bluedroid/stack/smp/smp_act.c | 2 +- .../bt/host/bluedroid/stack/smp/smp_keys.c | 18 +++++++++------- 25 files changed, 73 insertions(+), 80 deletions(-) diff --git a/components/bt/host/bluedroid/bta/av/bta_av_act.c b/components/bt/host/bluedroid/bta/av/bta_av_act.c index 4feb33e242..434dfa8b22 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_act.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_act.c @@ -1192,16 +1192,16 @@ void bta_av_conn_chg(tBTA_AV_DATA *p_data) } } } else { - if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) { - bta_sys_conn_close(TSEP_TO_SYS_ID(p_scb->seps[p_scb->sep_idx].tsep), bta_av_cb.audio_open_cnt, p_scb->peer_addr); - /* this channel is still marked as open. decrease the count */ - bta_av_cb.audio_open_cnt--; - } - - /* clear the conned mask for this channel */ - p_cb->conn_audio &= ~mask; - p_cb->conn_video &= ~mask; if (p_scb) { + if ((p_cb->conn_audio & mask) && bta_av_cb.audio_open_cnt) { + bta_sys_conn_close(TSEP_TO_SYS_ID(p_scb->seps[p_scb->sep_idx].tsep), bta_av_cb.audio_open_cnt, p_scb->peer_addr); + /* this channel is still marked as open. decrease the count */ + bta_av_cb.audio_open_cnt--; + } + /* clear the conned mask for this channel */ + p_cb->conn_audio &= ~mask; + p_cb->conn_video &= ~mask; + /* the stream is closed. * clear the peer address, so it would not mess up the AVRCP for the next round of operation */ bdcpy(p_scb->peer_addr, bd_addr_null); diff --git a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c index c0383286a2..fd7d665acc 100644 --- a/components/bt/host/bluedroid/bta/dm/bta_dm_act.c +++ b/components/bt/host/bluedroid/bta/dm/bta_dm_act.c @@ -2348,7 +2348,7 @@ void bta_dm_search_result (tBTA_DM_MSG *p_data) /* call back if application wants name discovery or found services that application is searching */ if (( !bta_dm_search_cb.services ) - || (( bta_dm_search_cb.services ) && ( p_data->disc_result.result.disc_res.services ))) { + || ( p_data->disc_result.result.disc_res.services )) { bta_dm_search_cb.p_search_cback(BTA_DM_DISC_RES_EVT, &p_data->disc_result.result); } diff --git a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c index eb2b091eae..f65dd43e7c 100644 --- a/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c +++ b/components/bt/host/bluedroid/bta/gatt/bta_gattc_act.c @@ -2022,7 +2022,7 @@ BOOLEAN bta_gattc_process_srvc_chg_ind(UINT16 conn_id, if ( ++ p_srcb->update_count == bta_gattc_num_reg_app()) { /* not an opened connection; or connection busy */ /* search for first available clcb and start discovery */ - if (p_clcb == NULL || (p_clcb && p_clcb->p_q_cmd != NULL)) { + if ((p_clcb == NULL) || (p_clcb->p_q_cmd != NULL)) { for (i = 0 ; i < BTA_GATTC_CLCB_MAX; i ++) { if (bta_gattc_cb.clcb[i].in_use && bta_gattc_cb.clcb[i].p_srcb == p_srcb && diff --git a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c index ad8c80b1fb..f3bf70e80c 100644 --- a/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c +++ b/components/bt/host/bluedroid/bta/hf_ag/bta_ag_sco.c @@ -1405,14 +1405,8 @@ BOOLEAN bta_ag_sco_is_open(tBTA_AG_SCB *p_scb) *******************************************************************************/ BOOLEAN bta_ag_sco_is_opening(tBTA_AG_SCB *p_scb) { -#if (BTM_WBS_INCLUDED == TRUE ) - return (((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) || - (bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST)) && - (bta_ag_cb.sco.p_curr_scb == p_scb)); -#else return ((bta_ag_cb.sco.state == BTA_AG_SCO_OPENING_ST) && (bta_ag_cb.sco.p_curr_scb == p_scb)); -#endif } /******************************************************************************* diff --git a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c index 29276fdb3d..169c14dfbf 100644 --- a/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c +++ b/components/bt/host/bluedroid/bta/hf_client/bta_hf_client_at.c @@ -1836,7 +1836,7 @@ void bta_hf_client_send_at_bia(void) for (i = 0; i < BTA_HF_CLIENT_AT_INDICATOR_COUNT; i++) { int sup = bta_hf_client_cb.scb.at_cb.indicator_lookup[i] == -1 ? 0 : 1; - at_len += snprintf(buf + at_len, BTA_HF_CLIENT_AT_MAX_LEN - at_len, "%u,", sup); + at_len += snprintf(buf + at_len, BTA_HF_CLIENT_AT_MAX_LEN - at_len, "%d,", sup); } buf[at_len - 1] = '\r'; diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c index 17eba5edd6..a49cfc91a0 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_act.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_act.c @@ -2941,7 +2941,9 @@ void bta_jv_l2cap_connect_le(tBTA_JV_MSG *p_data) if (call_init_f) { cc->p_cback(BTA_JV_L2CAP_CL_INIT_EVT, &evt, cc->user_data); } - t->init_called = TRUE; + if (t) { + t->init_called = TRUE; + } } diff --git a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c index 7419501550..7fb74fdfa8 100644 --- a/components/bt/host/bluedroid/bta/jv/bta_jv_api.c +++ b/components/bt/host/bluedroid/bta/jv/bta_jv_api.c @@ -696,7 +696,7 @@ on *******************************************************************************/ int BTA_JvL2capRead(UINT32 handle, UINT32 req_id, UINT8 *p_data, UINT16 len) { - tBTA_JV_L2CAP_READ evt_data; + tBTA_JV_L2CAP_READ evt_data = {0}; APPL_TRACE_API( "%s", __func__); diff --git a/components/bt/host/bluedroid/bta/sys/utl.c b/components/bt/host/bluedroid/bta/sys/utl.c index 94348e85f0..0c7954d45c 100644 --- a/components/bt/host/bluedroid/bta/sys/utl.c +++ b/components/bt/host/bluedroid/bta/sys/utl.c @@ -43,7 +43,7 @@ INT16 utl_str2int(const char *p_s) { INT32 val = 0; - for (; *p_s == ' ' && *p_s != 0; p_s++); + for (; *p_s == ' '; p_s++); if (*p_s == 0) { return -1; diff --git a/components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c b/components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c index 11126e0880..684c4e1da7 100644 --- a/components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c +++ b/components/bt/host/bluedroid/btc/profile/esp/ble_button/button_pro.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -115,7 +115,7 @@ static void button_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) //uuid = {LEN_UUID_16, {ATT_CHAR_BUTTON_WIT}}; //start the button service after created esp_ble_gatts_start_srvc(p_data->create.service_id); - //add the frist button characteristic --> write characteristic + //add the first button characteristic --> write characteristic esp_ble_gatts_add_char(button_cb_env.clcb.cur_srvc_id, &uuid, (GATT_PERM_WRITE | GATT_PERM_READ), (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE)); @@ -128,15 +128,15 @@ static void button_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) tBTA_GATT_CHAR_PROP prop = (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY); //save the att handle to the env button_cb_env.button_inst.but_wirt_hdl = p_data->add_result.attr_id; - //add the frist button characteristic --> Notify characteristic + //add the first button characteristic --> Notify characteristic esp_ble_gatts_add_char(button_cb_env.clcb.cur_srvc_id, &uuid, GATT_PERM_READ, (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY)); - } else if (p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_BUTTON_NTF) { // add the gattc config descriptor to the notify charateristic + } else if (p_data->add_result.char_uuid.uu.uuid16 == ATT_CHAR_BUTTON_NTF) { // add the gattc config descriptor to the notify characteristic //tBTA_GATT_PERM perm = (GATT_PERM_WRITE|GATT_PERM_WRITE); uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; button_cb_env.button_inst.but_ntf_hdl = p_data->add_result.attr_id; esp_ble_gatts_add_char_descr (button_cb_env.clcb.cur_srvc_id, - (GATT_PERM_WRITE | GATT_PERM_WRITE), + GATT_PERM_WRITE, &uuid); } @@ -151,7 +151,7 @@ static void button_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) //BTA_GATTS_Listen(button_cb_env.gatt_if, true, NULL); break; case ESP_GATTS_CONNECT_EVT: - BTC_TRACE_ERROR("############BUTTON CONNCET EVT################\n"); + BTC_TRACE_ERROR("############BUTTON CONNECT EVT################\n"); //esp_ble_stop_advertising(); //set the connection flag to true button_env_clcb_alloc(p_data->conn.conn_id, p_data->conn.remote_bda); @@ -232,7 +232,7 @@ but_clcb_t *button_env_clcb_alloc (uint16_t conn_id, BD_ADDR remote_bda) ** ** Function button_env_find_conn_id_by_bd_adddr ** -** Description The function searches all LCB with macthing bd address +** Description The function searches all LCB with matching bd address ** ** Returns total number of clcb found. ** @@ -280,7 +280,7 @@ BOOLEAN button_env_clcb_dealloc(uint16_t conn_id) ** ** Function button_init ** -** Description Initializa the GATT Service for button profiles. +** Description Initialize the GATT Service for button profiles. ** *******************************************************************************/ esp_gatt_status_t button_init (but_prf_cb_t call_back) @@ -323,7 +323,7 @@ void button_msg_notify(uint16_t len, uint8_t *button_msg) //notify rsp==false; indicate rsp==true. BOOLEAN rsp = false; if (!conn_status && button_cb_env.clcb.congest) { - BTC_TRACE_ERROR("the conneciton for button profile has been loss\n"); + BTC_TRACE_ERROR("the connection for button profile has been loss\n"); return; } diff --git a/components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c b/components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c index 9ba7ceed69..13b3998da3 100644 --- a/components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c +++ b/components/bt/host/bluedroid/btc/profile/esp/wechat_AirSync/wx_airsync_prf.c @@ -1,6 +1,6 @@ #include "wx_airsync_prf.h" /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -91,7 +91,7 @@ static void airsync_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) airsync_cb_env.is_primery = p_data->create.is_primary; //start the airsync service after created esp_ble_gatts_start_srvc(p_data->create.service_id); - //add the frist airsync characteristic --> write characteristic + //add the first airsync characteristic --> write characteristic esp_ble_gatts_add_char(airsync_cb_env.clcb.cur_srvc_id, &uuid, (GATT_PERM_WRITE | GATT_PERM_READ), (GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE)); @@ -112,7 +112,7 @@ static void airsync_profile_cb(esp_gatts_evt_t event, esp_gatts_t *p_data) uuid.uu.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG; airsync_cb_env.airsync_inst.airsync_ntf_hdl = p_data->add_result.attr_id; esp_ble_gatts_add_char_descr (airsync_cb_env.clcb.cur_srvc_id, - (GATT_PERM_WRITE | GATT_PERM_WRITE), + GATT_PERM_WRITE, &uuid); uuid.uu.uuid16 = ATT_CHAR_AIRSYNC_READ; @@ -207,7 +207,7 @@ tAirSync_CLCB *airsync_env_clcb_alloc (UINT16 conn_id, BD_ADDR remote_bda) ** ** Function airsync_env_find_conn_id_by_bd_adddr ** -** Description The function searches all LCB with macthing bd address +** Description The function searches all LCB with matching bd address ** ** Returns total number of clcb found. ** @@ -231,7 +231,7 @@ UINT16 airsync_env_find_conn_id_by_bd_adddr(BD_ADDR remote_bda) ** ** Function airsync_init ** -** Description Initializa the GATT Service for airsync profiles. +** Description Initialize the GATT Service for airsync profiles. ** *******************************************************************************/ tGATT_STATUS AirSync_Init(tAIRSYNC_CBACK *call_back) diff --git a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c index e1278954c4..8d9e413f51 100644 --- a/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c +++ b/components/bt/host/bluedroid/btc/profile/std/gap/btc_gap_bt.c @@ -290,14 +290,14 @@ static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_d /* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */ switch (event) { case BTA_DM_INQ_RES_EVT: { - if (p_data->inq_res.p_eir) { + if (p_data && p_data->inq_res.p_eir) { param_len += HCI_EXT_INQ_RESPONSE_LEN; } } break; case BTA_DM_DISC_RES_EVT: { - if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) { + if (p_data && p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) { param_len += p_data->disc_res.raw_data_size; } } @@ -305,7 +305,7 @@ static void bte_search_devices_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH *p_d } /* if remote name is available in EIR, set the flag so that stack doesn't trigger RNR */ - if (event == BTA_DM_INQ_RES_EVT) { + if (p_data && (event == BTA_DM_INQ_RES_EVT)) { p_data->inq_res.remt_name_not_required = check_eir_remote_name(p_data, NULL, NULL); } @@ -457,7 +457,7 @@ static void bte_dm_remote_service_record_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_S } /* Allocate buffer to hold the pointers (deep copy). The pointers will point to the end of the tBTA_DM_SEARCH */ if (event == BTA_DM_DISC_RES_EVT) { - if (p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) { + if (p_data && p_data->disc_res.raw_data_size && p_data->disc_res.p_raw_data) { param_len += p_data->disc_res.raw_data_size; } } @@ -549,7 +549,7 @@ static void bte_dm_search_services_evt(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH switch (event) { case BTA_DM_DISC_RES_EVT: { - if ((p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0)) { + if (p_data && (p_data->disc_res.result == BTA_SUCCESS) && (p_data->disc_res.num_uuids > 0)) { param_len += (p_data->disc_res.num_uuids * MAX_UUID_SIZE); } } break; diff --git a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c index 9155784fb8..2fd6b47ea7 100644 --- a/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c +++ b/components/bt/host/bluedroid/btc/profile/std/l2cap/btc_l2cap.c @@ -718,7 +718,7 @@ static void btc_l2cap_write(uint32_t handle) } l2cap_slot_t *slot = NULL; slot = l2cap_find_slot_by_handle(handle); - if (!slot || (slot && !slot->connected)) { + if (!slot || !slot->connected) { if (!slot) { BTC_TRACE_ERROR("%s unable to find l2cap slot!", __func__); } else { @@ -748,7 +748,7 @@ static void btc_l2cap_disconnect(uint32_t handle) } l2cap_slot_t *slot = NULL; slot = l2cap_find_slot_by_handle(handle); - if (!slot || (slot && !slot->connected)) { + if (!slot || !slot->connected) { if (!slot) { BTC_TRACE_ERROR("%s unable to find L2CAP slot! disconnect fail!", __func__); } else { diff --git a/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c b/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c index ede18df37a..6bc1819872 100644 --- a/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c +++ b/components/bt/host/bluedroid/btc/profile/std/pba/btc_pba_client.c @@ -392,7 +392,7 @@ static bool btc_pba_client_pull_vcard_listing(uint16_t handle, char *name, bool if (include_app_param) { uint8_t search_value_len = 0; - if (app_param->include_search_value) { + if (app_param->include_search_value && app_param->search_value) { search_value_len = strlen(app_param->search_value) + 1; } app_param_buff = osi_malloc(BTA_PBAP_PULL_VCARD_LISTING_APP_PARAM_BUFF_SIZE_MIN + search_value_len); diff --git a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c index bb142531a3..297d1d33d4 100644 --- a/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/host/bluedroid/btc/profile/std/spp/btc_spp.c @@ -703,7 +703,7 @@ static void btc_spp_disconnect(btc_spp_args_t *arg) spp_slot_t *slot = NULL; osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); slot = spp_find_slot_by_handle(arg->disconnect.handle); - if (!slot || (slot && !slot->connected)) { + if (!slot || !slot->connected) { osi_mutex_unlock(&spp_local_param.spp_slot_mutex); if (!slot) { BTC_TRACE_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__); @@ -883,7 +883,7 @@ static void btc_spp_write(btc_spp_args_t *arg) spp_slot_t *slot = NULL; osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT); slot = spp_find_slot_by_handle(arg->write.handle); - if (!slot || (slot && !slot->connected)) { + if (!slot || !slot->connected) { osi_mutex_unlock(&spp_local_param.spp_slot_mutex); if (!slot) { BTC_TRACE_ERROR("%s unable to find RFCOMM slot!", __func__); diff --git a/components/bt/host/bluedroid/hci/hci_hal_h4.c b/components/bt/host/bluedroid/hci/hci_hal_h4.c index f91a2260d9..0baa265f2a 100644 --- a/components/bt/host/bluedroid/hci/hci_hal_h4.c +++ b/components/bt/host/bluedroid/hci/hci_hal_h4.c @@ -357,7 +357,7 @@ int hci_adv_credits_prep_to_release(uint16_t num) hci_hal_env.adv_credits_to_release = credits_to_release; osi_mutex_unlock(&hci_hal_env.adv_flow_lock); - if (credits_to_release == num && num != 0) { + if (credits_to_release == num) { osi_alarm_cancel(hci_hal_env.adv_flow_monitor); osi_alarm_set(hci_hal_env.adv_flow_monitor, HCI_ADV_FLOW_MONITOR_PERIOD_MS); } diff --git a/components/bt/host/bluedroid/stack/avdt/avdt_scb.c b/components/bt/host/bluedroid/stack/avdt/avdt_scb.c index 43bc4452c9..ca1e9f4c0f 100644 --- a/components/bt/host/bluedroid/stack/avdt/avdt_scb.c +++ b/components/bt/host/bluedroid/stack/avdt/avdt_scb.c @@ -749,14 +749,14 @@ UINT8 avdt_scb_verify(tAVDT_CCB *p_ccb, UINT8 state, UINT8 *p_seid, UINT16 num_s switch (state) { case AVDT_VERIFY_OPEN: case AVDT_VERIFY_START: - if (p_scb->state != AVDT_SCB_OPEN_ST && p_scb->state != AVDT_SCB_STREAM_ST) { + if (p_scb && p_scb->state != AVDT_SCB_OPEN_ST && p_scb->state != AVDT_SCB_STREAM_ST) { *p_err_code = AVDT_ERR_BAD_STATE; } break; case AVDT_VERIFY_SUSPEND: case AVDT_VERIFY_STREAMING: - if (p_scb->state != AVDT_SCB_STREAM_ST) { + if (p_scb && p_scb->state != AVDT_SCB_STREAM_ST) { *p_err_code = AVDT_ERR_BAD_STATE; } break; diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble.c b/components/bt/host/bluedroid/stack/btm/btm_ble.c index 27ebe49dcf..b5216277e7 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble.c @@ -2393,7 +2393,7 @@ BOOLEAN BTM_BleVerifySignature (BD_ADDR bd_addr, UINT8 *p_orig, UINT16 len, UINT tBTM_SEC_DEV_REC *p_rec = btm_find_dev (bd_addr); UINT8 p_mac[BTM_CMAC_TLEN_SIZE]; - if (p_rec == NULL || (p_rec && !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK))) { + if (p_rec == NULL || !(p_rec->ble.key_type & BTM_LE_KEY_PCSRK)) { BTM_TRACE_ERROR("can not verify signature for unknown device"); } else if (counter < p_rec->ble.keys.counter) { BTM_TRACE_ERROR("signature received with out dated sign counter"); diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c b/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c index 9da0914306..7eef55e912 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_adv_filter.c @@ -429,8 +429,7 @@ BOOLEAN btm_ble_dealloc_addr_filter_counter(tBLE_BD_ADDR *p_bd_addr, UINT8 filte for (i = 0; i < cmn_ble_adv_vsc_cb.max_filter; i ++, p_addr_filter ++) { if ((p_addr_filter->in_use) && (NULL == p_bd_addr || - (NULL != p_bd_addr && - memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0))) { + (memcmp(p_bd_addr->bda, p_addr_filter->bd_addr, BD_ADDR_LEN) == 0)) { found = TRUE; memset(p_addr_filter, 0, sizeof(tBTM_BLE_PF_COUNT)); @@ -915,7 +914,7 @@ tBTM_STATUS btm_ble_clear_scan_pf_filter(tBTM_BLE_SCAN_COND_OP action, if (NULL == p_bda_filter || /* not a generic filter */ - (p_target != NULL && p_bda_filter)) { + (p_target != NULL)) { BTM_TRACE_ERROR("Error: Can not clear filter, No PF filter has been configured!"); return st; } diff --git a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c index 973f32754a..e43185e72d 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c +++ b/components/bt/host/bluedroid/stack/btm/btm_ble_gap.c @@ -3744,7 +3744,7 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt 3. For same address and scan response, do nothing */ int same_addr = memcmp(bda, p_le_inq_cb->adv_addr, BD_ADDR_LEN); - if (same_addr != 0 || (same_addr == 0 && evt_type != BTM_BLE_SCAN_RSP_EVT)) { + if (same_addr != 0 || (evt_type != BTM_BLE_SCAN_RSP_EVT)) { btm_ble_process_last_adv_pkt(); } @@ -3795,8 +3795,7 @@ static void btm_ble_process_adv_pkt_cont(BD_ADDR bda, UINT8 addr_type, UINT8 evt /* new device */ if (p_i == NULL || /* assume a DUMO device, BR/EDR inquiry is always active */ - (p_i && - (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE && + ((p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE && p_i->scan_rsp)) { BTM_TRACE_WARNING("INQ RES: Extra Response Received...cancelling inquiry.."); diff --git a/components/bt/host/bluedroid/stack/btm/btm_inq.c b/components/bt/host/bluedroid/stack/btm/btm_inq.c index 41a47300e7..c74f2b4396 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_inq.c +++ b/components/bt/host/bluedroid/stack/btm/btm_inq.c @@ -1860,7 +1860,7 @@ void btm_process_inq_results (UINT8 *p, UINT8 inq_res_mode) /* new device response */ && ( p_i == NULL || /* existing device with BR/EDR info */ - (p_i && (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0) + ((p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BREDR) != 0) ) #endif diff --git a/components/bt/host/bluedroid/stack/btm/btm_pm.c b/components/bt/host/bluedroid/stack/btm/btm_pm.c index 1c46a7446f..de48a2dad6 100644 --- a/components/bt/host/bluedroid/stack/btm/btm_pm.c +++ b/components/bt/host/bluedroid/stack/btm/btm_pm.c @@ -866,9 +866,7 @@ void btm_pm_proc_ssr_evt (UINT8 *p, UINT16 evt_len) /* notify registered parties */ for (xx = 0; xx < BTM_MAX_PM_RECORDS; xx++) { if (btm_cb.pm_reg_db[xx].mask & BTM_PM_REG_NOTIF) { - if ( p_acl) { - (*btm_cb.pm_reg_db[xx].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status); - } + (*btm_cb.pm_reg_db[xx].cback)( p_acl->remote_addr, BTM_PM_STS_SSR, use_ssr, status); } } } diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c b/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c index fc5f5b0700..6236f12a94 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_csm.c @@ -916,7 +916,7 @@ static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) case L2CEVT_LP_QOS_VIOLATION_IND: /* QOS violation */ /* Tell upper layer. If service guaranteed, then clear the channel */ - if (p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb) { + if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb) { (*p_ccb->p_rcb->api.pL2CA_QoSViolationInd_Cb)(p_ccb->p_lcb->remote_bd_addr); } break; diff --git a/components/bt/host/bluedroid/stack/rfcomm/port_api.c b/components/bt/host/bluedroid/stack/rfcomm/port_api.c index 1aa38ff77c..a6b5920cdb 100644 --- a/components/bt/host/bluedroid/stack/rfcomm/port_api.c +++ b/components/bt/host/bluedroid/stack/rfcomm/port_api.c @@ -181,7 +181,7 @@ int RFCOMM_CreateConnection (UINT16 uuid, UINT8 scn, BOOLEAN is_server, /* If the MTU is not specified (0), keep MTU decision until the * PN frame has to be send * at that time connection should be established and we - * will know for sure our prefered MTU + * will know for sure our preferred MTU */ rfcomm_mtu = L2CAP_MTU_SIZE - RFCOMM_DATA_OVERHEAD; @@ -298,12 +298,12 @@ int RFCOMM_RemoveServer (UINT16 handle) ** ** Description This function is called to provide an address of the ** function which will be called when one of the events -** specified in the mask occures. +** specified in the mask occurs. ** ** Parameters: handle - Handle returned in the RFCOMM_CreateConnection ** p_callback - address of the callback function which should ** be called from the RFCOMM when an event -** specified in the mask occures. +** specified in the mask occurs. ** ** *******************************************************************************/ @@ -537,8 +537,7 @@ BOOLEAN PORT_IsOpening (BD_ADDR bd_addr) } } - if ((!found_port) || - (found_port && (p_port->rfc.state < RFC_STATE_OPENED))) { + if ((!found_port) || (p_port->rfc.state < RFC_STATE_OPENED)) { /* Port is not established yet. */ memcpy (bd_addr, rfc_cb.port.rfc_mcb[xx].bd_addr, BD_ADDR_LEN); return TRUE; @@ -641,7 +640,7 @@ int PORT_GetRxQueueCnt (UINT16 handle, UINT16 *p_rx_queue_count) ** Function PORT_GetState ** ** Description This function is called to fill tPORT_STATE structure -** with the curremt control settings for the port +** with the current control settings for the port ** ** Parameters: handle - Handle returned in the RFCOMM_CreateConnection ** p_settings - Pointer to a tPORT_STATE structure in which @@ -1009,15 +1008,15 @@ int PORT_GetModemStatus (UINT16 handle, UINT8 *p_signal) ** ** Function PORT_ClearError ** -** Description This function retreives information about a communications +** Description This function retrieves information about a communications ** error and reports current status of a connection. The -** function should be called when an error occures to clear +** function should be called when an error occurs to clear ** the connection error flag and to enable additional read ** and write operations. ** ** Parameters: handle - Handle returned in the RFCOMM_CreateConnection ** p_errors - pointer of the variable to receive error codes -** p_status - pointer to the tPORT_STATUS structur to receive +** p_status - pointer to the tPORT_STATUS structure to receive ** connection status ** *******************************************************************************/ @@ -1090,7 +1089,7 @@ int PORT_SendError (UINT16 handle, UINT8 errors) ** Description This function reports current status of a connection. ** ** Parameters: handle - Handle returned in the RFCOMM_CreateConnection -** p_status - pointer to the tPORT_STATUS structur to receive +** p_status - pointer to the tPORT_STATUS structure to receive ** connection status ** *******************************************************************************/ @@ -1700,7 +1699,7 @@ int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len) rc = port_write (p_port, p_buf); - /* If queue went below the threashold need to send flow control */ + /* If queue went below the threshold need to send flow control */ event |= port_flow_control_user (p_port); if (rc == PORT_SUCCESS) { diff --git a/components/bt/host/bluedroid/stack/smp/smp_act.c b/components/bt/host/bluedroid/stack/smp/smp_act.c index e67634c4c5..b467a1c13d 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_act.c +++ b/components/bt/host/bluedroid/stack/smp/smp_act.c @@ -869,7 +869,7 @@ void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data) SMP_TRACE_DEBUG("%s", __func__); /* rejecting BR pairing request over non-SC BR link */ - if (!p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) { + if (p_dev_rec && !p_dev_rec->new_encryption_key_is_p256 && p_cb->role == HCI_ROLE_SLAVE) { reason = SMP_XTRANS_DERIVE_NOT_ALLOW; smp_br_state_machine_event(p_cb, SMP_BR_AUTH_CMPL_EVT, &reason); return; diff --git a/components/bt/host/bluedroid/stack/smp/smp_keys.c b/components/bt/host/bluedroid/stack/smp/smp_keys.c index aec6f709c5..24ef814279 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_keys.c +++ b/components/bt/host/bluedroid/stack/smp/smp_keys.c @@ -549,7 +549,7 @@ void smp_concatenate_peer( tSMP_CB *p_cb, UINT8 **p_data, UINT8 op_code) ** Function smp_gen_p1_4_confirm ** ** Description Generate Confirm/Compare Step1: -** p1 = pres || preq || rat' || iat' +** p1 = press || preq || rat' || iat' ** ** Returns void ** @@ -574,22 +574,22 @@ void smp_gen_p1_4_confirm( tSMP_CB *p_cb, BT_OCTET16 p1) UINT8_TO_STREAM(p, p_cb->addr_type); /* LSB : iat': responder's address type */ UINT8_TO_STREAM(p, addr_type); - /* concatinate preq */ + /* concatenate preq */ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_REQ); - /* concatinate pres */ + /* concatenate press */ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_RSP); } else { /* LSB : iat': initiator's address type */ UINT8_TO_STREAM(p, addr_type); /* LSB : rat': responder's(local) address type */ UINT8_TO_STREAM(p, p_cb->addr_type); - /* concatinate preq */ + /* concatenate preq */ smp_concatenate_peer(p_cb, &p, SMP_OPCODE_PAIRING_REQ); - /* concatinate pres */ + /* concatenate press */ smp_concatenate_local(p_cb, &p, SMP_OPCODE_PAIRING_RSP); } #if SMP_DEBUG == TRUE - SMP_TRACE_DEBUG("p1 = pres || preq || rat' || iat'\n"); + SMP_TRACE_DEBUG("p1 = press || preq || rat' || iat'\n"); smp_debug_print_nbyte_little_endian ((UINT8 *)p1, (const UINT8 *)"P1", 16); #endif } @@ -654,7 +654,7 @@ void smp_calculate_comfirm (tSMP_CB *p_cb, BT_OCTET16 rand, BD_ADDR bda) tSMP_STATUS status = SMP_PAIR_FAIL_UNKNOWN; SMP_TRACE_DEBUG ("smp_calculate_comfirm \n"); - /* generate p1 = pres || preq || rat' || iat' */ + /* generate p1 = press || preq || rat' || iat' */ smp_gen_p1_4_confirm(p_cb, p1); /* p1 = rand XOR p1 */ @@ -2229,7 +2229,7 @@ void smp_process_new_nonce(tSMP_CB *p_cb) static void smp_rand_back(tBTM_RAND_ENC *p) { tSMP_CB *p_cb = &smp_cb; - UINT8 *pp = p->param_buf; + UINT8 *pp = NULL; UINT8 failure = SMP_PAIR_FAIL_UNKNOWN; UINT8 state = p_cb->rand_enc_proc_state & ~0x80; @@ -2247,11 +2247,13 @@ static void smp_rand_back(tBTM_RAND_ENC *p) break; case SMP_GEN_DIV_LTK: + pp = p->param_buf; STREAM_TO_UINT16(p_cb->div, pp); smp_generate_ltk_cont(p_cb, NULL); break; case SMP_GEN_DIV_CSRK: + pp = p->param_buf; STREAM_TO_UINT16(p_cb->div, pp); smp_compute_csrk(p_cb, NULL); break; From ca3ff9aced2b4e58ce69718d014228e01069c196 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Fri, 17 Oct 2025 19:10:48 +0800 Subject: [PATCH 114/156] docs(ppa): add a note about bilinear scaling algorithm in PPA SRM Closes https://github.com/espressif/esp-idf/issues/17531 --- docs/en/api-reference/peripherals/ppa.rst | 4 ++++ docs/zh_CN/api-reference/peripherals/ppa.rst | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/en/api-reference/peripherals/ppa.rst b/docs/en/api-reference/peripherals/ppa.rst index 74998a03b2..3a6f64fe55 100644 --- a/docs/en/api-reference/peripherals/ppa.rst +++ b/docs/en/api-reference/peripherals/ppa.rst @@ -93,6 +93,10 @@ Some notes to avoid confusion in configuring :cpp:type:`ppa_srm_oper_config_t`: - Output block's width/height is totally determined by the input block's width/height, scaling factor, and rotation angle, so output block's width/height does not need to be configured. However, please make sure the output block can fit at the offset location in the output picture. - If the color mode of the input or output picture is ``PPA_SRM_COLOR_MODE_YUV420``, then its ``pic_w``, ``pic_h``, ``block_w``, ``block_h``, ``block_offset_x``, ``block_offset_y`` fields must be even. +.. note:: + + The PPA SRM internally uses bilinear scaling algorithm to process. Therefore, it may cause chromatic aberration and loss of contrast at the edges in a scaled picture. + Blend ~~~~~ diff --git a/docs/zh_CN/api-reference/peripherals/ppa.rst b/docs/zh_CN/api-reference/peripherals/ppa.rst index 053908b71a..c9b4841413 100644 --- a/docs/zh_CN/api-reference/peripherals/ppa.rst +++ b/docs/zh_CN/api-reference/peripherals/ppa.rst @@ -93,6 +93,10 @@ PPA 操作包括: - 输出块的宽度/高度完全由输入块的宽度/高度、缩放因子和旋转角度决定,因此无需配置输出块的宽度/高度。但请确保输出块可以适应输出图片中的偏移位置。 - 如果输入或输出图片的色彩模式为 ``PPA_SRM_COLOR_MODE_YUV420``,那么其 ``pic_w``、``pic_h``、``block_w``、``block_h``、``block_offset_x`` 以及 ``block_offset_y`` 字段必须为偶数。 +.. note:: + + PPA SRM 内部使用双线性缩放算法进行处理。因此,缩放后的图片边缘可能会出现色差和对比度损失。 + 叠加 ~~~~ From 507bea72e7b1b188885e3ba752d1546cccc74a7b Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 20 Oct 2025 16:58:21 +0800 Subject: [PATCH 115/156] fix(ppa): YUV444 cannot be a PPA SRM output color mode --- components/esp_driver_ppa/src/ppa_srm.c | 14 +++----------- components/hal/esp32p4/include/hal/ppa_ll.h | 2 +- components/hal/include/hal/ppa_types.h | 5 ++--- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c index fd30be80e7..2b6c834e98 100644 --- a/components/esp_driver_ppa/src/ppa_srm.c +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -114,13 +114,6 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel } ppa_srm_color_mode_t ppa_out_color_mode = srm_trans_desc->out.srm_cm; - if (ppa_out_color_mode == PPA_SRM_COLOR_MODE_YUV444) { - ppa_out_color_mode = PPA_SRM_COLOR_MODE_YUV420; - dma2d_csc_config_t dma_rx_csc = { - .rx_csc_option = DMA2D_CSC_RX_YUV420_TO_YUV444, - }; - dma2d_configure_color_space_conversion(dma2d_rx_chan, &dma_rx_csc); - } // Configure the block size to be received by the SRM engine, which is passed from the 2D-DMA TX channel (i.e. 2D-DMA dscr-port mode) uint32_t block_h = 0, block_v = 0; @@ -179,7 +172,9 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; ESP_RETURN_ON_FALSE(((uint32_t)config->out.buffer & (buf_alignment_size - 1)) == 0 && (config->out.buffer_size & (buf_alignment_size - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "out.buffer addr or out.buffer_size not aligned to cache line size"); - ESP_RETURN_ON_FALSE(ppa_ll_srm_is_color_mode_supported(config->in.srm_cm) && ppa_ll_srm_is_color_mode_supported(config->out.srm_cm), ESP_ERR_INVALID_ARG, TAG, "unsupported color mode"); + ESP_RETURN_ON_FALSE(ppa_ll_srm_is_color_mode_supported(config->in.srm_cm) && + (ppa_ll_srm_is_color_mode_supported(config->out.srm_cm) && config->out.srm_cm != PPA_SRM_COLOR_MODE_YUV444), + ESP_ERR_INVALID_ARG, TAG, "unsupported color mode"); // For YUV420 input/output: in desc, ha/hb/va/vb/x/y must be even number // For YUV422 input/output: in desc, ha/hb/x must be even number if (config->in.srm_cm == PPA_SRM_COLOR_MODE_YUV420) { @@ -290,9 +285,6 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s if (config->in.srm_cm == PPA_SRM_COLOR_MODE_YUV444) { dma_trans_desc->channel_flags |= DMA2D_CHANNEL_FUNCTION_FLAG_TX_CSC; } - if (config->out.srm_cm == PPA_SRM_COLOR_MODE_YUV444) { - dma_trans_desc->channel_flags |= DMA2D_CHANNEL_FUNCTION_FLAG_RX_CSC; - } dma_trans_desc->specified_tx_channel_mask = 0; dma_trans_desc->specified_rx_channel_mask = 0; diff --git a/components/hal/esp32p4/include/hal/ppa_ll.h b/components/hal/esp32p4/include/hal/ppa_ll.h index a0e7323397..60159b65c7 100644 --- a/components/hal/esp32p4/include/hal/ppa_ll.h +++ b/components/hal/esp32p4/include/hal/ppa_ll.h @@ -244,7 +244,7 @@ static inline bool ppa_ll_srm_is_color_mode_supported(ppa_srm_color_mode_t color case PPA_SRM_COLOR_MODE_RGB888: case PPA_SRM_COLOR_MODE_RGB565: case PPA_SRM_COLOR_MODE_YUV420: - case PPA_SRM_COLOR_MODE_YUV444: // YUV444 not supported by PPA hardware, but can be converted by 2D-DMA before/after PPA + case PPA_SRM_COLOR_MODE_YUV444: // YUV444 not supported by PPA hardware, but can be converted by 2D-DMA before PPA, and not supported as output color mode #if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 case PPA_SRM_COLOR_MODE_YUV422_UYVY: case PPA_SRM_COLOR_MODE_YUV422_VYUY: diff --git a/components/hal/include/hal/ppa_types.h b/components/hal/include/hal/ppa_types.h index 6f99322255..0120556ce3 100644 --- a/components/hal/include/hal/ppa_types.h +++ b/components/hal/include/hal/ppa_types.h @@ -40,10 +40,9 @@ typedef enum { PPA_SRM_COLOR_MODE_RGB888 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB888), /*!< PPA SRM color mode: RGB888 */ PPA_SRM_COLOR_MODE_RGB565 = COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), /*!< PPA SRM color mode: RGB565 */ PPA_SRM_COLOR_MODE_YUV420 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV420), /*!< PPA SRM color mode: YUV420 */ - PPA_SRM_COLOR_MODE_YUV444 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV444), /*!< PPA SRM color mode: YUV444 (limited range only)*/ - // YUV444 not supported by PPA hardware, but we can use 2D-DMA to do conversion before sending into and after coming out from the PPA module + PPA_SRM_COLOR_MODE_YUV444 = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUV444), /*!< PPA SRM color mode: YUV444 (limited range only and can only be the input color mode)*/ + // YUV444 not supported by PPA hardware, but we can use 2D-DMA to do conversion before sending into the PPA module // If in_pic is YUV444, then TX DMA channel could do DMA2D_CSC_TX_YUV444_TO_RGB888_601/709, so PPA in_color_mode is RGB888 - // If out_pic is YUV444, then RX DMA channel could do DMA2D_CSC_RX_YUV420_TO_YUV444, so PPA out_color_mode is YUV420 PPA_SRM_COLOR_MODE_YUV422_UYVY = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_UYVY422), /*!< PPA SRM color mode: YUV422 */ PPA_SRM_COLOR_MODE_YUV422_VYUY = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_VYUY422), /*!< PPA SRM color mode: YUV422, only available on input */ PPA_SRM_COLOR_MODE_YUV422_YUYV = COLOR_TYPE_ID(COLOR_SPACE_YUV, COLOR_PIXEL_YUYV422), /*!< PPA SRM color mode: YUV422, only available on input */ From 1b13ef0498328d02cde60c8e69c1bf1b6736ca36 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 20 Oct 2025 17:39:17 +0800 Subject: [PATCH 116/156] fix(ppa): fix potential SRM operation stuck on DMA issue Apply a workaound to bypass macro block order function in PPA SRM when specific conditions are met to avoid SRM operation getting stuck --- components/esp_driver_ppa/src/ppa_srm.c | 22 +++++ .../esp_driver_ppa/test_apps/main/test_ppa.c | 84 +++++++++++++++++++ components/hal/esp32p4/include/hal/ppa_ll.h | 11 +++ 3 files changed, 117 insertions(+) diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c index 2b6c834e98..c35a736bf3 100644 --- a/components/esp_driver_ppa/src/ppa_srm.c +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -156,6 +156,28 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel ppa_ll_srm_enable_mirror_x(platform->hal.dev, srm_trans_desc->mirror_x); ppa_ll_srm_enable_mirror_y(platform->hal.dev, srm_trans_desc->mirror_y); + // Hardware bug workaround (DIG-734) + uint32_t w_out = srm_trans_desc->in.block_w * srm_trans_desc->scale_x_int + srm_trans_desc->in.block_w * srm_trans_desc->scale_x_frag / PPA_LL_SRM_SCALING_FRAG_MAX; + uint32_t w_divisor = (ppa_out_color_mode == PPA_SRM_COLOR_MODE_ARGB8888 || ppa_out_color_mode == PPA_SRM_COLOR_MODE_RGB888) ? 32 : 64; + uint32_t w_left = w_out % w_divisor; + w_left = (w_left == 0) ? w_divisor : w_left; + uint32_t h_mb = (ppa_ll_srm_get_mb_size(platform->hal.dev) == PPA_LL_SRM_MB_SIZE_16_16) ? 16 : 32; + uint32_t h_in_left = srm_trans_desc->in.block_h % h_mb; + h_in_left = (h_in_left == 0) ? h_mb : h_in_left; + uint32_t h_left = h_in_left * srm_trans_desc->scale_y_int + h_in_left * srm_trans_desc->scale_y_frag / PPA_LL_SRM_SCALING_FRAG_MAX; + const uint32_t dma2d_fifo_depth_bits = 12 * 128; + color_space_pixel_format_t out_pixel_format = { + .color_type_id = ppa_out_color_mode, + }; + uint32_t out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format); + bool bypass_mb_order = false; + if (((w_out > w_divisor) || (srm_trans_desc->in.block_h > h_mb)) && // will be cut into more than one trans unit + ((w_left * h_left * out_pixel_depth) < dma2d_fifo_depth_bits) + ) { + bypass_mb_order = true; + } + ppa_ll_srm_bypass_mb_order(platform->hal.dev, bypass_mb_order); + ppa_ll_srm_start(platform->hal.dev); // No need to yield diff --git a/components/esp_driver_ppa/test_apps/main/test_ppa.c b/components/esp_driver_ppa/test_apps/main/test_ppa.c index 011add8c2e..8684e6ee15 100644 --- a/components/esp_driver_ppa/test_apps/main/test_ppa.c +++ b/components/esp_driver_ppa/test_apps/main/test_ppa.c @@ -18,6 +18,7 @@ #include "hal/color_hal.h" #include "esp_cache.h" #include "ppa_performance.h" +#include "esp_random.h" #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) @@ -837,3 +838,86 @@ TEST_CASE("ppa_fill_performance", "[PPA]") free(out_buf); } + +TEST_CASE("ppa_srm_stress_test", "[PPA]") +{ + // Configurable parameters + const uint32_t w = 200; + const uint32_t h = 200; + const ppa_srm_color_mode_t in_cm = PPA_SRM_COLOR_MODE_RGB565; + const ppa_srm_color_mode_t out_cm = PPA_SRM_COLOR_MODE_RGB565; + const ppa_srm_rotation_angle_t rotation = PPA_SRM_ROTATION_ANGLE_0; + const float scale_x = 1.0; + const float scale_y = 1.0; + + color_space_pixel_format_t in_pixel_format = { + .color_type_id = in_cm, + }; + color_space_pixel_format_t out_pixel_format = { + .color_type_id = out_cm, + }; + + uint32_t in_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_pixel_format) / 8; + uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64); + uint8_t *out_buf = heap_caps_aligned_calloc(4, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(out_buf); + uint8_t *in_buf = heap_caps_aligned_calloc(4, in_buf_size, sizeof(uint8_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(in_buf); + + ppa_client_handle_t ppa_client_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_SRM, + .max_pending_trans_num = 1, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle)); + + // Test on different sizes of the block + int test_iterations = 50; + while (test_iterations-- > 0) { + uint32_t block_w_initial = esp_random() % (w - 100); + uint32_t block_h_initial = esp_random() % (h - 100); + block_w_initial = (block_w_initial == 0) ? 1 : block_w_initial; + block_h_initial = (block_h_initial == 0) ? 1 : block_h_initial; + uint32_t block_w = 0; + uint32_t block_h = 0; + for (int i = 0; i < 100; i++) { + block_w = block_w_initial + i; + block_h = block_h_initial + i; + // printf("block_w = %ld, block_h = %ld\n", block_w, block_h); + ppa_srm_oper_config_t oper_config = { + .in.buffer = in_buf, + .in.pic_w = w, + .in.pic_h = h, + .in.block_w = block_w, + .in.block_h = block_h, + .in.block_offset_x = 0, + .in.block_offset_y = 0, + .in.srm_cm = in_cm, + + .out.buffer = out_buf, + .out.buffer_size = out_buf_size, + .out.pic_w = block_w, + .out.pic_h = block_h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.srm_cm = out_cm, + + .rotation_angle = rotation, + .scale_x = scale_x, + .scale_y = scale_y, + + .rgb_swap = 0, + .byte_swap = 0, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config)); + } + } + + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); + + free(in_buf); + free(out_buf); +} diff --git a/components/hal/esp32p4/include/hal/ppa_ll.h b/components/hal/esp32p4/include/hal/ppa_ll.h index 60159b65c7..cf4e5786d5 100644 --- a/components/hal/esp32p4/include/hal/ppa_ll.h +++ b/components/hal/esp32p4/include/hal/ppa_ll.h @@ -600,6 +600,17 @@ static inline void ppa_ll_srm_get_dma_dscr_port_mode_block_size(ppa_dev_t *dev, } } +/** + * @brief Whether to bypass the macro block order function in PPA SRM + * + * @param dev Peripheral instance address + * @param enable True to bypass; False to not bypass + */ +static inline void ppa_ll_srm_bypass_mb_order(ppa_dev_t *dev, bool enable) +{ + dev->sr_byte_order.sr_macro_bk_ro_bypass = enable; +} + //////////////////////////////////// Blending //////////////////////////////////////// /* * Alpha Blending Calculation: From d6fbe418c6886bc4c7f0c25aaad85793c5081d03 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 17 Dec 2025 21:31:05 +0800 Subject: [PATCH 117/156] fix(ppa): fix SRM YUV422/420 incorrect DMA descriptor port mode block size --- components/hal/esp32p4/include/hal/ppa_ll.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/hal/esp32p4/include/hal/ppa_ll.h b/components/hal/esp32p4/include/hal/ppa_ll.h index cf4e5786d5..a299531151 100644 --- a/components/hal/esp32p4/include/hal/ppa_ll.h +++ b/components/hal/esp32p4/include/hal/ppa_ll.h @@ -550,14 +550,14 @@ static inline void ppa_ll_srm_get_dma_dscr_port_mode_block_size(ppa_dev_t *dev, break; case PPA_SRM_COLOR_MODE_YUV420: *block_h = 20; - *block_v = 18; + *block_v = 20; break; case PPA_SRM_COLOR_MODE_YUV422_UYVY: case PPA_SRM_COLOR_MODE_YUV422_VYUY: case PPA_SRM_COLOR_MODE_YUV422_YUYV: case PPA_SRM_COLOR_MODE_YUV422_YVYU: *block_h = 20; - *block_v = 20; + *block_v = 18; break; default: // Unsupported SRM input color mode @@ -577,14 +577,14 @@ static inline void ppa_ll_srm_get_dma_dscr_port_mode_block_size(ppa_dev_t *dev, break; case PPA_SRM_COLOR_MODE_YUV420: *block_h = 36; - *block_v = 34; + *block_v = 36; break; case PPA_SRM_COLOR_MODE_YUV422_UYVY: case PPA_SRM_COLOR_MODE_YUV422_VYUY: case PPA_SRM_COLOR_MODE_YUV422_YUYV: case PPA_SRM_COLOR_MODE_YUV422_YVYU: *block_h = 36; - *block_v = 36; + *block_v = 34; break; default: // Unsupported SRM input color mode From 9cc1f04c742fbc2755725000a23b7333cae02177 Mon Sep 17 00:00:00 2001 From: "igor.udot" Date: Tue, 23 Dec 2025 13:18:20 +0800 Subject: [PATCH 118/156] ci: docs artifacts expiration time --- .gitlab/ci/docs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab/ci/docs.yml b/.gitlab/ci/docs.yml index 3ea791048a..139ac5b32e 100644 --- a/.gitlab/ci/docs.yml +++ b/.gitlab/ci/docs.yml @@ -118,7 +118,7 @@ build_docs_html_full: paths: - docs/_build/*/*/*.txt - docs/_build/*/*/html/* - expire_in: 4 days + expire_in: 12 hrs variables: DOC_BUILDERS: "html" @@ -131,7 +131,7 @@ build_docs_html_partial: paths: - docs/_build/*/*/*.txt - docs/_build/*/*/html/* - expire_in: 4 days + expire_in: 12 hrs variables: DOC_BUILDERS: "html" parallel: From 4f1cf6a5d2e86eda19f46df57cd54e134556b3f1 Mon Sep 17 00:00:00 2001 From: diplfranzhoepfinger Date: Mon, 17 Nov 2025 00:42:50 +0100 Subject: [PATCH 119/156] chor(twai): improve error logging in _node_queue_tx function Enhanced error message for unmatched dlc and buffer_len. Merges https://github.com/espressif/esp-idf/pull/17888 --- components/esp_driver_twai/esp_twai_onchip.c | 3 +- components/esp_driver_twai/include/esp_twai.h | 33 ++++++++++++++----- .../esp_driver_twai/include/esp_twai_types.h | 1 + .../test_twai/main/test_twai_common.c | 6 +++- docs/en/api-reference/peripherals/twai.rst | 2 +- docs/zh_CN/api-reference/peripherals/twai.rst | 2 +- 6 files changed, 34 insertions(+), 13 deletions(-) diff --git a/components/esp_driver_twai/esp_twai_onchip.c b/components/esp_driver_twai/esp_twai_onchip.c index 262f4d183a..e6cf642394 100644 --- a/components/esp_driver_twai/esp_twai_onchip.c +++ b/components/esp_driver_twai/esp_twai_onchip.c @@ -569,6 +569,7 @@ static esp_err_t _node_get_status(twai_node_handle_t node, twai_node_status_t *s status_ret->state = atomic_load(&twai_ctx->state); status_ret->tx_error_count = twai_hal_get_tec(twai_ctx->hal); status_ret->rx_error_count = twai_hal_get_rec(twai_ctx->hal); + status_ret->tx_queue_remaining = uxQueueSpacesAvailable(twai_ctx->tx_mount_queue); } if (record_ret) { *record_ret = twai_ctx->history; @@ -582,7 +583,7 @@ static esp_err_t _node_queue_tx(twai_node_handle_t node, const twai_frame_t *fra { twai_onchip_ctx_t *twai_ctx = __containerof(node, twai_onchip_ctx_t, api_base); if (frame->header.dlc && frame->buffer_len) { - ESP_RETURN_ON_FALSE_ISR(frame->header.dlc == twaifd_len2dlc(frame->buffer_len), ESP_ERR_INVALID_ARG, TAG, "unmatched dlc and buffer_len"); + ESP_RETURN_ON_FALSE_ISR(frame->header.dlc == twaifd_len2dlc(frame->buffer_len), ESP_ERR_INVALID_ARG, TAG, "unmatched dlc(%i) and buffer_len(%i)", frame->header.dlc, twaifd_len2dlc(frame->buffer_len)); } #if !SOC_TWAI_SUPPORT_FD ESP_RETURN_ON_FALSE_ISR(!frame->header.fdf || frame->buffer_len <= TWAI_FRAME_MAX_LEN, ESP_ERR_INVALID_ARG, TAG, "fdf flag or buffer_len not supported"); diff --git a/components/esp_driver_twai/include/esp_twai.h b/components/esp_driver_twai/include/esp_twai.h index 73cba1a636..8a99ee75b2 100644 --- a/components/esp_driver_twai/include/esp_twai.h +++ b/components/esp_driver_twai/include/esp_twai.h @@ -18,7 +18,8 @@ extern "C" { * @brief Enable the TWAI node * * @param node Handle to the TWAI node - * @return ESP_OK on success, error code otherwise + * @return - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Node already in enabled state */ esp_err_t twai_node_enable(twai_node_handle_t node); @@ -26,7 +27,8 @@ esp_err_t twai_node_enable(twai_node_handle_t node); * @brief Disable the TWAI node * * @param node Handle to the TWAI node - * @return ESP_OK on success, error code otherwise + * @return - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Node not in enabled state */ esp_err_t twai_node_disable(twai_node_handle_t node); @@ -35,7 +37,8 @@ esp_err_t twai_node_disable(twai_node_handle_t node); * @note Follow `on_state_change` callback or `twai_node_get_info` to know recover finish or not * * @param node Handle to the TWAI node - * @return ESP_OK on success, error code otherwise + * @return - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Node not in bus-off state */ esp_err_t twai_node_recover(twai_node_handle_t node); @@ -43,7 +46,8 @@ esp_err_t twai_node_recover(twai_node_handle_t node); * @brief Delete the TWAI node and release resources * * @param node Handle to the TWAI node - * @return ESP_OK on success, error code otherwise + * @return - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Node not in disabled state */ esp_err_t twai_node_delete(twai_node_handle_t node); @@ -75,7 +79,9 @@ esp_err_t twai_node_reconfig_timing(twai_node_handle_t node, const twai_timing_a * @param node Handle to the TWAI node * @param filter_id Index of the filter to configure * @param mask_cfg Pointer to the mask filter configuration - * @return ESP_OK on success, error code otherwise + * @return - ESP_OK: Success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Node not in disabled state */ esp_err_t twai_node_config_mask_filter(twai_node_handle_t node, uint8_t filter_id, const twai_mask_filter_config_t *mask_cfg); @@ -85,7 +91,9 @@ esp_err_t twai_node_config_mask_filter(twai_node_handle_t node, uint8_t filter_i * @param node Handle to the TWAI node * @param filter_id Index of the filter to configure * @param range_cfg Pointer to the range filter configuration - * @return ESP_OK on success, error code otherwise + * @return - ESP_OK: Success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Node not in disabled state */ esp_err_t twai_node_config_range_filter(twai_node_handle_t node, uint8_t filter_id, const twai_range_filter_config_t *range_cfg); @@ -107,7 +115,11 @@ esp_err_t twai_node_get_info(twai_node_handle_t node, twai_node_status_t *status * @param[in] node Handle to the TWAI node * @param[in] frame Pointer to the frame to transmit * @param[in] timeout_ms Maximum wait time if the transmission queue is full (milliseconds), -1 to wait forever - * @return ESP_OK on success, error code otherwise + * @return - ESP_OK: Success + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_INVALID_STATE: Node already in bus-off state + * - ESP_ERR_NOT_SUPPORTED: Node is config as listen only + * - ESP_ERR_TIMEOUT: Timeout to wait for queue space */ esp_err_t twai_node_transmit(twai_node_handle_t node, const twai_frame_t *frame, int timeout_ms); @@ -116,7 +128,9 @@ esp_err_t twai_node_transmit(twai_node_handle_t node, const twai_frame_t *frame, * * @param[in] node Handle to the TWAI node * @param[in] timeout_ms Maximum wait time for all pending transfers to finish (milliseconds), -1 to wait forever - * @return ESP_OK on success, error code otherwise + * @return - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Node already in bus-off state + * - ESP_ERR_TIMEOUT: Timeout */ esp_err_t twai_node_transmit_wait_all_done(twai_node_handle_t node, int timeout_ms); @@ -129,7 +143,8 @@ esp_err_t twai_node_transmit_wait_all_done(twai_node_handle_t node, int timeout_ * * @param[in] node Handle to the TWAI node * @param[out] rx_frame Pointer to the frame store rx content - * @return ESP_OK on success, error code otherwise + * @return - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Called from a task or from other callbacks except `rx_done_cb` */ esp_err_t twai_node_receive_from_isr(twai_node_handle_t node, twai_frame_t *rx_frame); diff --git a/components/esp_driver_twai/include/esp_twai_types.h b/components/esp_driver_twai/include/esp_twai_types.h index 35023ae76f..84320545eb 100644 --- a/components/esp_driver_twai/include/esp_twai_types.h +++ b/components/esp_driver_twai/include/esp_twai_types.h @@ -42,6 +42,7 @@ typedef struct { twai_error_state_t state; /**< Node's error state */ uint16_t tx_error_count; /**< Node's TX error count */ uint16_t rx_error_count; /**< Node's RX error count */ + uint32_t tx_queue_remaining; /**< Node's TX free queue space */ } twai_node_status_t; /** diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.c b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.c index 18f289dc2c..20f5032e35 100644 --- a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.c +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.c @@ -230,7 +230,11 @@ TEST_CASE("twai transmit stop resume (loopback)", "[twai]") TEST_ESP_OK(twai_node_enable(node_hdl)); //waiting pkg receive finish - TEST_ESP_OK(twai_node_transmit_wait_all_done(node_hdl, -1)); + twai_node_status_t status = {}; + while (status.tx_queue_remaining < TEST_TWAI_QUEUE_DEPTH) { + TEST_ESP_OK(twai_node_get_info(node_hdl, &status, NULL)); + printf("%ld\n", status.tx_queue_remaining); + } free(tx_msgs); // check if pkg receive correct diff --git a/docs/en/api-reference/peripherals/twai.rst b/docs/en/api-reference/peripherals/twai.rst index 59e03f4f5f..7d2a08bd64 100644 --- a/docs/en/api-reference/peripherals/twai.rst +++ b/docs/en/api-reference/peripherals/twai.rst @@ -311,7 +311,7 @@ The TWAI controller can detect errors caused by bus interference or corrupted fr - **Error Passive**: When either TEC or REC is greater than or equal to 128, the node enters the passive error state. It can still communicate on the bus but sends only one **passive error flag** when detecting errors. - **Bus Off**: When **TEC** is greater than or equal to 256, the node enters the bus off (offline) state. The node is effectively disconnected and does not affect the bus. It remains offline until recovery is triggered by software. -Software can retrieve the node status anytime via the function :cpp:func:`twai_node_get_info`. When the controller detects errors, it triggers the :cpp:member:`twai_event_callbacks_t::on_error` callback, where the error data provides detailed information. +Software can retrieve the node status from tasks via the function :cpp:func:`twai_node_get_info`. When the controller detects errors, it triggers the :cpp:member:`twai_event_callbacks_t::on_error` callback, where the error data provides detailed information. When the node’s error state changes, the :cpp:member:`twai_event_callbacks_t::on_state_change` callback is triggered, allowing the application to respond to the state transition. If the node is offline and needs recovery, call :cpp:func:`twai_node_recover` from a task context. **Note that recovery is not immediate; the controller will automatically reconnect to the bus only after detecting 129 consecutive recessive bits (11 bits each).** diff --git a/docs/zh_CN/api-reference/peripherals/twai.rst b/docs/zh_CN/api-reference/peripherals/twai.rst index e01c230063..33c15ef03c 100644 --- a/docs/zh_CN/api-reference/peripherals/twai.rst +++ b/docs/zh_CN/api-reference/peripherals/twai.rst @@ -311,7 +311,7 @@ TWAI控制器能够检测由于总线干扰产生的/损坏的不符合帧格式 - **被动错误:** 当 TEC 或 REC 中的一个大于或等于 128 时,节点处于被动错误状态。仍可以参与总线通信,但在检测到错误时,只能发送一次 **被动错误标志**。 - **离线:** 当 **TEC** 大于或等于 256 时,节点进入离线状态。离线的节点相当于断开连接,不会对总线产生任何影响。节点将保持离线状态,直到软件触发恢复操作。 -软件可随时使用函数 :cpp:func:`twai_node_get_info` 获取节点状态。或当控制器检测到错误时,会产生 :cpp:member:`twai_event_callbacks_t::on_error` 回调,可通过传参中的错误数据查看错误原因。 +软件可随时在 task 中使用函数 :cpp:func:`twai_node_get_info` 获取节点状态。或当控制器检测到错误时,会产生 :cpp:member:`twai_event_callbacks_t::on_error` 回调,可通过传参中的错误数据查看错误原因。 当错误导致节点状态变化时,会进入 :cpp:member:`twai_event_callbacks_t::on_state_change` 回调,可在回调中查看节点的状态变化。若节点已经离线且需要恢复,需要在task中调用 :cpp:func:`twai_node_recover`。 **但注意,控制器不会立即恢复** ,需要在检测到 129 次连续 11 个隐性位后才会自动重新连接到总线。 From 973c1b4f9a07a45190b6ba28edc17ba6eba6c1c3 Mon Sep 17 00:00:00 2001 From: wanckl Date: Tue, 2 Dec 2025 19:29:20 +0800 Subject: [PATCH 120/156] fix(driver_twai): improve new driver API description --- components/esp_driver_twai/include/esp_twai_types.h | 2 +- docs/en/api-reference/peripherals/twai.rst | 9 +++++++-- docs/zh_CN/api-reference/peripherals/twai.rst | 9 +++++++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/components/esp_driver_twai/include/esp_twai_types.h b/components/esp_driver_twai/include/esp_twai_types.h index 84320545eb..8690153556 100644 --- a/components/esp_driver_twai/include/esp_twai_types.h +++ b/components/esp_driver_twai/include/esp_twai_types.h @@ -42,7 +42,7 @@ typedef struct { twai_error_state_t state; /**< Node's error state */ uint16_t tx_error_count; /**< Node's TX error count */ uint16_t rx_error_count; /**< Node's RX error count */ - uint32_t tx_queue_remaining; /**< Node's TX free queue space */ + uint32_t tx_queue_remaining; /**< Node's TX queue remaining frame space (number of frames) */ } twai_node_status_t; /** diff --git a/docs/en/api-reference/peripherals/twai.rst b/docs/en/api-reference/peripherals/twai.rst index 7d2a08bd64..9badaa7aba 100644 --- a/docs/en/api-reference/peripherals/twai.rst +++ b/docs/en/api-reference/peripherals/twai.rst @@ -103,7 +103,12 @@ TWAI messages come in various types, which are specified by their headers. A typ .. image:: ../../../_static/diagrams/twai/frame_struct.svg :align: center -To reduce performance overhead caused by memory copying, the TWAI driver uses pointers to pass messages. The following code demonstrates how to transmit a typical data frame: +To reduce performance overhead caused by memory copying, the TWAI driver uses pointers to pass messages. The driver is designed to operate in asynchronous mode, so the :cpp:type:`twai_frame_t` structure and the memory pointed to by :cpp:member:`twai_frame_t::buffer` must remain valid until the transmission is actually complete. You can determine when transmission is complete in the following ways: + +- Call the :cpp:func:`twai_node_transmit_wait_all_done` function to wait for all transmissions to complete. +- Register the :cpp:member:`twai_event_callbacks_t::on_tx_done` event callback function to receive a notification when transmission is complete. + +The following code demonstrates how to transmit a typical data frame: .. code:: c @@ -200,7 +205,7 @@ The TWAI driver supports transmitting messages from an Interrupt Service Routine } .. note:: - When calling :cpp:func:`twai_node_transmit` from an ISR, the ``timeout`` parameter is ignored, and the function will not block. If the transmit queue is full, the function will return immediately with an error. It is the application's responsibility to handle cases where the queue is full. + When calling :cpp:func:`twai_node_transmit` from an ISR, the ``timeout`` parameter is ignored, and the function will not block. If the transmit queue is full, the function will return immediately with an error. It is the application's responsibility to handle cases where the queue is full. Similarly, the ``twai_frame_t`` structure and the memory pointed to by ``buffer`` must remain valid until the transmission is complete. You can get the completed frame by the :cpp:member:`twai_tx_done_event_data_t::done_tx_frame` pointer. Bit Timing Customization ------------------------ diff --git a/docs/zh_CN/api-reference/peripherals/twai.rst b/docs/zh_CN/api-reference/peripherals/twai.rst index 33c15ef03c..f7585ab98c 100644 --- a/docs/zh_CN/api-reference/peripherals/twai.rst +++ b/docs/zh_CN/api-reference/peripherals/twai.rst @@ -103,7 +103,12 @@ TWAI 报文有多种类型,由报头指定。一个典型的数据帧报文主 .. image:: ../../../_static/diagrams/twai/frame_struct.svg :align: center -为减少拷贝带来的性能损失,TWAI 驱动使用指针进行传递。以下代码展示了如何发送一条典型的数据帧报文: +为减少拷贝带来的性能损失,TWAI 驱动使用指针进行传递。且驱动设计为异步模式,因此,在传输真正完成之前, :cpp:type:`twai_frame_t` 实体及其 :cpp:member:`twai_frame_t::buffer` 指向的内存必须保持有效。可通过以下方式得知传输完成: + +- 调用 :cpp:func:`twai_node_transmit_wait_all_done` 函数等待所有传输完成。 +- 注册 :cpp:member:`twai_event_callbacks_t::on_tx_done` 事件回调函数,在传输完成时接收通知。 + +以下代码展示了如何发送一条典型的数据帧报文: .. code:: c @@ -200,7 +205,7 @@ TWAI 驱动支持在中断服务程序 (ISR) 中发送报文。这对于需要 } .. note:: - 在 ISR 中调用 :cpp:func:`twai_node_transmit` 时,``timeout`` 参数将被忽略,函数不会阻塞。如果发送队列已满,函数将立即返回错误。应用程序需要自行处理队列已满的情况。 + 在 ISR 中调用 :cpp:func:`twai_node_transmit` 时,``timeout`` 参数将被忽略,函数不会阻塞。如果发送队列已满,函数将立即返回错误。应用程序需要自行处理队列已满的情况。同样,``twai_frame_t`` 及其 ``buffer`` 指向的内存必须在 **该传输** 完成之前保持有效。通过 :cpp:member:`twai_tx_done_event_data_t::done_tx_frame` 指针可得知该次完成的报文。 位时序自定义 ------------- From 9be95156d0a286eedd57ecd5c8c06521d47d9a60 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Thu, 18 Dec 2025 12:16:21 +0100 Subject: [PATCH 121/156] test(freertos): Fix race condition in suspend-resume tests This commit fixes a race condition in suspend-resume tests where in a test task could escape deletion and result in a memory leak after test completion. --- .../test_vTaskSuspendAll_xTaskResumeAll.c | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/components/freertos/test_apps/freertos/kernel/tasks/test_vTaskSuspendAll_xTaskResumeAll.c b/components/freertos/test_apps/freertos/kernel/tasks/test_vTaskSuspendAll_xTaskResumeAll.c index 746540bc02..609fe2e55f 100644 --- a/components/freertos/test_apps/freertos/kernel/tasks/test_vTaskSuspendAll_xTaskResumeAll.c +++ b/components/freertos/test_apps/freertos/kernel/tasks/test_vTaskSuspendAll_xTaskResumeAll.c @@ -227,6 +227,12 @@ TEST_CASE("Test vTaskSuspendAll() and xTaskResumeAll() multicore", "[freertos]") for (int j = 0; j < 2; j++) { xSemaphoreTake(done_sem, portMAX_DELAY); } + + // Suspend the test tasks in case they haven't suspended themselves yet + vTaskSuspend(taskA_hdl); + vTaskSuspend(taskB_hdl); + vTaskDelay(10); + // Cleanup the tasks vTaskDelete(taskA_hdl); vTaskDelete(taskB_hdl); @@ -339,6 +345,8 @@ static void test_unblk_a1_task(void *arg) // Cleanup A2 and interrupt deregister_intr_cb(); + vTaskSuspend(a2_task_hdl); + vTaskDelay(10); vTaskDelete(a2_task_hdl); // Indicate done and wait to be deleted @@ -391,6 +399,11 @@ TEST_CASE("Test vTaskSuspendAll allows scheduling on other cores", "[freertos]") for (int j = 0; j < 2; j++) { xSemaphoreTake(test_unblk_done_sem, portMAX_DELAY); } + // Suspend the test tasks in case they haven't suspended themselves yet + vTaskSuspend(a1_task_hdl); + vTaskSuspend(b1_task_hdl); + vTaskDelay(10); + // Cleanup tasks vTaskDelete(a1_task_hdl); vTaskDelete(b1_task_hdl); @@ -515,6 +528,10 @@ TEST_CASE("Test vTaskSuspendAll doesn't block unpinned tasks from being schedule for (int i = 0; i < 2; i++) { xSemaphoreTake(test_unpinned_sem, portMAX_DELAY); } + // Suspend the test tasks in case they haven't suspended themselves yet + vTaskSuspend(pinned_task_hdl); + vTaskSuspend(unpinned_task_hdl); + vTaskDelay(10); // Cleanup vTaskDelete(pinned_task_hdl); @@ -643,8 +660,9 @@ TEST_CASE("Test xTaskResumeAll resumes pended tasks", "[freertos]") TEST_ASSERT_EQUAL(pdTRUE, xTaskCreatePinnedToCore(test_pended_running_task, "susp", 2048, (void *)xTaskGetCurrentTaskHandle(), UNITY_FREERTOS_PRIORITY + 1, &susp_tsk_hdl, i)); // Wait for to be notified to test completion ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - // Add a short delay to allow the test_pended_running_task to go to suspend state - vTaskDelay(1); + // Suspend the test task in case it hasn't suspended itself yet + vTaskSuspend(susp_tsk_hdl); + vTaskDelay(10); vTaskDelete(susp_tsk_hdl); } // Add a short delay to allow the idle task to free any remaining task memory @@ -759,8 +777,12 @@ TEST_CASE("Test xTaskSuspendAll on all cores pends all tasks and xTaskResumeAll // Cleanup for (int i = 0; i < TEST_PENDED_NUM_BLOCKED_TASKS; i++) { + vTaskSuspend(blkd_tasks[i]); + vTaskDelay(10); vTaskDelete(blkd_tasks[i]); } + vTaskSuspend(susp_task); + vTaskDelay(10); vTaskDelete(susp_task); vSemaphoreDelete(done_sem); } From 131200a1fe770ad80aff7959e9164b0ecf858ab2 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Thu, 18 Dec 2025 16:18:40 +0100 Subject: [PATCH 122/156] test(freertos): Added stability fixes to the delete blocked tasks test --- .../kernel/tasks/test_freertos_task_delete.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/freertos/test_apps/freertos/kernel/tasks/test_freertos_task_delete.c b/components/freertos/test_apps/freertos/kernel/tasks/test_freertos_task_delete.c index 727951210d..4f72ba8a96 100644 --- a/components/freertos/test_apps/freertos/kernel/tasks/test_freertos_task_delete.c +++ b/components/freertos/test_apps/freertos/kernel/tasks/test_freertos_task_delete.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -128,7 +128,8 @@ TEST_CASE("FreeRTOS Delete Blocked Tasks", "[freertos]") (1000 iterations takes about 9 seconds on ESP32 dual core) */ - for (unsigned iter = 0; iter < 1000; iter++) { + unsigned iter = 0; + for (iter = 0; iter < 1000; iter++) { // Create everything SemaphoreHandle_t sem = xSemaphoreCreateMutex(); for (unsigned i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES + 1; i++) { @@ -144,14 +145,24 @@ TEST_CASE("FreeRTOS Delete Blocked Tasks", "[freertos]") vTaskDelay(5); // Let the tasks juggle the mutex for a bit for (unsigned i = 0; i < CONFIG_FREERTOS_NUMBER_OF_CORES + 1; i++) { + vTaskSuspend(blocking_tasks[i]); vTaskDelete(blocking_tasks[i]); params[i].deleted = true; } vTaskDelay(4); // Yield to the idle task for cleanup + // As an experiment, until IDFCI-4988 is fixed (CI runner loses connection to the target) + // let's occasionally print a message to the console to ensure the test is running + // and keep the console active. + if (iter && iter % 100 == 0) { + // In each iteration, we create CONFIG_FREERTOS_NUMBER_OF_CORES + 1 tasks + printf("Deleted %u blocked tasks\n", iter * (CONFIG_FREERTOS_NUMBER_OF_CORES + 1)); + } + vSemaphoreDelete(sem); // Check we haven't leaked resources yet TEST_ASSERT_GREATER_OR_EQUAL(before - 256, heap_caps_get_free_size(MALLOC_CAP_8BIT)); } + printf("Deleted %u blocked tasks\n", iter * (CONFIG_FREERTOS_NUMBER_OF_CORES + 1)); } From b652c1a5e885cdfc223b63a52cd05e8cbb22910d Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 18 Nov 2025 18:56:46 +0800 Subject: [PATCH 123/156] refactor(gdma): skip the null buffer in mount pre-check --- components/esp_hw_support/dma/gdma_link.c | 45 +++++++++++++++-------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/components/esp_hw_support/dma/gdma_link.c b/components/esp_hw_support/dma/gdma_link.c index 1011abb224..cc861e0aca 100644 --- a/components/esp_hw_support/dma/gdma_link.c +++ b/components/esp_hw_support/dma/gdma_link.c @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include "soc/soc_caps.h" #include "esp_log.h" @@ -74,6 +76,8 @@ esp_err_t gdma_new_link_list(const gdma_link_list_config_t *config, gdma_link_li size_t item_alignment = config->item_alignment ? config->item_alignment : 4; // each list item should align to the specified alignment size_t item_size = ALIGN_UP(sizeof(gdma_link_list_item_t), item_alignment); + // guard against overflow when calculating total bytes for descriptors + ESP_GOTO_ON_FALSE(num_items <= SIZE_MAX / item_size, ESP_ERR_INVALID_SIZE, err, TAG, "list too big"); uint32_t list_items_mem_caps = MALLOC_CAP_8BIT | MALLOC_CAP_DMA; if (config->flags.items_in_ext_mem) { @@ -130,14 +134,13 @@ esp_err_t gdma_del_link_list(gdma_link_list_handle_t list) esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_index, const gdma_buffer_mount_config_t *buf_config_array, size_t num_buf, int *end_item_index) { - if(!list || !buf_config_array || !num_buf) { + if (!list || !buf_config_array || !num_buf) { return ESP_ERR_INVALID_ARG; } size_t item_size = list->item_size; uint32_t list_item_capacity = list->num_items; // ensure the start_item_index is between 0 and `list_item_capacity - 1` start_item_index = (start_item_index % list_item_capacity + list_item_capacity) % list_item_capacity; - uint32_t begin_item_idx = start_item_index; gdma_link_list_item_t *lli_nc = NULL; uint32_t num_items_avail = 0; @@ -147,6 +150,9 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i lli_nc = (gdma_link_list_item_t *)(list->items_nc + (i + start_item_index) % list_item_capacity * item_size); if (lli_nc->dw0.owner == GDMA_LLI_OWNER_CPU) { num_items_avail++; + } else { + // if the DMA descriptor "write back" feature is not enabled, descriptor is always owned by DMA after being used + break; } } } else { @@ -154,31 +160,36 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i } // check alignment and length for each buffer + uint32_t remaining = num_items_avail; for (size_t bi = 0; bi < num_buf; bi++) { const gdma_buffer_mount_config_t *config = &buf_config_array[bi]; uint8_t *buf = (uint8_t *)config->buffer; size_t len = config->length; + // zero-length/NULL buffers don't consume a slot in pre-check + if (len == 0 || buf == NULL) { + continue; + } size_t buffer_alignment = config->buffer_alignment; if (buffer_alignment == 0) { buffer_alignment = 1; } - // check the buffer alignment - ESP_RETURN_ON_FALSE_ISR((buffer_alignment & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "invalid buffer alignment: %"PRIu32"", buffer_alignment); + // alignment must be a power of 2 + ESP_RETURN_ON_FALSE_ISR((buffer_alignment & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "align err idx=%"PRIu32" align=%"PRIu32, bi, buffer_alignment); size_t max_buffer_mount_length = ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, buffer_alignment); if (!config->flags.bypass_buffer_align_check) { - ESP_RETURN_ON_FALSE_ISR(((uintptr_t)buf & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buffer not aligned to %"PRIu32"", buffer_alignment); + ESP_RETURN_ON_FALSE_ISR(((uintptr_t)buf & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buf misalign idx=%"PRIu32" align=%"PRIu32, bi, buffer_alignment); } - uint32_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length; - // check if there are enough link list items - ESP_RETURN_ON_FALSE_ISR((begin_item_idx + num_items_need) <= (start_item_index + num_items_avail), ESP_ERR_INVALID_ARG, TAG, "no more space for buffer mounting"); - begin_item_idx += num_items_need; + size_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length; + ESP_RETURN_ON_FALSE_ISR(num_items_need <= remaining, ESP_ERR_INVALID_ARG, TAG, + "lli full start=%d need=%"PRIu32" avail=%"PRIu32, start_item_index, num_items_need, remaining); + remaining -= num_items_need; } // link_nodes[start_item_index-1] --> link_nodes[start_item_index] lli_nc = (gdma_link_list_item_t *)(list->items_nc + (start_item_index + list_item_capacity - 1) % list_item_capacity * item_size); lli_nc->next = (gdma_link_list_item_t *)(list->items + start_item_index * item_size); - begin_item_idx = start_item_index; + int begin_item_idx = start_item_index; for (size_t bi = 0; bi < num_buf; bi++) { const gdma_buffer_mount_config_t *config = &buf_config_array[bi]; uint8_t *buf = (uint8_t *)config->buffer; @@ -188,13 +199,16 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i buffer_alignment = 1; } size_t max_buffer_mount_length = ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, buffer_alignment); - // skip zero-length buffer + // skip zero-length buffer but scrub any stale descriptor to keep ring clean; no slot consumption if (len == 0 || buf == NULL) { + lli_nc = (gdma_link_list_item_t *)(list->items_nc + begin_item_idx % list_item_capacity * item_size); + // reset the descriptor, especially the owner and next fields + memset(lli_nc, 0, item_size); continue; } - uint32_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length; + size_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length; // mount the buffer to the link list - for (int i = 0; i < num_items_need; i++) { + for (size_t i = 0; i < num_items_need; i++) { lli_nc = (gdma_link_list_item_t *)(list->items_nc + (i + begin_item_idx) % list_item_capacity * item_size); lli_nc->buffer = buf; lli_nc->dw0.length = len > max_buffer_mount_length ? max_buffer_mount_length : len; @@ -207,6 +221,7 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i if ((config->flags.mark_final == 1) && (i == num_items_need - 1)) { lli_nc->next = NULL; } else { + // DMA expects cached addresses in `next` lli_nc->next = (gdma_link_list_item_t *)(list->items + (i + begin_item_idx + 1) % list_item_capacity * item_size); } lli_nc->dw0.owner = GDMA_LLI_OWNER_DMA; @@ -233,7 +248,7 @@ uintptr_t gdma_link_get_head_addr(gdma_link_list_handle_t list) esp_err_t gdma_link_concat(gdma_link_list_handle_t first_link, int first_link_item_index, gdma_link_list_handle_t second_link, int second_link_item_index) { - if(!(first_link && second_link)) { + if (!(first_link && second_link)) { return ESP_ERR_INVALID_ARG; } gdma_link_list_item_t *lli_nc = NULL; @@ -264,7 +279,7 @@ esp_err_t gdma_link_set_owner(gdma_link_list_handle_t list, int item_index, gdma esp_err_t gdma_link_get_owner(gdma_link_list_handle_t list, int item_index, gdma_lli_owner_t *owner) { - if(!list || !owner) { + if (!list || !owner) { return ESP_ERR_INVALID_ARG; } int num_items = list->num_items; From 798ec369ce29bbfd3acbe019f62bd9211b0c3d72 Mon Sep 17 00:00:00 2001 From: morris Date: Fri, 19 Dec 2025 12:14:29 +0800 Subject: [PATCH 124/156] fix(drivers): enlarge the default DMA burst size in peripheral drivers --- components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c | 2 +- components/esp_driver_parlio/src/parlio_tx.c | 2 +- components/esp_driver_spi/src/gpspi/spi_common.c | 2 +- components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c index 65b2794c33..8c36e4742f 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c @@ -101,7 +101,7 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_ ESP_GOTO_ON_ERROR(gdma_apply_strategy(dma->dma_chan, &strategy_config), fail1, TAG, "apply strategy failed"); // set DMA transfer ability gdma_transfer_config_t transfer_config = { - .max_data_burst_size = burst_size, + .max_data_burst_size = burst_size ? burst_size : 32, // Enable DMA burst transfer for better performance .access_ext_mem = true, }; ESP_GOTO_ON_ERROR(gdma_config_transfer(dma->dma_chan, &transfer_config), fail1, TAG, "set trans ability failed"); diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index baf1d295c7..3734e3529e 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -174,7 +174,7 @@ static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit, const parlio // configure DMA transfer parameters gdma_transfer_config_t trans_cfg = { - .max_data_burst_size = config->dma_burst_size ? config->dma_burst_size : 16, // Enable DMA burst transfer for better performance, + .max_data_burst_size = config->dma_burst_size ? config->dma_burst_size : 32, // Enable DMA burst transfer for better performance, .access_ext_mem = true, // support transmit PSRAM buffer }; ESP_RETURN_ON_ERROR(gdma_config_transfer(tx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index 92973a6694..92c420f26d 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -256,7 +256,7 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch #endif // TODO: add support to allow SPI transfer PSRAM buffer gdma_transfer_config_t trans_cfg = { - .max_data_burst_size = 16, + .max_data_burst_size = 32, .access_ext_mem = false, }; ESP_RETURN_ON_ERROR(gdma_config_transfer(dma_ctx->tx_dma_chan, &trans_cfg), SPI_TAG, "config gdma tx transfer failed"); diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index f0ffb1b1a4..9aa8187ec6 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -618,7 +618,7 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_l gdma_apply_strategy(bus->dma_chan, &strategy_config); // config DMA transfer parameters gdma_transfer_config_t trans_cfg = { - .max_data_burst_size = bus_config->dma_burst_size ? bus_config->dma_burst_size : 16, // Enable DMA burst transfer for better performance + .max_data_burst_size = bus_config->dma_burst_size ? bus_config->dma_burst_size : 32, // Enable DMA burst transfer for better performance .access_ext_mem = true, // the LCD can carry pixel buffer from the external memory }; ESP_RETURN_ON_ERROR(gdma_config_transfer(bus->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); From 08b3edc0a679a084f1317b790f4af3277d05b23d Mon Sep 17 00:00:00 2001 From: hebinglin Date: Wed, 19 Nov 2025 16:20:38 +0800 Subject: [PATCH 125/156] fix(esp_hw_support): fix flash cs unhold during sleep when pd top in esp32h2 --- components/esp_hw_support/sleep_modes.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 391a7d4063..f075046e35 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -904,10 +904,8 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) { #if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND /* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */ -#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359 gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS0); #endif -#endif #if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM /* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */ gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS1); @@ -961,10 +959,8 @@ static esp_err_t FORCE_IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint /* Unhold the SPI CS pin */ if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) { #if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND -#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359 gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS0); #endif -#endif #if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS1); #endif From 707147fe57c5f57d40ef0192e291e2a71bdb7d1b Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 1 Dec 2025 11:53:42 +0800 Subject: [PATCH 126/156] fix(i2c_master): Add i2c master timeout range check Closes https://github.com/espressif/esp-idf/issues/17930 --- components/esp_driver_i2c/i2c_master.c | 17 +++++++++++++++++ components/hal/esp32/include/hal/i2c_ll.h | 2 ++ components/hal/esp32c2/include/hal/i2c_ll.h | 2 ++ components/hal/esp32c3/include/hal/i2c_ll.h | 2 ++ components/hal/esp32c5/include/hal/i2c_ll.h | 2 ++ components/hal/esp32c6/include/hal/i2c_ll.h | 2 ++ components/hal/esp32c61/include/hal/i2c_ll.h | 2 ++ components/hal/esp32h2/include/hal/i2c_ll.h | 2 ++ components/hal/esp32h21/include/hal/i2c_ll.h | 2 ++ components/hal/esp32p4/include/hal/i2c_ll.h | 2 ++ components/hal/esp32s2/include/hal/i2c_ll.h | 2 ++ components/hal/esp32s3/include/hal/i2c_ll.h | 2 ++ 12 files changed, 39 insertions(+) diff --git a/components/esp_driver_i2c/i2c_master.c b/components/esp_driver_i2c/i2c_master.c index 162042c701..918984d7ac 100644 --- a/components/esp_driver_i2c/i2c_master.c +++ b/components/esp_driver_i2c/i2c_master.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include "esp_rom_sys.h" @@ -664,6 +665,16 @@ static void s_i2c_send_command_async(i2c_master_bus_handle_t i2c_master, BaseTyp i2c_hal_master_trans_start(hal); } +static inline bool s_i2c_timeout_range_check(uint32_t *timeout_us, uint32_t sclk_clock_hz) +{ + uint32_t max_timeout_us = (I2C_LL_MAX_TIMEOUT_PERIOD * 1000000ULL) / sclk_clock_hz; + if (*timeout_us > max_timeout_us) { + *timeout_us = max_timeout_us; + return true; + } + return false; +} + static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xfer_timeout_ms) { i2c_master_bus_handle_t i2c_master = i2c_dev->master_bus; @@ -692,6 +703,7 @@ static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xf } // Set the timeout value + bool timeout_range_exceeded = s_i2c_timeout_range_check(&i2c_dev->scl_wait_us, i2c_master->base->clk_src_freq_hz); i2c_hal_master_set_scl_timeout_val(hal, i2c_dev->scl_wait_us, i2c_master->base->clk_src_freq_hz); i2c_ll_master_set_fractional_divider(hal->dev, 0, 0); @@ -701,6 +713,11 @@ static esp_err_t s_i2c_transaction_start(i2c_master_dev_handle_t i2c_dev, int xf i2c_ll_rxfifo_rst(hal->dev); i2c_ll_enable_intr_mask(hal->dev, I2C_LL_MASTER_EVENT_INTR); portEXIT_CRITICAL(&i2c_master->base->spinlock); + + if (timeout_range_exceeded) { + ESP_LOGW(TAG, "Timeout value exceeds the maximum supported value, rounded down to maximum supported value: %" PRIu32 " us", i2c_dev->scl_wait_us); + } + if (i2c_master->async_trans == true) { s_i2c_send_command_async(i2c_master, NULL); } else { diff --git a/components/hal/esp32/include/hal/i2c_ll.h b/components/hal/esp32/include/hal/i2c_ll.h index 0e49866be7..de9bb8be5c 100644 --- a/components/hal/esp32/include/hal/i2c_ll.h +++ b/components/hal/esp32/include/hal/i2c_ll.h @@ -890,6 +890,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_FULL_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0xffff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32c2/include/hal/i2c_ll.h b/components/hal/esp32c2/include/hal/i2c_ll.h index b5a02817af..28f721c65c 100644 --- a/components/hal/esp32c2/include/hal/i2c_ll.h +++ b/components/hal/esp32c2/include/hal/i2c_ll.h @@ -815,6 +815,8 @@ static inline uint32_t i2c_ll_calculate_timeout_us_to_reg_val(uint32_t src_clk_h #define I2C_LL_MASTER_RX_INT (I2C_TIME_OUT_INT_ENA_M|I2C_TRANS_COMPLETE_INT_ENA_M|I2C_ARBITRATION_LOST_INT_ENA_M|I2C_END_DETECT_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (1UL << I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32c3/include/hal/i2c_ll.h b/components/hal/esp32c3/include/hal/i2c_ll.h index 687ea77e6b..f3067b09ba 100644 --- a/components/hal/esp32c3/include/hal/i2c_ll.h +++ b/components/hal/esp32c3/include/hal/i2c_ll.h @@ -1000,6 +1000,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (1UL << I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0xffff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32c5/include/hal/i2c_ll.h b/components/hal/esp32c5/include/hal/i2c_ll.h index 73d8be5a36..164e1a4a8f 100644 --- a/components/hal/esp32c5/include/hal/i2c_ll.h +++ b/components/hal/esp32c5/include/hal/i2c_ll.h @@ -1039,6 +1039,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (1UL << I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32c6/include/hal/i2c_ll.h b/components/hal/esp32c6/include/hal/i2c_ll.h index 49da17be0d..056f6372e3 100644 --- a/components/hal/esp32c6/include/hal/i2c_ll.h +++ b/components/hal/esp32c6/include/hal/i2c_ll.h @@ -1040,6 +1040,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (1UL << I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32c61/include/hal/i2c_ll.h b/components/hal/esp32c61/include/hal/i2c_ll.h index 5e50d96967..2445f7d357 100644 --- a/components/hal/esp32c61/include/hal/i2c_ll.h +++ b/components/hal/esp32c61/include/hal/i2c_ll.h @@ -951,6 +951,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (1UL << I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32h2/include/hal/i2c_ll.h b/components/hal/esp32h2/include/hal/i2c_ll.h index e0e8334f93..8d88976952 100644 --- a/components/hal/esp32h2/include/hal/i2c_ll.h +++ b/components/hal/esp32h2/include/hal/i2c_ll.h @@ -948,6 +948,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (1UL << I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32h21/include/hal/i2c_ll.h b/components/hal/esp32h21/include/hal/i2c_ll.h index 903a77fec6..f4302c1329 100644 --- a/components/hal/esp32h21/include/hal/i2c_ll.h +++ b/components/hal/esp32h21/include/hal/i2c_ll.h @@ -946,6 +946,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (1UL << I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32p4/include/hal/i2c_ll.h b/components/hal/esp32p4/include/hal/i2c_ll.h index 37fb6e1038..71a00cd702 100644 --- a/components/hal/esp32p4/include/hal/i2c_ll.h +++ b/components/hal/esp32p4/include/hal/i2c_ll.h @@ -1071,6 +1071,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (1UL << I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32s2/include/hal/i2c_ll.h b/components/hal/esp32s2/include/hal/i2c_ll.h index 2f9febeb9c..98b6e0f509 100644 --- a/components/hal/esp32s2/include/hal/i2c_ll.h +++ b/components/hal/esp32s2/include/hal/i2c_ll.h @@ -956,6 +956,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0x1ffff) /*!< I2C all interrupt bitmap */ diff --git a/components/hal/esp32s3/include/hal/i2c_ll.h b/components/hal/esp32s3/include/hal/i2c_ll.h index 5a96009d14..8202a9cfc7 100644 --- a/components/hal/esp32s3/include/hal/i2c_ll.h +++ b/components/hal/esp32s3/include/hal/i2c_ll.h @@ -1004,6 +1004,8 @@ static inline i2c_slave_read_write_status_t i2c_ll_slave_get_read_write_status(i #define I2C_LL_SLAVE_RX_INT (I2C_RXFIFO_WM_INT_ENA_M | I2C_TRANS_COMPLETE_INT_ENA_M) // I2C max timeout value #define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_VALUE_V +// I2C max timeout period in clock cycles +#define I2C_LL_MAX_TIMEOUT_PERIOD (1UL << I2C_LL_MAX_TIMEOUT) #define I2C_LL_INTR_MASK (0x3fff) /*!< I2C all interrupt bitmap */ From cb9acbdd21c4af5a0cbd19e3bb603f5f3d4b7a8b Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Fri, 12 Dec 2025 12:27:18 +0530 Subject: [PATCH 127/156] fix(secure_boot): Application's Secure Boot verify API support ECDSA-P384 --- .../secure_boot_v2/secure_boot_ecdsa_signature.c | 13 ++++++++++++- .../esp_rom/esp32c5/include/esp32c5/rom/ecdsa.h | 5 +++-- .../esp_rom/esp32p4/include/esp32p4/rom/ecdsa.h | 8 +++++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/components/bootloader_support/src/secure_boot_v2/secure_boot_ecdsa_signature.c b/components/bootloader_support/src/secure_boot_v2/secure_boot_ecdsa_signature.c index f0996e4059..12c7ce7492 100644 --- a/components/bootloader_support/src/secure_boot_v2/secure_boot_ecdsa_signature.c +++ b/components/bootloader_support/src/secure_boot_v2/secure_boot_ecdsa_signature.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,12 +13,17 @@ #include "mbedtls/ctr_drbg.h" #include "mbedtls/ecp.h" #include "rom/ecdsa.h" +#include "sdkconfig.h" #include "secure_boot_signature_priv.h" static const char *TAG = "secure_boot_v2_ecdsa"; +#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS +#define ECDSA_INTEGER_LEN 48 +#else #define ECDSA_INTEGER_LEN 32 +#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */ esp_err_t verify_ecdsa_signature_block(const ets_secure_boot_signature_t *sig_block, const uint8_t *image_digest, const ets_secure_boot_sig_block_t *trusted_block) { @@ -48,6 +53,12 @@ esp_err_t verify_ecdsa_signature_block(const ets_secure_boot_signature_t *sig_bl key_size = 32; mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1); break; +#if CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS + case ECDSA_CURVE_P384: + key_size = 48; + mbedtls_ecp_group_load(&ecdsa_context.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP384R1); + break; +#endif /* CONFIG_SECURE_BOOT_ECDSA_KEY_LEN_384_BITS */ default: ESP_LOGE(TAG, "Invalid curve ID"); return ESP_ERR_INVALID_ARG; diff --git a/components/esp_rom/esp32c5/include/esp32c5/rom/ecdsa.h b/components/esp_rom/esp32c5/include/esp32c5/rom/ecdsa.h index 3a700b4e29..7a2346be30 100644 --- a/components/esp_rom/esp32c5/include/esp32c5/rom/ecdsa.h +++ b/components/esp_rom/esp32c5/include/esp32c5/rom/ecdsa.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,7 +12,8 @@ extern "C" { #endif -#define ETS_DIGEST_LEN 32 /* SHA-256, bytes */ +#define ETS_DIGEST_SHA256_LEN 32 /* SHA-256, bytes */ +#define ETS_DIGEST_SHA384_LEN 48 /* SHA-384, bytes */ typedef enum { ECDSA_CURVE_P192 = 1, diff --git a/components/esp_rom/esp32p4/include/esp32p4/rom/ecdsa.h b/components/esp_rom/esp32p4/include/esp32p4/rom/ecdsa.h index 6b7313a00b..cc23b3188f 100644 --- a/components/esp_rom/esp32p4/include/esp32p4/rom/ecdsa.h +++ b/components/esp_rom/esp32p4/include/esp32p4/rom/ecdsa.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,11 +12,13 @@ extern "C" { #endif -#define ETS_DIGEST_LEN 32 /* SHA-256, bytes */ +#define ETS_DIGEST_SHA256_LEN 32 /* SHA-256, bytes */ +#define ETS_DIGEST_SHA384_LEN 48 /* SHA-384, bytes */ typedef enum { ECDSA_CURVE_P192 = 1, - ECDSA_CURVE_P256 = 2 + ECDSA_CURVE_P256 = 2, + ECDSA_CURVE_P384 = 3 } ECDSA_CURVE; int ets_ecdsa_verify(const uint8_t *key, const uint8_t *sig, ECDSA_CURVE curve_id, const uint8_t *digest, uint8_t *verified_digest); From af61a3e6b64b08179c12036b6ab621dfeaf7d2a5 Mon Sep 17 00:00:00 2001 From: armando Date: Mon, 22 Dec 2025 18:20:00 +0800 Subject: [PATCH 128/156] fix(sdmmc): fixed header structure not shown in doc issue --- docs/doxygen/Doxyfile | 4 ++++ docs/doxygen/Doxyfile_esp32p4 | 2 -- docs/en/api-reference/peripherals/sdmmc_host.rst | 8 ++++++-- docs/en/api-reference/storage/sdmmc.rst | 2 ++ docs/zh_CN/api-reference/peripherals/sdmmc_host.rst | 8 ++++++-- docs/zh_CN/api-reference/storage/sdmmc.rst | 2 ++ 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index a81b73bb74..ebf51a92b2 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -271,6 +271,7 @@ INPUT = \ $(PROJECT_PATH)/components/hal/include/hal/efuse_hal.h \ $(PROJECT_PATH)/components/hal/include/hal/eth_types.h \ $(PROJECT_PATH)/components/hal/include/hal/lp_core_types.h \ + $(PROJECT_PATH)/components/hal/include/hal/sd_types.h \ $(PROJECT_PATH)/components/hal/include/hal/uhci_types.h \ $(PROJECT_PATH)/components/heap/include/esp_heap_caps_init.h \ $(PROJECT_PATH)/components/heap/include/esp_heap_caps.h \ @@ -310,6 +311,9 @@ INPUT = \ $(PROJECT_PATH)/components/protocomm/include/transports/protocomm_httpd.h \ $(PROJECT_PATH)/components/protocomm/include/crypto/srp6a/esp_srp.h \ $(PROJECT_PATH)/components/pthread/include/esp_pthread.h \ + $(PROJECT_PATH)/components/sdmmc/include/sd_protocol_types.h \ + $(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl.h \ + $(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl_by_on_chip_ldo.h \ $(PROJECT_PATH)/components/sdmmc/include/sdmmc_cmd.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/adc_channel.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/clk_tree_defs.h \ diff --git a/docs/doxygen/Doxyfile_esp32p4 b/docs/doxygen/Doxyfile_esp32p4 index bf64bf8cb7..7e3d14a9fd 100644 --- a/docs/doxygen/Doxyfile_esp32p4 +++ b/docs/doxygen/Doxyfile_esp32p4 @@ -55,6 +55,4 @@ INPUT += \ $(PROJECT_PATH)/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h \ $(PROJECT_PATH)/components/esp_lcd/rgb/include/esp_lcd_panel_rgb.h \ $(PROJECT_PATH)/components/soc/$(IDF_TARGET)/include/soc/bitscrambler_peri_select.h \ - $(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl.h \ - $(PROJECT_PATH)/components/sdmmc/include/sd_pwr_ctrl_by_on_chip_ldo.h \ $(PROJECT_PATH)/components/ulp/lp_core/shared/include/ulp_lp_core_lp_uart_shared.h \ diff --git a/docs/en/api-reference/peripherals/sdmmc_host.rst b/docs/en/api-reference/peripherals/sdmmc_host.rst index 64160b824a..76ea45e2df 100644 --- a/docs/en/api-reference/peripherals/sdmmc_host.rst +++ b/docs/en/api-reference/peripherals/sdmmc_host.rst @@ -176,8 +176,8 @@ To configure the bus width, set the ``width`` field of :cpp:class:`sdmmc_slot_co If the design does require higher speed SD modes (which only work at 1.8V IO levels), there are two options available: - - Use the on-chip programmable LDO. In this case, connect the desired LDO output channel to VDDPST_5 (SD_VREF) pin. Call :cpp:func:`sd_pwr_ctrl_new_on_chip_ldo` to initialize the SD power control driver, then set :cpp:class:`sdmmc_host_t::pwr_ctrl_handle` to the resulting handle. - - Use an external programmable LDO. Likewise, connect the LDO output to the VDDPST_5 (SD_VREF) pin. Then implement a custom `sd_pwr_ctrl` driver to control your LDO. Finally, assign :cpp:class:`sdmmc_host_t::pwr_ctrl_handle` to the handle of your driver instance. + - Use the on-chip programmable LDO. In this case, connect the desired LDO output channel to VDDPST_5 (SD_VREF) pin. Call :cpp:func:`sd_pwr_ctrl_new_on_chip_ldo` to initialize the SD power control driver, then set :cpp:member:`sdmmc_host_t::pwr_ctrl_handle` to the resulting handle. + - Use an external programmable LDO. Likewise, connect the LDO output to the VDDPST_5 (SD_VREF) pin. Then implement a custom `sd_pwr_ctrl` driver to control your LDO. Finally, assign :cpp:member:`sdmmc_host_t::pwr_ctrl_handle` to the handle of your driver instance. DDR Mode for eMMC Chips @@ -209,3 +209,7 @@ API Reference ------------- .. include-build-file:: inc/sdmmc_host.inc + +.. include-build-file:: inc/sd_pwr_ctrl.inc + +.. include-build-file:: inc/sd_pwr_ctrl_by_on_chip_ldo.inc diff --git a/docs/en/api-reference/storage/sdmmc.rst b/docs/en/api-reference/storage/sdmmc.rst index f90ba43625..1902d072fe 100644 --- a/docs/en/api-reference/storage/sdmmc.rst +++ b/docs/en/api-reference/storage/sdmmc.rst @@ -130,4 +130,6 @@ API Reference .. include-build-file:: inc/sdmmc_cmd.inc +.. include-build-file:: inc/sd_protocol_types.inc + .. include-build-file:: inc/sdmmc_types.inc diff --git a/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst b/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst index 53e81d8ab7..4fcf9a5b29 100644 --- a/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst +++ b/docs/zh_CN/api-reference/peripherals/sdmmc_host.rst @@ -176,8 +176,8 @@ SDMMC 主机驱动支持以下速率模式: 如果设计需要更高速度的 SD 模式(仅在 1.8 V IO 电平下工作),则有两种可选方案: - - 使用片上可编程 LDO。将所需的 LDO 输出通道连接到 VDDPST_5 (SD_VREF) 管脚上,并调用 :cpp:func:`sd_pwr_ctrl_new_on_chip_ldo` 来初始化 SD 电源控制驱动。最后,将 :cpp:class:`sdmmc_host_t::pwr_ctl_handle` 设置为生成句柄。 - - 使用外部可编程 LDO。同样,将 LDO 输出连接到 VDDPST_5 (SD_VREF) 管脚,并自定义 `sd_pwr_ctrl` 驱动程序来控制 LDO。最后,将 :cpp:class:`sdmmc_host_t::pwr_ctrl_handle` 分配给驱动程序实例句柄。 + - 使用片上可编程 LDO。将所需的 LDO 输出通道连接到 VDDPST_5 (SD_VREF) 管脚上,并调用 :cpp:func:`sd_pwr_ctrl_new_on_chip_ldo` 来初始化 SD 电源控制驱动。最后,将 :cpp:member:`sdmmc_host_t::pwr_ctl_handle` 设置为生成句柄。 + - 使用外部可编程 LDO。同样,将 LDO 输出连接到 VDDPST_5 (SD_VREF) 管脚,并自定义 `sd_pwr_ctrl` 驱动程序来控制 LDO。最后,将 :cpp:member:`sdmmc_host_t::pwr_ctrl_handle` 分配给驱动程序实例句柄。 eMMC 芯片的 DDR 模式 @@ -209,3 +209,7 @@ API 参考 ------------- .. include-build-file:: inc/sdmmc_host.inc + +.. include-build-file:: inc/sd_pwr_ctrl.inc + +.. include-build-file:: inc/sd_pwr_ctrl_by_on_chip_ldo.inc diff --git a/docs/zh_CN/api-reference/storage/sdmmc.rst b/docs/zh_CN/api-reference/storage/sdmmc.rst index fa23ff479a..7d4d7b5fcf 100644 --- a/docs/zh_CN/api-reference/storage/sdmmc.rst +++ b/docs/zh_CN/api-reference/storage/sdmmc.rst @@ -130,4 +130,6 @@ API 参考 .. include-build-file:: inc/sdmmc_cmd.inc +.. include-build-file:: inc/sd_protocol_types.inc + .. include-build-file:: inc/sdmmc_types.inc From d4defb6ef97933fb7f8f85a0899fee1f954966e2 Mon Sep 17 00:00:00 2001 From: Tan Yan Quan Date: Thu, 4 Dec 2025 11:17:24 +0800 Subject: [PATCH 129/156] feat(openthread): update OT upstream to a12ff0d0f --- components/openthread/CMakeLists.txt | 5 +++++ components/openthread/openthread | 2 +- components/openthread/sbom_openthread.yml | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index 54e8f99d8a..faa68c2ac9 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -102,6 +102,7 @@ if(CONFIG_OPENTHREAD_ENABLED) "openthread/src/core/thread/announce_begin_server.cpp" "openthread/src/core/thread/announce_sender.cpp" "openthread/src/core/thread/address_resolver.cpp" + "openthread/src/core/thread/child.cpp" "openthread/src/core/thread/child_supervision.cpp" "openthread/src/core/thread/csl_tx_scheduler.cpp" "openthread/src/core/thread/discover_scanner.cpp" @@ -115,6 +116,8 @@ if(CONFIG_OPENTHREAD_ENABLED) "openthread/src/core/thread/mesh_forwarder_mtd.cpp" "openthread/src/core/thread/message_framer.cpp" "openthread/src/core/thread/mle.cpp" + "openthread/src/core/thread/mle_ftd.cpp" + "openthread/src/core/thread/mle_p2p.cpp" "openthread/src/core/thread/mle_router.cpp" "openthread/src/core/thread/mle_types.cpp" "openthread/src/core/thread/neighbor.cpp" @@ -125,7 +128,9 @@ if(CONFIG_OPENTHREAD_ENABLED) "openthread/src/core/thread/network_data_types.cpp" "openthread/src/core/thread/network_data_service.cpp" "openthread/src/core/thread/network_diagnostic.cpp" + "openthread/src/core/thread/network_diagnostic_tlvs.cpp" "openthread/src/core/thread/panid_query_server.cpp" + "openthread/src/core/thread/router.cpp" "openthread/src/core/thread/thread_netif.cpp" "openthread/src/core/thread/time_sync_service.cpp" "openthread/src/core/thread/tmf.cpp" diff --git a/components/openthread/openthread b/components/openthread/openthread index 36b14d3ef7..a12ff0d0f5 160000 --- a/components/openthread/openthread +++ b/components/openthread/openthread @@ -1 +1 @@ -Subproject commit 36b14d3ef74f5e37e5be8902e1c1955a642fdfbf +Subproject commit a12ff0d0f54fd41954b45047fcdd08f302731c5f diff --git a/components/openthread/sbom_openthread.yml b/components/openthread/sbom_openthread.yml index 74398658c6..8e476b6bfd 100644 --- a/components/openthread/sbom_openthread.yml +++ b/components/openthread/sbom_openthread.yml @@ -5,4 +5,4 @@ supplier: 'Organization: Espressif Systems (Shanghai) CO LTD' originator: 'Organization: Google LLC' description: OpenThread released by Google is an open-source implementation of the Thread networking url: https://github.com/espressif/openthread -hash: 36b14d3ef74f5e37e5be8902e1c1955a642fdfbf +hash: a12ff0d0f54fd41954b45047fcdd08f302731c5f From 5d7ca541098786d249899d65f028ea8769046771 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Tue, 23 Dec 2025 15:41:37 +0800 Subject: [PATCH 130/156] feat(openthread): add message pool deinitialization --- .../src/port/esp_openthread_messagepool.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/components/openthread/src/port/esp_openthread_messagepool.c b/components/openthread/src/port/esp_openthread_messagepool.c index 0e0794dc8a..17761b5061 100644 --- a/components/openthread/src/port/esp_openthread_messagepool.c +++ b/components/openthread/src/port/esp_openthread_messagepool.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +14,7 @@ int s_buffer_pool_head = -1; otMessageBuffer **s_buffer_pool_pointer = NULL; +otMessageBuffer *s_buffer_pool = NULL; void otPlatMessagePoolInit(otInstance *aInstance, uint16_t aMinNumFreeBuffers, size_t aBufferSize) { @@ -27,6 +28,7 @@ void otPlatMessagePoolInit(otInstance *aInstance, uint16_t aMinNumFreeBuffers, s s_buffer_pool_pointer[i] = buffer_pool + i * aBufferSize / sizeof(otMessageBuffer); } s_buffer_pool_head = aMinNumFreeBuffers - 1; + s_buffer_pool = buffer_pool; ESP_LOGI(OT_PLAT_LOG_TAG, "Create message buffer pool successfully, size %d", aMinNumFreeBuffers*aBufferSize); } @@ -50,3 +52,16 @@ uint16_t otPlatMessagePoolNumFreeBuffers(otInstance *aInstance) { return s_buffer_pool_head + 1; } + +void otPlatMessagePoolDeinit(otInstance *aInstance) +{ + if (s_buffer_pool_pointer != NULL) { + heap_caps_free(s_buffer_pool_pointer); + s_buffer_pool_pointer = NULL; + } + if (s_buffer_pool != NULL) { + heap_caps_free(s_buffer_pool); + s_buffer_pool = NULL; + } + s_buffer_pool_head = -1; +} From 6435473cd450fcee138ab0ffc16c17e51bb5ad19 Mon Sep 17 00:00:00 2001 From: Tan Yan Quan Date: Wed, 24 Dec 2025 08:42:25 +0000 Subject: [PATCH 131/156] feat(openthread/lib): update thread-lib for upstream a12ff0d0f * esp-openthread: thread_zigbee/esp-openthread@77b4edfd8 * openthread: espressif/openthread@a12ff0d0f * esp-idf: espressif/esp-idf@5d7ca5410 --- components/openthread/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openthread/lib b/components/openthread/lib index e9980c5655..2e2d91a382 160000 --- a/components/openthread/lib +++ b/components/openthread/lib @@ -1 +1 @@ -Subproject commit e9980c56558876ae1102be8ae9dc70821aded72c +Subproject commit 2e2d91a382ad6387ce77551c6adbb1514db12472 From 05ff6f2d952ffd55466d15b3dff2cc04c212d0d1 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Wed, 24 Dec 2025 17:05:03 +0800 Subject: [PATCH 132/156] feat(ble): added xor checksum for integrity check performance optimization (cherry picked from commit c604afa272f9b4e81835562eb812d86288f040c5) Co-authored-by: Zhou Xiao --- components/bt/common/ble_log/Kconfig.in | 6 ++ .../bt/common/ble_log/src/ble_log_util.c | 56 ++++++++++++++++++- .../src/internal_include/ble_log_util.h | 2 +- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/components/bt/common/ble_log/Kconfig.in b/components/bt/common/ble_log/Kconfig.in index 2bb05ede5a..edf459311d 100644 --- a/components/bt/common/ble_log/Kconfig.in +++ b/components/bt/common/ble_log/Kconfig.in @@ -91,6 +91,12 @@ if BLE_LOG_ENABLED checksum of frame head and payload all together by default, or only calculate the checksum of frame head to minimize performance decrease + config BLE_LOG_XOR_CHECKSUM_ENABLED + bool "Enable XOR checksum for BLE Log payload integrity check" + default y + help + XOR checksum is introduced for integrity check performance optimization. + config BLE_LOG_ENH_STAT_ENABLED bool "Enable enhanced statistics for BLE Log" default n diff --git a/components/bt/common/ble_log/src/ble_log_util.c b/components/bt/common/ble_log/src/ble_log_util.c index 7657ad92dd..c084d6d249 100644 --- a/components/bt/common/ble_log/src/ble_log_util.c +++ b/components/bt/common/ble_log/src/ble_log_util.c @@ -17,7 +17,60 @@ portMUX_TYPE ble_log_spin_lock = portMUX_INITIALIZER_UNLOCKED; #endif /* !UNIT_TEST */ /* INTERNAL INTERFACE */ -BLE_LOG_IRAM_ATTR uint32_t ble_log_fast_checksum(const uint8_t *data, size_t len) +#if CONFIG_BLE_LOG_XOR_CHECKSUM_ENABLED +#include "esp_compiler.h" + +static inline uint32_t ror32(uint32_t word, uint32_t shift) +{ + if (unlikely(shift == 0)) { + return word; + } + return (word >> shift) | (word << ((32 - shift) & 0x1F)); +} + +__attribute__((optimize("-O3"))) +BLE_LOG_IRAM_ATTR +uint32_t ble_log_fast_checksum(const uint8_t *data, size_t len) +{ + /* Validate input length */ + if (unlikely(len == 0)) { + return 0; + } + + /* Step 1: Force 32-bit align read and calculate offset */ + const uint32_t start_offset_shift = ((uintptr_t)data & 0x3) << 3; + const uint32_t *p_aligned = (const uint32_t *)((uintptr_t)data & ~0x3); + const uint32_t *p_end_aligned = (const uint32_t *)((uintptr_t)(data + len) & ~0x3); + + /* Step 2: Handle first word with mask (Little endian) */ + uint32_t checksum = (*p_aligned) & (0xFFFFFFFFU << start_offset_shift); + + /* Step 3: Check if first word is last word */ + const uint32_t end_offset_shift = ((uintptr_t)(data + len) & 0x3) << 3; + const uint32_t end_offset_shift_mask = ~(0xFFFFFFFFU << end_offset_shift); + if (unlikely(p_aligned == p_end_aligned)) { + if (end_offset_shift) { + checksum &= end_offset_shift_mask; + } + } else { + /* Step 4: Handle word in the middle */ + p_aligned++; + while (p_aligned < p_end_aligned) { + checksum ^= *p_aligned++; + } + + /* Step 5: Handle last word with mask (Little endian) */ + if (end_offset_shift) { + checksum ^= (*p_aligned) & end_offset_shift_mask; + } + } + + /* Step 6: Rotate the final result */ + return ror32(checksum, start_offset_shift); +} +#else /* !CONFIG_BLE_LOG_XOR_CHECKSUM_ENABLED */ +BLE_LOG_IRAM_ATTR +uint32_t ble_log_fast_checksum(const uint8_t *data, size_t len) { uint32_t sum = 0; size_t i = 0; @@ -46,3 +99,4 @@ BLE_LOG_IRAM_ATTR uint32_t ble_log_fast_checksum(const uint8_t *data, size_t len return sum; } +#endif /* CONFIG_BLE_LOG_XOR_CHECKSUM_ENABLED */ diff --git a/components/bt/common/ble_log/src/internal_include/ble_log_util.h b/components/bt/common/ble_log/src/internal_include/ble_log_util.h index d0e7c460f0..352ae80cbd 100644 --- a/components/bt/common/ble_log/src/internal_include/ble_log_util.h +++ b/components/bt/common/ble_log/src/internal_include/ble_log_util.h @@ -130,7 +130,7 @@ bool ble_log_cas_acquire(volatile bool *cas_lock); void ble_log_cas_release(volatile bool *cas_lock); #endif /* UNIT_TEST */ -#define BLE_LOG_VERSION (2) +#define BLE_LOG_VERSION (3) /* TYPEDEF */ typedef enum { From 4c21f792faecd736378c1b7b490be3aa062a4298 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Wed, 24 Dec 2025 17:05:04 +0800 Subject: [PATCH 133/156] fix(ble): added missed ts sync reset (cherry picked from commit d1d07eb60a6e822c61516154b090e69f61a0a765) Co-authored-by: Zhou Xiao --- components/bt/common/ble_log/src/ble_log_rt.c | 1 + components/bt/common/ble_log/src/ble_log_ts.c | 9 +++++++++ .../bt/common/ble_log/src/internal_include/ble_log_ts.h | 1 + 3 files changed, 11 insertions(+) diff --git a/components/bt/common/ble_log/src/ble_log_rt.c b/components/bt/common/ble_log/src/ble_log_rt.c index 382438c0cd..0fb2dcc331 100644 --- a/components/bt/common/ble_log/src/ble_log_rt.c +++ b/components/bt/common/ble_log/src/ble_log_rt.c @@ -139,6 +139,7 @@ bool ble_log_sync_enable(bool enable) return false; } rt_ts_enabled = enable; + ble_log_ts_reset(enable); return true; } #endif /* CONFIG_BLE_LOG_TS_ENABLED */ diff --git a/components/bt/common/ble_log/src/ble_log_ts.c b/components/bt/common/ble_log/src/ble_log_ts.c index 38ad21c210..cd01d03dcb 100644 --- a/components/bt/common/ble_log/src/ble_log_ts.c +++ b/components/bt/common/ble_log/src/ble_log_ts.c @@ -73,3 +73,12 @@ void ble_log_ts_info_update(ble_log_ts_info_t **info) *info = ts_info; } + +void ble_log_ts_reset(bool status) +{ + if (!status && !ts_info->io_level) { + gpio_set_level(CONFIG_BLE_LOG_SYNC_IO_NUM, 1); + } + ts_info->io_level = 0; + gpio_set_level(CONFIG_BLE_LOG_SYNC_IO_NUM, 0); +} diff --git a/components/bt/common/ble_log/src/internal_include/ble_log_ts.h b/components/bt/common/ble_log/src/internal_include/ble_log_ts.h index 11e74e1508..393cd28a46 100644 --- a/components/bt/common/ble_log/src/internal_include/ble_log_ts.h +++ b/components/bt/common/ble_log/src/internal_include/ble_log_ts.h @@ -53,5 +53,6 @@ typedef struct { bool ble_log_ts_init(void); void ble_log_ts_deinit(void); void ble_log_ts_info_update(ble_log_ts_info_t **ts_info); +void ble_log_ts_reset(bool status); #endif /* __BLE_LOG_TS_H__ */ From a961d7da47d89e50ef76c4b3765ff653e0c46fe0 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Wed, 24 Dec 2025 17:05:04 +0800 Subject: [PATCH 134/156] fix(ble): added null pointer check in ble log ts submodule (cherry picked from commit 2b9c7471d0f3841f36f8a4a01aae79b6d08e0cbd) Co-authored-by: Zhou Xiao --- components/bt/common/ble_log/src/ble_log_rt.c | 4 +++- components/bt/common/ble_log/src/ble_log_ts.c | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/components/bt/common/ble_log/src/ble_log_rt.c b/components/bt/common/ble_log/src/ble_log_rt.c index 0fb2dcc331..7268797e36 100644 --- a/components/bt/common/ble_log/src/ble_log_rt.c +++ b/components/bt/common/ble_log/src/ble_log_rt.c @@ -60,7 +60,9 @@ BLE_LOG_IRAM_ATTR BLE_LOG_STATIC void ble_log_rt_task(void *pvParameters) if (rt_ts_enabled) { ble_log_ts_info_t *ts_info = NULL; ble_log_ts_info_update(&ts_info); - ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)ts_info, sizeof(ble_log_ts_info_t)); + if (ts_info) { + ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)ts_info, sizeof(ble_log_ts_info_t)); + } } #endif /* CONFIG_BLE_LOG_TS_ENABLED */ diff --git a/components/bt/common/ble_log/src/ble_log_ts.c b/components/bt/common/ble_log/src/ble_log_ts.c index cd01d03dcb..e01611da10 100644 --- a/components/bt/common/ble_log/src/ble_log_ts.c +++ b/components/bt/common/ble_log/src/ble_log_ts.c @@ -63,6 +63,10 @@ void ble_log_ts_deinit(void) void ble_log_ts_info_update(ble_log_ts_info_t **info) { + if (!ts_inited) { + return; + } + BLE_LOG_ENTER_CRITICAL(); ts_info->io_level = !ts_info->io_level; gpio_set_level(CONFIG_BLE_LOG_SYNC_IO_NUM, ts_info->io_level); @@ -76,6 +80,10 @@ void ble_log_ts_info_update(ble_log_ts_info_t **info) void ble_log_ts_reset(bool status) { + if (!ts_inited) { + return; + } + if (!status && !ts_info->io_level) { gpio_set_level(CONFIG_BLE_LOG_SYNC_IO_NUM, 1); } From 46ae86b4cfa7d2efb41b27153315a958629a2110 Mon Sep 17 00:00:00 2001 From: armando Date: Fri, 19 Dec 2025 16:01:15 +0800 Subject: [PATCH 135/156] fix(cache): fixed cache sync ops concurrent call issue Closes https://github.com/espressif/esp-idf/issues/18023 --- components/esp_mm/esp_cache_msync.c | 10 ++++++++++ components/esp_mm/esp_mmu_map.c | 2 ++ .../esp_mm/include/esp_private/esp_cache_private.h | 10 ++++++++++ components/spi_flash/flash_mmap.c | 3 +++ 4 files changed, 25 insertions(+) diff --git a/components/esp_mm/esp_cache_msync.c b/components/esp_mm/esp_cache_msync.c index e8af782c26..d296da1a9b 100644 --- a/components/esp_mm/esp_cache_msync.c +++ b/components/esp_mm/esp_cache_msync.c @@ -32,6 +32,16 @@ DEFINE_CRIT_SECTION_LOCK_STATIC(s_spinlock); static _lock_t s_mutex; #endif +void esp_cache_sync_ops_enter_critical_section(void) +{ + esp_os_enter_critical_safe(&s_spinlock); +} + +void esp_cache_sync_ops_exit_critical_section(void) +{ + esp_os_exit_critical_safe(&s_spinlock); +} + #if SOC_CACHE_WRITEBACK_SUPPORTED static void s_c2m_ops(uint32_t vaddr, size_t size) { diff --git a/components/esp_mm/esp_mmu_map.c b/components/esp_mm/esp_mmu_map.c index 6bdd8420ef..791b55d59d 100644 --- a/components/esp_mm/esp_mmu_map.c +++ b/components/esp_mm/esp_mmu_map.c @@ -404,7 +404,9 @@ static void IRAM_ATTR NOINLINE_ATTR s_do_cache_invalidate(uint32_t vaddr_start, */ cache_sync(); #else //Other chips + esp_cache_sync_ops_enter_critical_section(); cache_hal_invalidate_addr(vaddr_start, size); + esp_cache_sync_ops_exit_critical_section(); #endif // CONFIG_IDF_TARGET_ESP32 } diff --git a/components/esp_mm/include/esp_private/esp_cache_private.h b/components/esp_mm/include/esp_private/esp_cache_private.h index 9768765b73..fc09ed44f1 100644 --- a/components/esp_mm/include/esp_private/esp_cache_private.h +++ b/components/esp_mm/include/esp_private/esp_cache_private.h @@ -159,6 +159,16 @@ esp_err_t esp_cache_aligned_calloc(size_t n, size_t size, uint32_t heap_caps, vo __attribute__((deprecated("Use 'heap_caps_calloc' with MALLOC_CAP_CACHE_ALIGNED caps instead"))) esp_err_t esp_cache_aligned_calloc_prefer(size_t n, size_t size, void **out_ptr, size_t *actual_size, size_t flag_nums, ...); +/** + * @brief Enter critical section for cache sync operations + */ +void esp_cache_sync_ops_enter_critical_section(void); + +/** + * @brief Exit critical section for cache sync operations + */ +void esp_cache_sync_ops_exit_critical_section(void); + /** * @brief Get Cache alignment requirement for data * diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index d9476cbe30..8b5ed948e6 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -22,6 +22,7 @@ #endif #include "esp_private/esp_mmu_map_private.h" +#include "esp_private/esp_cache_private.h" #include "esp_mmu_map.h" #include "esp_rom_spiflash.h" #if CONFIG_SPIRAM @@ -315,7 +316,9 @@ IRAM_ATTR bool spi_flash_check_and_flush_cache(size_t start_addr, size_t length) return true; #else // CONFIG_IDF_TARGET_ESP32 if (vaddr != NULL) { + esp_cache_sync_ops_enter_critical_section(); cache_hal_invalidate_addr((uint32_t)vaddr, SPI_FLASH_MMU_PAGE_SIZE); + esp_cache_sync_ops_exit_critical_section(); ret = true; } #endif // CONFIG_IDF_TARGET_ESP32 From 3fb705d852d3078b8bfe577f55f93c63a2c1037e Mon Sep 17 00:00:00 2001 From: "chaijie@espressif.com" Date: Tue, 23 Dec 2025 17:32:00 +0800 Subject: [PATCH 136/156] feat (p4eco6): open dcdc switch by software when dcdc stable --- components/esp_hw_support/port/esp32p4/rtc_clk_init.c | 6 ++++++ .../soc/esp32p4/register/hw_ver1/soc/lp_system_reg.h | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c index a8bc0d5b18..97f6eefb0b 100644 --- a/components/esp_hw_support/port/esp32p4/rtc_clk_init.c +++ b/components/esp_hw_support/port/esp32p4/rtc_clk_init.c @@ -19,11 +19,13 @@ #include "soc/lp_clkrst_reg.h" #include "soc/lp_system_reg.h" #include "soc/pmu_reg.h" +#include "soc/chip_revision.h" #include "esp_hw_log.h" #include "sdkconfig.h" #include "esp_rom_uart.h" #include "esp_private/esp_pmu.h" #include "hal/clk_tree_ll.h" +#include "hal/efuse_hal.h" static const char *TAG = "rtc_clk_init"; @@ -71,6 +73,10 @@ void rtc_clk_init(rtc_clk_config_t cfg) pmu_ll_hp_set_dcm_vset(&PMU, PMU_MODE_HP_ACTIVE, hp_dcmvset); SET_PERI_REG_MASK(PMU_HP_ACTIVE_HP_REGULATOR0_REG, PMU_DIG_REGULATOR0_DBIAS_SEL); // Hand over control of dbias to pmu esp_rom_delay_us(1000); + unsigned chip_version = efuse_hal_chip_revision(); + if (ESP_CHIP_REV_ABOVE(chip_version, 301)) { + REG_SET_FIELD(LP_SYSTEM_REG_SYS_CTRL_REG, LP_SYSTEM_REG_LP_FIB_SEL, 0xEF);// lp_fib_sel bit4 set to 0: select dig_fib_reg instead of ana_fib_reg + } pmu_ll_hp_set_regulator_xpd(&PMU, PMU_MODE_HP_ACTIVE, false); soc_xtal_freq_t xtal_freq = cfg.xtal_freq; diff --git a/components/soc/esp32p4/register/hw_ver1/soc/lp_system_reg.h b/components/soc/esp32p4/register/hw_ver1/soc/lp_system_reg.h index 910c591aaa..a0485fa38d 100644 --- a/components/soc/esp32p4/register/hw_ver1/soc/lp_system_reg.h +++ b/components/soc/esp32p4/register/hw_ver1/soc/lp_system_reg.h @@ -88,6 +88,14 @@ extern "C" { #define LP_SYSTEM_REG_ANA_FIB_M (LP_SYSTEM_REG_ANA_FIB_V << LP_SYSTEM_REG_ANA_FIB_S) #define LP_SYSTEM_REG_ANA_FIB_V 0x0000007FU #define LP_SYSTEM_REG_ANA_FIB_S 14 +/** LP_SYSTEM_REG_LP_FIB_SEL : R/W; bitpos: [28:21]; default: 255; + * This is for compatibility with hw_ver3 chips + * This field does not exist on hw_ver1 chips + */ +#define LP_SYSTEM_REG_LP_FIB_SEL 0x000000FFU +#define LP_SYSTEM_REG_LP_FIB_SEL_M (LP_SYSTEM_REG_LP_FIB_SEL_V << LP_SYSTEM_REG_LP_FIB_SEL_S) +#define LP_SYSTEM_REG_LP_FIB_SEL_V 0x000000FFU +#define LP_SYSTEM_REG_LP_FIB_SEL_S 21 /** LP_SYSTEM_REG_LP_FIB_BOD_RESET : R/W; bitpos: [22]; default: 1; * need_des */ From 8417c7006d2e021f5231cd16f5ab3f68659be1ac Mon Sep 17 00:00:00 2001 From: luoxu Date: Tue, 19 Nov 2024 17:51:49 +0800 Subject: [PATCH 137/156] feat(ble_mesh): Device Firmware Update (Zephyr v4.0.0) --- components/bt/esp_ble_mesh/v1.1/dfu/dfd.h | 29 + components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c | 1306 +++++++++++++ .../esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h | 47 + components/bt/esp_ble_mesh/v1.1/dfu/dfu.h | 44 + components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c | 1265 +++++++++++++ .../bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c | 102 + .../bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c | 402 ++++ .../bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h | 135 ++ components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c | 617 ++++++ .../v1.1/include/mesh_v1.1/dfu/dfd.h | 123 ++ .../v1.1/include/mesh_v1.1/dfu/dfd_srv.h | 313 ++++ .../v1.1/include/mesh_v1.1/dfu/dfu.h | 171 ++ .../v1.1/include/mesh_v1.1/dfu/dfu_cli.h | 409 ++++ .../v1.1/include/mesh_v1.1/dfu/dfu_metadata.h | 115 ++ .../v1.1/include/mesh_v1.1/dfu/dfu_srv.h | 266 +++ .../v1.1/include/mesh_v1.1/mbt/blob.h | 262 +++ .../v1.1/include/mesh_v1.1/mbt/blob_cli.h | 454 +++++ .../v1.1/include/mesh_v1.1/mbt/blob_srv.h | 220 +++ components/bt/esp_ble_mesh/v1.1/mbt/blob.h | 154 ++ .../bt/esp_ble_mesh/v1.1/mbt/blob_cli.c | 1658 +++++++++++++++++ .../bt/esp_ble_mesh/v1.1/mbt/blob_srv.c | 1013 ++++++++++ 21 files changed, 9105 insertions(+) create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfd.h create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfu.h create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h create mode 100644 components/bt/esp_ble_mesh/v1.1/mbt/blob.h create mode 100644 components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c create mode 100644 components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h new file mode 100644 index 0000000000..3af9af7214 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define BT_MESH_DFD_OP_RECEIVERS_ADD BT_MESH_MODEL_OP_2(0x83, 0x11) +#define BT_MESH_DFD_OP_RECEIVERS_DELETE_ALL BT_MESH_MODEL_OP_2(0x83, 0x12) +#define BT_MESH_DFD_OP_RECEIVERS_STATUS BT_MESH_MODEL_OP_2(0x83, 0x13) +#define BT_MESH_DFD_OP_RECEIVERS_GET BT_MESH_MODEL_OP_2(0x83, 0x14) +#define BT_MESH_DFD_OP_RECEIVERS_LIST BT_MESH_MODEL_OP_2(0x83, 0x15) +#define BT_MESH_DFD_OP_CAPABILITIES_GET BT_MESH_MODEL_OP_2(0x83, 0x16) +#define BT_MESH_DFD_OP_CAPABILITIES_STATUS BT_MESH_MODEL_OP_2(0x83, 0x17) +#define BT_MESH_DFD_OP_GET BT_MESH_MODEL_OP_2(0x83, 0x18) +#define BT_MESH_DFD_OP_START BT_MESH_MODEL_OP_2(0x83, 0x19) +#define BT_MESH_DFD_OP_SUSPEND BT_MESH_MODEL_OP_2(0x83, 0x1a) +#define BT_MESH_DFD_OP_CANCEL BT_MESH_MODEL_OP_2(0x83, 0x1b) +#define BT_MESH_DFD_OP_APPLY BT_MESH_MODEL_OP_2(0x83, 0x1c) +#define BT_MESH_DFD_OP_STATUS BT_MESH_MODEL_OP_2(0x83, 0x1d) +#define BT_MESH_DFD_OP_UPLOAD_GET BT_MESH_MODEL_OP_2(0x83, 0x1e) +#define BT_MESH_DFD_OP_UPLOAD_START BT_MESH_MODEL_OP_2(0x83, 0x1f) +#define BT_MESH_DFD_OP_UPLOAD_START_OOB BT_MESH_MODEL_OP_2(0x83, 0x20) +#define BT_MESH_DFD_OP_UPLOAD_CANCEL BT_MESH_MODEL_OP_2(0x83, 0x21) +#define BT_MESH_DFD_OP_UPLOAD_STATUS BT_MESH_MODEL_OP_2(0x83, 0x22) +#define BT_MESH_DFD_OP_FW_GET BT_MESH_MODEL_OP_2(0x83, 0x23) +#define BT_MESH_DFD_OP_FW_GET_BY_INDEX BT_MESH_MODEL_OP_2(0x83, 0x24) +#define BT_MESH_DFD_OP_FW_DELETE BT_MESH_MODEL_OP_2(0x83, 0x25) +#define BT_MESH_DFD_OP_FW_DELETE_ALL BT_MESH_MODEL_OP_2(0x83, 0x26) +#define BT_MESH_DFD_OP_FW_STATUS BT_MESH_MODEL_OP_2(0x83, 0x27) diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c new file mode 100644 index 0000000000..4a395a175b --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c @@ -0,0 +1,1306 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "dfu_slot.h" +#include "dfd.h" +#include "dfu.h" +#include "dfd_srv_internal.h" +#include "net.h" +#include "transport.h" + +#define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_mesh_dfd_srv); + +#define ERASE_BLOCK_SIZE DT_PROP(DT_CHOSEN(zephyr_flash), erase_block_size) + +#define DFD_UPLOAD_STATUS_MSG_MAXLEN (5 + CONFIG_BT_MESH_DFU_FWID_MAXLEN) + +BUILD_ASSERT((DFD_UPLOAD_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_UPLOAD_STATUS) + + BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, + "The Firmware Distribution Upload Status message does not fit into the maximum " + "outgoing SDU size."); + +#define DFD_UPLOAD_START_MSG_MAXLEN (16 + CONFIG_BT_MESH_DFU_FWID_MAXLEN + \ + CONFIG_BT_MESH_DFU_METADATA_MAXLEN) + +BUILD_ASSERT((DFD_UPLOAD_START_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_UPLOAD_START) + + BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, + "The Firmware Distribution Upload Start message does not fit into the maximum " + "incoming SDU size."); + +#define DFD_RECEIVERS_LIST_MSG_MAXLEN (4 + CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX * 5) + +BUILD_ASSERT((DFD_RECEIVERS_LIST_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_RECEIVERS_LIST) + + BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, + "The Firmware Distribution Receivers List message does not fit into the maximum " + "outgoing SDU size."); + +#define DFD_RECEIVERS_ADD_MSG_MAXLEN (CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX * 3) + +BUILD_ASSERT((DFD_RECEIVERS_ADD_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_RECEIVERS_ADD) + + BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, + "The Firmware Distribution Receivers Add message does not fit into the maximum " + "incoming SDU size."); + +struct slot_search_ctx { + off_t offset; + size_t size; + bool failed; +}; + +static void dfd_phase_set(struct bt_mesh_dfd_srv *srv, + enum bt_mesh_dfd_phase new_phase) +{ + srv->phase = new_phase; + + if (srv->cb && srv->cb->phase) { + srv->cb->phase(srv, srv->phase); + } +} + +static struct bt_mesh_dfu_target *target_get(struct bt_mesh_dfd_srv *srv, + uint16_t addr) +{ + for (int i = 0; i < srv->target_cnt; ++i) { + if (addr == srv->targets[i].blob.addr) { + return &srv->targets[i]; + } + } + + return NULL; +} + +static bool is_busy(const struct bt_mesh_dfd_srv *srv) +{ + return srv->phase == BT_MESH_DFD_PHASE_TRANSFER_ACTIVE || + srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUCCESS || + srv->phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE; +} + +static bool upload_is_busy(const struct bt_mesh_dfd_srv *srv) +{ + return bt_mesh_blob_srv_is_busy(&srv->upload.blob) || + srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; +} + +static int slot_del(struct bt_mesh_dfd_srv *srv, const struct bt_mesh_dfu_slot *slot) +{ + if (srv->cb && srv->cb->del) { + srv->cb->del(srv, slot); + } + + return bt_mesh_dfu_slot_del(slot); +} + +static void receivers_status_rsp(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFD_OP_RECEIVERS_STATUS, 3); + bt_mesh_model_msg_init(&buf, BT_MESH_DFD_OP_RECEIVERS_STATUS); + + net_buf_simple_add_u8(&buf, status); + net_buf_simple_add_le16(&buf, srv->target_cnt); + + bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); +} + +static int handle_receivers_add(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + enum bt_mesh_dfd_status status = BT_MESH_DFD_SUCCESS; + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + if (buf->len % 3) { + return -EINVAL; + } + + if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { + receivers_status_rsp(srv, ctx, + BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION); + return 0; + } + + while (buf->len >= 3 && status == BT_MESH_DFD_SUCCESS) { + uint8_t img_idx; + uint16_t addr; + + addr = net_buf_simple_pull_le16(buf); + img_idx = net_buf_simple_pull_u8(buf); + + status = bt_mesh_dfd_srv_receiver_add(srv, addr, img_idx); + } + + receivers_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_receivers_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + receivers_status_rsp(srv, ctx, bt_mesh_dfd_srv_receivers_delete_all(srv)); + + return 0; +} + +static int handle_receivers_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + uint16_t first, cnt; + uint8_t progress; + int i; + + first = net_buf_simple_pull_le16(buf); + cnt = net_buf_simple_pull_le16(buf); + if (cnt == 0) { + return -EINVAL; + } + + /* Create a buffer that can fit the full target list, maxing out at TX_SDU_MAX: */ + NET_BUF_SIMPLE_DEFINE( + rsp, BT_MESH_MODEL_BUF_LEN(BT_MESH_DFD_OP_RECEIVERS_LIST, + DFD_RECEIVERS_LIST_MSG_MAXLEN)); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_RECEIVERS_LIST); + + net_buf_simple_add_le16(&rsp, srv->target_cnt); + net_buf_simple_add_le16(&rsp, first); + + cnt = MIN(cnt, srv->target_cnt - first); + progress = bt_mesh_dfu_cli_progress(&srv->dfu) / 2; + + for (i = 0; i < cnt && net_buf_simple_tailroom(&rsp) >= 5 + BT_MESH_MIC_SHORT; i++) { + const struct bt_mesh_dfu_target *t = &srv->targets[i + first]; + + net_buf_simple_add_le32( + &rsp, ((t->blob.addr & BIT_MASK(15)) | + ((t->phase & BIT_MASK(4)) << 15U) | + ((t->status & BIT_MASK(3)) << 19U) | + ((t->blob.status & BIT_MASK(4)) << 22U) | + ((progress & BIT_MASK(6)) << 26U))); + net_buf_simple_add_u8(&rsp, t->img_idx); + } + + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +static enum bt_mesh_dfu_iter slot_space_cb(const struct bt_mesh_dfu_slot *slot, + void *user_data) +{ + size_t *total = user_data; + + *total += slot->size; + + return BT_MESH_DFU_ITER_CONTINUE; +} + +static int handle_capabilities_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + size_t size = 0; + + BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_CAPABILITIES_STATUS, 17); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_CAPABILITIES_STATUS); + + net_buf_simple_add_le16(&rsp, CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX); + net_buf_simple_add_le16(&rsp, CONFIG_BT_MESH_DFU_SLOT_CNT); + net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE); + net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE); + + /* Remaining size */ + (void)bt_mesh_dfu_slot_foreach(slot_space_cb, &size); + size = MIN(size, CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE); + + net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE - size); + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + if (srv->oob_schemes.count > 0) { + net_buf_simple_add_u8(&rsp, 1); + net_buf_simple_add_mem(&rsp, srv->oob_schemes.schemes, + srv->oob_schemes.count); + } else +#endif + { + net_buf_simple_add_u8(&rsp, 0); + } + + bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +static void status_rsp(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status) +{ + BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_STATUS, 12); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_STATUS); + + net_buf_simple_add_u8(&rsp, status); + net_buf_simple_add_u8(&rsp, srv->phase); + + if (srv->phase == BT_MESH_DFD_PHASE_IDLE || !srv->dfu.xfer.slot) { + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + return; + } + + net_buf_simple_add_le16(&rsp, srv->inputs.group); + net_buf_simple_add_le16(&rsp, srv->inputs.app_idx); + net_buf_simple_add_u8(&rsp, srv->inputs.ttl); + net_buf_simple_add_le16(&rsp, srv->inputs.timeout_base); + net_buf_simple_add_u8(&rsp, ((srv->dfu.xfer.blob.mode & BIT_MASK(2)) | + ((srv->apply & BIT_MASK(1)) << 2))); + net_buf_simple_add_le16(&rsp, srv->slot_idx); + + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); +} + +static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + + return 0; +} + +static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_start_params params; + uint8_t byte; + + params.app_idx = net_buf_simple_pull_le16(buf); + params.ttl = net_buf_simple_pull_u8(buf); + params.timeout_base = net_buf_simple_pull_le16(buf); + byte = net_buf_simple_pull_u8(buf); + params.xfer_mode = byte & BIT_MASK(2); + params.apply = (byte >> 2U) & BIT_MASK(1); + params.slot_idx = net_buf_simple_pull_le16(buf); + + if (buf->len == 16) { + /* TODO: Virtual addresses not supported. */ + status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } + + if (buf->len != 2) { + return -EINVAL; + } + + params.group = net_buf_simple_pull_le16(buf); + + status_rsp(srv, ctx, bt_mesh_dfd_srv_start(srv, ¶ms)); + + return 0; +} + +static int handle_suspend(const struct bt_mesh_model *mod, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + status_rsp(srv, ctx, bt_mesh_dfd_srv_suspend(srv)); + + return 0; +} + +static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + bt_mesh_dfd_srv_cancel(srv, ctx); + + return 0; +} + +static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + status_rsp(srv, ctx, bt_mesh_dfd_srv_apply(srv)); + + return 0; +} + +static void upload_status_rsp_with_progress(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status, + uint8_t progress) +{ + BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_UPLOAD_STATUS, + DFD_UPLOAD_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_UPLOAD_STATUS); + + net_buf_simple_add_u8(&rsp, status); + net_buf_simple_add_u8(&rsp, srv->upload.phase); + + if (srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_IDLE || + !srv->upload.slot) { + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + return; + } + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob) { + net_buf_simple_add_u8(&rsp, progress | BIT(7)); + net_buf_simple_add_mem(&rsp, srv->upload.oob.current_fwid, + srv->upload.oob.current_fwid_len); + } else +#endif + { + net_buf_simple_add_u8(&rsp, progress); + net_buf_simple_add_mem(&rsp, srv->upload.slot->fwid, + srv->upload.slot->fwid_len); + } + + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); +} + +static void upload_status_rsp(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status) +{ + uint8_t progress; + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob) { + progress = srv->cb->oob_progress_get(srv, srv->upload.slot); + } else +#endif + { + progress = bt_mesh_blob_srv_progress(&srv->upload.blob); + } + + upload_status_rsp_with_progress(srv, ctx, status, progress); +} + +static int handle_upload_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + + return 0; +} + +static inline int set_upload_fwid(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, + const uint8_t *fwid, size_t fwid_len) +{ + int err = bt_mesh_dfu_slot_fwid_set(srv->upload.slot, fwid, fwid_len); + + switch (err) { + case -EFBIG: /* Fwid too long */ + case -EALREADY: /* Other server is in progress with this fwid */ + bt_mesh_dfu_slot_release(srv->upload.slot); + srv->upload.slot = NULL; + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + break; + case -EEXIST: /* Img with this fwid already is in list */ + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + bt_mesh_dfu_slot_release(srv->upload.slot); + + err = bt_mesh_dfu_slot_get(fwid, fwid_len, &srv->upload.slot); + if (!err) { + upload_status_rsp_with_progress(srv, ctx, BT_MESH_DFD_SUCCESS, 100); + } else { + srv->upload.slot = NULL; + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + } + break; + case 0: + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + break; + case -EINVAL: /* Slot in wrong state. */ + default: + break; + } + + return err; +} + +static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + size_t meta_len, fwid_len, size; + const uint8_t *meta, *fwid; + uint16_t timeout_base; + uint64_t blob_id; + int err; + uint8_t ttl; + + ttl = net_buf_simple_pull_u8(buf); + timeout_base = net_buf_simple_pull_le16(buf); + blob_id = net_buf_simple_pull_le64(buf); + size = net_buf_simple_pull_le32(buf); + meta_len = net_buf_simple_pull_u8(buf); + if (buf->len < meta_len) { + return -EINVAL; + } + + meta = net_buf_simple_pull_mem(buf, meta_len); + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); + + LOG_DBG("Upload Start: size: %d, fwid: %s, metadata: %s", size, bt_hex(fwid, fwid_len), + bt_hex(meta, meta_len)); + + if (size > CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE) { + upload_status_rsp(srv, ctx, + BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + return 0; + } + + if (upload_is_busy(srv)) { + if (!srv->upload.slot) { + LOG_WRN("Busy with no upload slot"); + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } + + if (srv->upload.slot->fwid_len == fwid_len && + !memcmp(srv->upload.slot->fwid, fwid, fwid_len) && + srv->upload.slot->metadata_len == meta_len && + !memcmp(srv->upload.slot->metadata, meta, meta_len) && + srv->upload.blob.state.xfer.id == blob_id && + srv->upload.blob.state.ttl == ttl && + srv->upload.blob.state.timeout_base == timeout_base +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + && !srv->upload.is_oob +#endif + ) { + LOG_DBG("Duplicate upload start"); + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + return 0; + } + + LOG_WRN("Upload already in progress"); + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD); + return 0; + } + + /* This will be a no-op if the slot state isn't RESERVED, which is + * what we want. + */ + if (srv->upload.slot) { + bt_mesh_dfu_slot_release(srv->upload.slot); + } + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + srv->upload.is_oob = false; +#endif + srv->upload.slot = bt_mesh_dfu_slot_reserve(); + + if (!srv->upload.slot) { + LOG_WRN("No space for slot"); + upload_status_rsp(srv, ctx, + BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + return 0; + } + + err = set_upload_fwid(srv, ctx, fwid, fwid_len); + if (err) { + return err; + } + + err = bt_mesh_dfu_slot_info_set(srv->upload.slot, size, meta, meta_len); + switch (err) { + case -EFBIG: + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + break; + case 0: + break; + default: + return err; + } + + srv->io = NULL; + err = srv->cb->recv(srv, srv->upload.slot, &srv->io); + if (err || !srv->io) { + LOG_ERR("App rejected upload. err: %d io: %p", err, srv->io); + bt_mesh_dfu_slot_release(srv->upload.slot); + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } + + err = bt_mesh_blob_srv_recv(&srv->upload.blob, blob_id, srv->io, ttl, + timeout_base); + if (err) { + LOG_ERR("BLOB Server rejected upload (err: %d)", err); + bt_mesh_dfu_slot_release(srv->upload.slot); + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } + + LOG_DBG("%s", bt_hex(fwid, fwid_len)); + + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + + return 0; +} + +static int handle_upload_start_oob(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + uint8_t uri_len; + uint8_t *uri; + uint16_t fwid_len; + uint8_t *fwid; + + uri_len = net_buf_simple_pull_u8(buf); + + if (uri_len > buf->len) { + return -EINVAL; + } + + uri = net_buf_simple_pull_mem(buf, uri_len); + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); + + LOG_DBG("Upload OOB Start"); + LOG_HEXDUMP_DBG(uri, uri_len, "URI"); + LOG_HEXDUMP_DBG(fwid, fwid_len, "FWID"); + + if (upload_is_busy(srv)) { +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob && + uri_len == srv->upload.oob.uri_len && + fwid_len == srv->upload.oob.current_fwid_len && + !memcmp(uri, srv->upload.oob.uri, uri_len) && + !memcmp(fwid, srv->upload.oob.current_fwid, fwid_len)) { + /* Same image, return SUCCESS for idempotency */ + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + return 0; + } +#endif + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD); + return 0; +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + } else if (srv->upload.is_oob && srv->upload.is_pending_oob_check) { + /* Ignore the request if we didn't confirm the previous one. */ + return 0; +#endif + } + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + if (uri_len > CONFIG_BT_MESH_DFU_URI_MAXLEN || + fwid_len > CONFIG_BT_MESH_DFU_FWID_MAXLEN) { + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } + + struct bt_mesh_dfu_slot *slot = bt_mesh_dfu_slot_reserve(); + + if (slot == NULL) { + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + return 0; + } + + /* This will be a no-op if the slot state isn't RESERVED, which is + * what we want. + */ + if (srv->upload.slot) { + bt_mesh_dfu_slot_release(srv->upload.slot); + } + + srv->upload.is_oob = true; + srv->upload.slot = slot; + memcpy(srv->upload.oob.uri, uri, uri_len); + srv->upload.oob.uri_len = uri_len; + memcpy(srv->upload.oob.current_fwid, fwid, fwid_len); + srv->upload.oob.current_fwid_len = fwid_len; + memcpy(&srv->upload.oob.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + + int status = srv->cb->start_oob_upload(srv, srv->upload.slot, srv->upload.oob.uri, + srv->upload.oob.uri_len, + srv->upload.oob.current_fwid, + srv->upload.oob.current_fwid_len); + + if (status != BT_MESH_DFD_SUCCESS) { + upload_status_rsp(srv, ctx, status); + bt_mesh_dfu_slot_release(srv->upload.slot); + } else { + srv->upload.is_pending_oob_check = true; + } +#else + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_URI_NOT_SUPPORTED); +#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ + + return 0; +} + +static int handle_upload_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob) { + srv->cb->cancel_oob_upload(srv, srv->upload.slot); + } else +#endif + { + (void)bt_mesh_blob_srv_cancel(&srv->upload.blob); + } + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + + return 0; +} + +static void fw_status_rsp(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status, uint16_t idx, + const uint8_t *fwid, size_t fwid_len) +{ + BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_FW_STATUS, + 7 + CONFIG_BT_MESH_DFU_FWID_MAXLEN); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_FW_STATUS); + + net_buf_simple_add_u8(&rsp, status); + net_buf_simple_add_le16(&rsp, bt_mesh_dfu_slot_count()); + + net_buf_simple_add_le16(&rsp, idx); + if (fwid) { + net_buf_simple_add_mem(&rsp, fwid, fwid_len); + } + + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); +} + +static int handle_fw_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfu_slot *slot; + const uint8_t *fwid; + size_t fwid_len; + int idx; + + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); + + idx = bt_mesh_dfu_slot_get(fwid, fwid_len, &slot); + if (idx >= 0) { + fw_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS, idx, fwid, + fwid_len); + } else { + fw_status_rsp(srv, ctx, BT_MESH_DFD_ERR_FW_NOT_FOUND, 0xffff, + fwid, fwid_len); + } + + return 0; +} + +static int handle_fw_get_by_index(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + const struct bt_mesh_dfu_slot *slot; + uint16_t idx; + + idx = net_buf_simple_pull_le16(buf); + + slot = bt_mesh_dfu_slot_at(idx); + if (slot) { + fw_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS, idx, slot->fwid, + slot->fwid_len); + } else { + fw_status_rsp(srv, ctx, BT_MESH_DFD_ERR_FW_NOT_FOUND, idx, + NULL, 0); + } + + return 0; +} + +static int handle_fw_delete(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + const uint8_t *fwid; + size_t fwid_len; + + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); + + enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_fw_delete(srv, &fwid_len, &fwid); + + fw_status_rsp(srv, ctx, status, 0xffff, fwid, fwid_len); + + return 0; +} + +static enum bt_mesh_dfu_iter slot_del_cb(const struct bt_mesh_dfu_slot *slot, + void *user_data) +{ + struct bt_mesh_dfd_srv *srv = user_data; + + if (srv->cb && srv->cb->del) { + srv->cb->del(srv, slot); + } + + return BT_MESH_DFU_ITER_CONTINUE; +} + +static int handle_fw_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + fw_status_rsp(srv, ctx, bt_mesh_dfd_srv_fw_delete_all(srv), 0xffff, NULL, 0); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[] = { + { BT_MESH_DFD_OP_RECEIVERS_ADD, BT_MESH_LEN_MIN(3), handle_receivers_add }, + { BT_MESH_DFD_OP_RECEIVERS_DELETE_ALL, BT_MESH_LEN_EXACT(0), handle_receivers_delete_all }, + { BT_MESH_DFD_OP_RECEIVERS_GET, BT_MESH_LEN_EXACT(4), handle_receivers_get }, + { BT_MESH_DFD_OP_CAPABILITIES_GET, BT_MESH_LEN_EXACT(0), handle_capabilities_get }, + { BT_MESH_DFD_OP_GET, BT_MESH_LEN_EXACT(0), handle_get }, + { BT_MESH_DFD_OP_START, BT_MESH_LEN_MIN(10), handle_start }, + { BT_MESH_DFD_OP_SUSPEND, BT_MESH_LEN_EXACT(0), handle_suspend }, + { BT_MESH_DFD_OP_CANCEL, BT_MESH_LEN_EXACT(0), handle_cancel }, + { BT_MESH_DFD_OP_APPLY, BT_MESH_LEN_EXACT(0), handle_apply }, + { BT_MESH_DFD_OP_UPLOAD_GET, BT_MESH_LEN_EXACT(0), handle_upload_get }, + { BT_MESH_DFD_OP_UPLOAD_START, BT_MESH_LEN_MIN(16), handle_upload_start }, + { BT_MESH_DFD_OP_UPLOAD_START_OOB, BT_MESH_LEN_MIN(2), handle_upload_start_oob }, + { BT_MESH_DFD_OP_UPLOAD_CANCEL, BT_MESH_LEN_EXACT(0), handle_upload_cancel }, + { BT_MESH_DFD_OP_FW_GET, BT_MESH_LEN_MIN(0), handle_fw_get }, + { BT_MESH_DFD_OP_FW_GET_BY_INDEX, BT_MESH_LEN_EXACT(2), handle_fw_get_by_index }, + { BT_MESH_DFD_OP_FW_DELETE, BT_MESH_LEN_MIN(0), handle_fw_delete }, + { BT_MESH_DFD_OP_FW_DELETE_ALL, BT_MESH_LEN_EXACT(0), handle_fw_delete_all }, + + BT_MESH_MODEL_OP_END +}; + +static void dfu_suspended(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + + dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED); +} + +static void dfu_ended(struct bt_mesh_dfu_cli *cli, + enum bt_mesh_dfu_status reason) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + int err; + + LOG_DBG("reason: %u, phase: %u, apply: %u", reason, srv->phase, srv->apply); + + if (srv->phase == BT_MESH_DFD_PHASE_IDLE) { + return; + } + + if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + return; + } + + if (reason != BT_MESH_DFU_SUCCESS) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + return; + } + + if (!srv->apply) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_SUCCESS); + return; + } + + dfd_phase_set(srv, BT_MESH_DFD_PHASE_APPLYING_UPDATE); + + err = bt_mesh_dfu_cli_apply(cli); + if (err) { + LOG_ERR("Apply failed: %d", err); + dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + } +} + +static void dfu_applied(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + int err; + + if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + return; + } + + if (srv->phase != BT_MESH_DFD_PHASE_APPLYING_UPDATE) { + return; + } + + err = bt_mesh_dfu_cli_confirm(cli); + if (err) { + LOG_ERR("Confirm failed: %d", err); + dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + } +} + +static void dfu_confirmed(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + + if (srv->phase != BT_MESH_DFD_PHASE_APPLYING_UPDATE && + srv->phase != BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + return; + } + + dfd_phase_set(srv, BT_MESH_DFD_PHASE_COMPLETED); +} + +const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb = { + .suspended = dfu_suspended, + .ended = dfu_ended, + .applied = dfu_applied, + .confirmed = dfu_confirmed, +}; + +static int upload_start(struct bt_mesh_blob_srv *b, struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_blob_xfer *xfer) +{ + LOG_DBG(""); + return 0; +} + +static void upload_end(struct bt_mesh_blob_srv *b, uint64_t id, bool success) +{ + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(b, struct bt_mesh_dfd_srv, upload.blob); + + if (srv->upload.phase != BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE) { + return; + } + + LOG_DBG("%u", success); + + if (success && (bt_mesh_dfu_slot_commit(srv->upload.slot) == 0)) { + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + return; + } + + /* Will delete slot when we start a new upload */ + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; +} + +static void upload_timeout(struct bt_mesh_blob_srv *b) +{ + LOG_DBG(""); + + upload_end(b, b->state.xfer.id, false); +} + +const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb = { + .start = upload_start, + .end = upload_end, + .suspended = upload_timeout, +}; + +static int dfd_srv_init(const struct bt_mesh_model *mod) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + srv->mod = mod; + + if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) { + bt_mesh_model_extend(mod, srv->upload.blob.mod); + } + + return 0; +} + +static void dfd_srv_reset(const struct bt_mesh_model *mod) +{ + struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; + + sys_slist_init(&srv->inputs.targets); + srv->target_cnt = 0; + + bt_mesh_dfu_slot_foreach(slot_del_cb, srv); + bt_mesh_dfu_slot_del_all(); +} + +const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb = { + .init = dfd_srv_init, + .reset = dfd_srv_reset, +}; + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_receiver_add(struct bt_mesh_dfd_srv *srv, uint16_t addr, + uint8_t img_idx) +{ + struct bt_mesh_dfu_target *t; + struct bt_mesh_blob_target_pull *p; + + if (!BT_MESH_ADDR_IS_UNICAST(addr)) { + return BT_MESH_DFD_SUCCESS; + } + + t = target_get(srv, addr); + if (t) { + t->img_idx = img_idx; + return BT_MESH_DFD_SUCCESS; + } + + /* New target node, add it to the list */ + + if (srv->target_cnt == ARRAY_SIZE(srv->targets)) { + return BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES; + } + + t = &srv->targets[srv->target_cnt]; + p = &srv->pull_ctxs[srv->target_cnt]; + srv->target_cnt++; + + memset(t, 0, sizeof(*t)); + memset(p, 0, sizeof(*p)); + t->blob.addr = addr; + t->blob.pull = p; + t->img_idx = img_idx; + + LOG_DBG("Added receiver 0x%04x img: %u", t->blob.addr, + t->img_idx); + + return BT_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_receivers_delete_all(struct bt_mesh_dfd_srv *srv) +{ + if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + sys_slist_init(&srv->inputs.targets); + srv->target_cnt = 0; + + return BT_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_dfd_start_params *params) +{ + int err, i; + struct bt_mesh_dfu_cli_xfer xfer = { 0 }; + + if (!srv->target_cnt) { + return BT_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY; + } + + if (!bt_mesh_app_key_exists(params->app_idx)) { + return BT_MESH_DFD_ERR_INVALID_APPKEY_INDEX; + } + + xfer.mode = params->xfer_mode; + xfer.slot = bt_mesh_dfu_slot_at(params->slot_idx); + if (!xfer.slot) { + return BT_MESH_DFD_ERR_FW_NOT_FOUND; + } + + if (srv->inputs.app_idx == params->app_idx && + srv->inputs.timeout_base == params->timeout_base && + srv->inputs.group == params->group && srv->inputs.ttl == params->ttl && + srv->dfu.xfer.blob.mode == xfer.mode && srv->apply == params->apply && + srv->slot_idx == params->slot_idx) { + if (is_busy(srv) || + srv->phase == BT_MESH_DFD_PHASE_COMPLETED) { + LOG_WRN("Already completed or in progress"); + return BT_MESH_DFD_SUCCESS; + } else if (srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + bt_mesh_dfu_cli_resume(&srv->dfu); + dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_ACTIVE); + return BT_MESH_DFD_SUCCESS; + } + } else if (is_busy(srv) || + srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + LOG_WRN("Busy with distribution"); + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + LOG_WRN("Canceling distribution"); + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + srv->io = NULL; + err = srv->cb->send(srv, xfer.slot, &srv->io); + if (err || !srv->io) { + return BT_MESH_DFD_ERR_INTERNAL; + } + + sys_slist_init(&srv->inputs.targets); + for (i = 0; i < srv->target_cnt; i++) { + uint16_t addr = srv->targets[i].blob.addr; + + memset(&srv->targets[i].blob, 0, sizeof(struct bt_mesh_blob_target)); + memset(&srv->pull_ctxs[i], 0, sizeof(struct bt_mesh_blob_target_pull)); + srv->targets[i].blob.addr = addr; + srv->targets[i].blob.pull = &srv->pull_ctxs[i]; + + sys_slist_append(&srv->inputs.targets, &srv->targets[i].blob.n); + } + + srv->slot_idx = params->slot_idx; + srv->inputs.app_idx = params->app_idx; + srv->inputs.timeout_base = params->timeout_base; + srv->inputs.group = params->group; + srv->inputs.ttl = params->ttl; + srv->apply = params->apply; + + LOG_DBG("Distribution Start: slot: %d, appidx: %d, tb: %d, addr: %04X, ttl: %d, apply: %d", + params->slot_idx, params->app_idx, params->timeout_base, params->group, params->ttl, + params->apply); + + /* DFD Server will always retrieve targets' capabilities before distributing a firmware.*/ + xfer.blob_params = NULL; + + dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_ACTIVE); + err = bt_mesh_dfu_cli_send(&srv->dfu, &srv->inputs, srv->io, &xfer); + if (err) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + return BT_MESH_DFD_ERR_INTERNAL; + } + + return BT_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_suspend(struct bt_mesh_dfd_srv *srv) +{ + int err; + + if (srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + return BT_MESH_DFD_SUCCESS; + } + + if (srv->phase != BT_MESH_DFD_PHASE_TRANSFER_ACTIVE) { + return BT_MESH_DFD_ERR_WRONG_PHASE; + } + + err = bt_mesh_dfu_cli_suspend(&srv->dfu); + if (err) { + return BT_MESH_DFD_ERR_SUSPEND_FAILED; + } + + srv->phase = BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED; + return BT_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_cancel(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx) +{ + enum bt_mesh_dfd_phase prev_phase; + int err; + + if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE || + srv->phase == BT_MESH_DFD_PHASE_IDLE) { + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + } + return BT_MESH_DFD_SUCCESS; + } + + if (srv->phase == BT_MESH_DFD_PHASE_COMPLETED || + srv->phase == BT_MESH_DFD_PHASE_FAILED) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + } + return BT_MESH_DFD_SUCCESS; + } + + /* Phase TRANSFER_ACTIVE, TRANSFER_SUSPENDED, TRANSFER_SUCCESS, APPLYING_UPDATE: */ + + prev_phase = srv->phase; + dfd_phase_set(srv, BT_MESH_DFD_PHASE_CANCELING_UPDATE); + err = bt_mesh_dfu_cli_cancel(&srv->dfu, NULL); + if (err) { + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + } + return BT_MESH_DFD_ERR_INTERNAL; + } + + if (prev_phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE && ctx) { + /* Disable randomization for the Firmware Distribution State message to avoid + * reordering when Firmware Distribution Server sends 2 messages in a row when + * cancelling the update (see section 6.2.3.10 of MshDFUv1.0). + */ + ctx->rnd_delay = false; + } + + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + } + + if (prev_phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + } + } + + return BT_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_apply(struct bt_mesh_dfd_srv *srv) +{ + int err; + + if (srv->phase == BT_MESH_DFD_PHASE_IDLE || + srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE || + srv->phase == BT_MESH_DFD_PHASE_TRANSFER_ACTIVE || + srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED || + srv->phase == BT_MESH_DFD_PHASE_FAILED) { + return BT_MESH_DFD_ERR_WRONG_PHASE; + } + + if (srv->phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE || + srv->phase == BT_MESH_DFD_PHASE_COMPLETED) { + return BT_MESH_DFD_SUCCESS; + } + + err = bt_mesh_dfu_cli_apply(&srv->dfu); + if (err) { + return BT_MESH_DFD_ERR_INTERNAL; + } + + dfd_phase_set(srv, BT_MESH_DFD_PHASE_APPLYING_UPDATE); + return BT_MESH_DFD_SUCCESS; +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete(struct bt_mesh_dfd_srv *srv, size_t *fwid_len, + const uint8_t **fwid) +{ + struct bt_mesh_dfu_slot *slot; + int idx, err; + + if (srv->phase != BT_MESH_DFD_PHASE_IDLE) { + *fwid = NULL; + *fwid_len = 0; + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + idx = bt_mesh_dfu_slot_get(*fwid, *fwid_len, &slot); + if (idx < 0) { + return BT_MESH_DFD_SUCCESS; + } + + err = slot_del(srv, slot); + if (err) { + *fwid = NULL; + *fwid_len = 0; + return BT_MESH_DFD_ERR_INTERNAL; + } else { + return BT_MESH_DFD_SUCCESS; + } +} + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete_all(struct bt_mesh_dfd_srv *srv) +{ + if (srv->phase != BT_MESH_DFD_PHASE_IDLE) { + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } + + bt_mesh_dfu_slot_foreach(slot_del_cb, srv); + + bt_mesh_dfu_slot_del_all(); + + return BT_MESH_DFD_SUCCESS; +} + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD +int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len) +{ + int err; + + if (slot != srv->upload.slot || !srv->upload.is_oob || + srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || + !srv->upload.is_pending_oob_check) { + /* This should not happen, unless the application calls the function with a + * "wrong" pointer or at a wrong time. + */ + return -EINVAL; + } + + srv->upload.is_pending_oob_check = false; + + if (status != BT_MESH_DFD_SUCCESS) { + bt_mesh_dfu_slot_release(srv->upload.slot); + upload_status_rsp(srv, &srv->upload.oob.ctx, status); + return -ECANCELED; + } + + err = set_upload_fwid(srv, &srv->upload.oob.ctx, fwid, fwid_len); + + if (err) { + return err; + } + + upload_status_rsp(srv, &srv->upload.oob.ctx, BT_MESH_DFD_SUCCESS); + return 0; +} + +int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len) +{ + int err = 0; + + if (srv->upload.phase != BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || + srv->upload.slot != slot || !srv->upload.is_oob) { + return -EINVAL; + } + + if (!success) { + goto error; + } + + err = bt_mesh_dfu_slot_info_set(srv->upload.slot, size, metadata, metadata_len); + if (err) { + goto error; + } + + err = bt_mesh_dfu_slot_commit(srv->upload.slot); + if (err) { + goto error; + } + + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + return 0; + +error: + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; + bt_mesh_dfu_slot_release(srv->upload.slot); + return err; +} +#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h new file mode 100644 index 0000000000..12c7d943f6 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_INTERNAL_H__ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_INTERNAL_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_mesh_dfd_start_params { + uint16_t app_idx, timeout_base, slot_idx, group; + enum bt_mesh_blob_xfer_mode xfer_mode; + uint8_t ttl; + bool apply; +}; + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_receiver_add(struct bt_mesh_dfd_srv *srv, uint16_t addr, + uint8_t img_idx); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_receivers_delete_all(struct bt_mesh_dfd_srv *srv); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_dfd_start_params *params); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_suspend(struct bt_mesh_dfd_srv *srv); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_cancel(struct bt_mesh_dfd_srv *srv, + struct bt_mesh_msg_ctx *ctx); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_apply(struct bt_mesh_dfd_srv *srv); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete(struct bt_mesh_dfd_srv *srv, size_t *fwid_len, + const uint8_t **fwid); + +enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete_all(struct bt_mesh_dfd_srv *srv); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_INTERNAL_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h new file mode 100644 index 0000000000..c1c5aca46c --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define BT_MESH_DFU_OP_UPDATE_INFO_GET BT_MESH_MODEL_OP_2(0x83, 0x08) +#define BT_MESH_DFU_OP_UPDATE_INFO_STATUS BT_MESH_MODEL_OP_2(0x83, 0x09) + +#define BT_MESH_DFU_OP_UPDATE_METADATA_CHECK BT_MESH_MODEL_OP_2(0x83, 0x0a) +#define BT_MESH_DFU_OP_UPDATE_METADATA_STATUS BT_MESH_MODEL_OP_2(0x83, 0x0b) + +#define BT_MESH_DFU_OP_UPDATE_GET BT_MESH_MODEL_OP_2(0x83, 0x0c) +#define BT_MESH_DFU_OP_UPDATE_START BT_MESH_MODEL_OP_2(0x83, 0x0d) +#define BT_MESH_DFU_OP_UPDATE_CANCEL BT_MESH_MODEL_OP_2(0x83, 0x0e) +#define BT_MESH_DFU_OP_UPDATE_APPLY BT_MESH_MODEL_OP_2(0x83, 0x0f) +#define BT_MESH_DFU_OP_UPDATE_STATUS BT_MESH_MODEL_OP_2(0x83, 0x10) + +#define DFU_UPDATE_INFO_STATUS_MSG_MINLEN (4 + CONFIG_BT_MESH_DFU_FWID_MAXLEN + \ + CONFIG_BT_MESH_DFU_URI_MAXLEN) +#define DFU_UPDATE_START_MSG_MAXLEN (12 + CONFIG_BT_MESH_DFU_METADATA_MAXLEN) + +static inline uint16_t dfu_metadata_checksum(struct net_buf_simple *buf) +{ + /* Simple Fletcher-16 checksum to ensure duplicate start messages don't + * have different metadata. + */ + struct net_buf_simple_state state; + uint8_t sum[2] = {0, 0}; + + net_buf_simple_save(buf, &state); + + + while (buf->len) { + uint8_t byte = net_buf_simple_pull_u8(buf); + + sum[0] += byte; + sum[1] += sum[0]; + } + + net_buf_simple_restore(buf, &state); + + return (sum[0] << 8U) | sum[1]; +} diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c new file mode 100644 index 0000000000..f02b884d22 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c @@ -0,0 +1,1265 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "access.h" +#include "dfu.h" +#include "blob.h" +#include + +#define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_mesh_dfu_cli); + +#define TARGETS_FOR_EACH(cli, target) \ + SYS_SLIST_FOR_EACH_CONTAINER( \ + (sys_slist_t *)&((cli)->blob.inputs)->targets, target, blob.n) + +#define MSG_CTX(cli, dst) \ + { \ + .app_idx = (cli)->blob.inputs->app_idx, .addr = dst, \ + .send_ttl = (cli)->blob.inputs->ttl, \ + } + +#define DFU_CLI(blob_cli) CONTAINER_OF(blob_cli, struct bt_mesh_dfu_cli, blob) + +BUILD_ASSERT((DFU_UPDATE_START_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_START) + + BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, + "The Firmware Update Start message does not fit into the maximum outgoing SDU size."); + +BUILD_ASSERT((DFU_UPDATE_INFO_STATUS_MSG_MINLEN + + BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_INFO_STATUS) + BT_MESH_MIC_SHORT) + <= BT_MESH_RX_SDU_MAX, + "The Firmware Update Info Status message does not fit into the maximum incoming SDU " + "size."); + +enum req { + REQ_NONE, + REQ_METADATA, + REQ_IMG, + REQ_STATUS, +}; + +enum { + FLAG_FAILED = BIT(0), + FLAG_CANCELLED = BIT(1), + FLAG_SKIP_CAPS_GET = BIT(2), + FLAG_RESUME = BIT(3), + FLAG_COMPLETED = BIT(4), +}; + +enum { + STATE_IDLE, + STATE_TRANSFER, + STATE_REFRESH, + STATE_VERIFIED, + STATE_APPLY, + STATE_APPLIED, + STATE_CONFIRM, + STATE_CANCEL, + STATE_SUSPENDED, +}; + +static int32_t dfu_cli_timeout = (10 * MSEC_PER_SEC); + +static struct bt_mesh_dfu_target *target_get(struct bt_mesh_dfu_cli *cli, + uint16_t addr) +{ + struct bt_mesh_dfu_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (addr == target->blob.addr) { + return target; + } + } + + return NULL; +} + +static void target_failed(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_dfu_target *target, + enum bt_mesh_dfu_status status) +{ + target->status = status; + + LOG_ERR("Target 0x%04x failed: %u", target->blob.addr, status); + + /* Invalidate blob status to prevent the target from being included in + * future sending: + */ + if (target->blob.status == BT_MESH_BLOB_SUCCESS) { + target->blob.status = BT_MESH_BLOB_ERR_INTERNAL; + } + + if (cli->cb && cli->cb->lost_target) { + cli->cb->lost_target(cli, target); + } +} + +static void dfu_complete(struct bt_mesh_dfu_cli *cli) +{ + LOG_DBG(""); + + if (cli->cb && cli->cb->ended) { + cli->cb->ended(cli, BT_MESH_DFU_SUCCESS); + } +} + +static void dfu_applied(struct bt_mesh_dfu_cli *cli) +{ + LOG_DBG(""); + + cli->xfer.state = STATE_APPLIED; + + if (cli->cb && cli->cb->applied) { + cli->cb->applied(cli); + } +} + +static void dfu_failed(struct bt_mesh_dfu_cli *cli, + enum bt_mesh_dfu_status reason) +{ + LOG_DBG("%u", reason); + + cli->xfer.flags |= FLAG_FAILED; + + if (cli->cb && cli->cb->ended) { + cli->cb->ended(cli, reason); + } +} + +static int req_setup(struct bt_mesh_dfu_cli *cli, enum req type, uint16_t addr, + void *params) +{ + if (cli->req.type != REQ_NONE) { + return -EBUSY; + } + + cli->req.addr = addr; + cli->req.params = params; + cli->req.type = type; + + return 0; +} + +static int req_wait(struct bt_mesh_dfu_cli *cli, k_timeout_t timeout) +{ + int err; + + err = k_sem_take(&cli->req.sem, timeout); + cli->req.type = REQ_NONE; + + return err; +} + +static bool targets_active(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfu_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_DFU_SUCCESS) { + return true; + } + } + + return false; +} + +/******************************************************************************* + * Blob client + ******************************************************************************/ +static void refresh(struct bt_mesh_dfu_cli *cli); + +static void blob_caps(struct bt_mesh_blob_cli *b, + const struct bt_mesh_blob_cli_caps *caps) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + int err; + + if (!caps) { + dfu_failed(cli, BT_MESH_DFU_ERR_RESOURCES); + return; + } + + cli->xfer.blob.block_size_log = caps->max_block_size_log; + cli->xfer.blob.chunk_size = caps->max_chunk_size; + + /* If mode is not already set and server reported it supports all modes + * default to PUSH, otherwise set value reported by server. If mode + * was set and server supports all modes, keep old value; set + * reported value otherwise. + */ + if (!(cli->xfer.blob.mode & BT_MESH_BLOB_XFER_MODE_ALL)) { + cli->xfer.blob.mode = + caps->modes == BT_MESH_BLOB_XFER_MODE_ALL ? + BT_MESH_BLOB_XFER_MODE_PUSH : caps->modes; + } else { + cli->xfer.blob.mode = + caps->modes == BT_MESH_BLOB_XFER_MODE_ALL ? + cli->xfer.blob.mode : caps->modes; + } + + err = bt_mesh_blob_cli_send(b, b->inputs, &cli->xfer.blob, cli->xfer.io); + if (err) { + LOG_ERR("Starting BLOB xfer failed: %d", err); + dfu_failed(cli, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); + } +} + +static void blob_lost_target(struct bt_mesh_blob_cli *b, + struct bt_mesh_blob_target *blobt, + enum bt_mesh_blob_status reason) +{ + struct bt_mesh_dfu_target *target = + CONTAINER_OF(blobt, struct bt_mesh_dfu_target, blob); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + if ((cli->xfer.state == STATE_CONFIRM || cli->xfer.state == STATE_APPLY) && + target->effect == BT_MESH_DFU_EFFECT_UNPROV) { + /* Reset status for such targets to use them in consequent procedures. See sections + * 7.1.2.6 and 7.1.2.9 of the MeshDFU. + */ + target->blob.status = BT_MESH_BLOB_SUCCESS; + return; + } + + target_failed(cli, target, BT_MESH_DFU_ERR_INTERNAL); +} + +static void blob_suspended(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + LOG_DBG("BLOB transfer suspended"); + + cli->xfer.state = STATE_SUSPENDED; + + if (cli->cb && cli->cb->suspended) { + cli->cb->suspended(cli); + } +} + +static void blob_end(struct bt_mesh_blob_cli *b, + const struct bt_mesh_blob_xfer *xfer, bool success) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + cli->req.img_cb = NULL; + + if (success) { + refresh(cli); + return; + } + + if (cli->xfer.state == STATE_CANCEL) { + /* The user cancelled the transfer, DFU will end when all + * targets have been notified. + */ + return; + } + + if (cli->xfer.state != STATE_TRANSFER) { + LOG_ERR("Blob failed in invalid state %u", cli->xfer.state); + return; + } + + dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); +} + +const struct bt_mesh_blob_cli_cb _bt_mesh_dfu_cli_blob_handlers = { + .caps = blob_caps, + .lost_target = blob_lost_target, + .suspended = blob_suspended, + .end = blob_end, +}; + +/******************************************************************************* + * Message sending + ******************************************************************************/ + +static void tx_start(uint16_t dur, int err, void *cb_data); +static void tx_end(int err, void *cb_data); + +static const struct bt_mesh_send_cb send_cb = { + .start = tx_start, + .end = tx_end, +}; + +static void tx_start(uint16_t dur, int err, void *cb_data) +{ + if (err) { + tx_end(err, cb_data); + } +} + +static void tx_end(int err, void *cb_data) +{ + struct bt_mesh_dfu_cli *cli = cb_data; + + blob_cli_broadcast_tx_complete(&cli->blob); +} + +static int tx(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf, const struct bt_mesh_send_cb *cb, + struct bt_mesh_dfu_cli *cli) +{ + int err; + + err = bt_mesh_model_send(mod, ctx, buf, cb, cli); + if (err) { + LOG_ERR("Send err: %d", err); + if (cb) { + cb->end(err, cli); + } + return err; + } + + return 0; +} + +static int info_get(struct bt_mesh_dfu_cli *cli, struct bt_mesh_msg_ctx *ctx, + uint8_t idx, uint8_t max_count, + const struct bt_mesh_send_cb *cb) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_INFO_GET, 2); + bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_INFO_GET); + net_buf_simple_add_u8(&buf, idx); + net_buf_simple_add_u8(&buf, max_count); + + return tx(cli->mod, ctx, &buf, cb, cli); +} + +static void send_info_get(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + + cli->req.img_cnt = 0xff; + + info_get(cli, &ctx, 0, cli->req.img_cnt, &send_cb); +} + +static void send_update_start(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + struct bt_mesh_dfu_target *target; + + if (b->tx.ctx.force_unicast) { + target = target_get(cli, dst); + } else { + target = SYS_SLIST_PEEK_HEAD_CONTAINER( + (sys_slist_t *)&((cli)->blob.inputs)->targets, + target, blob.n); + } + + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_START, + DFU_UPDATE_START_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_START); + + net_buf_simple_add_u8(&buf, cli->blob.inputs->ttl); + net_buf_simple_add_le16(&buf, cli->blob.inputs->timeout_base); + net_buf_simple_add_le64(&buf, cli->xfer.blob.id); + net_buf_simple_add_u8(&buf, target->img_idx); + net_buf_simple_add_mem(&buf, cli->xfer.slot->metadata, + cli->xfer.slot->metadata_len); + + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); +} + +static void send_update_get(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_GET); + + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); +} + +static void send_update_cancel(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_CANCEL, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_CANCEL); + + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); +} + +static void send_update_apply(struct bt_mesh_blob_cli *b, uint16_t dst) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_APPLY, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_APPLY); + + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); +} + +/******************************************************************************* + * Distribution procedure + ******************************************************************************/ +static void transfer(struct bt_mesh_blob_cli *b); +static void apply(struct bt_mesh_dfu_cli *cli); +static void applied(struct bt_mesh_blob_cli *b); +static void confirmed(struct bt_mesh_blob_cli *b); +static void cancelled(struct bt_mesh_blob_cli *b); + +static void initiate(struct bt_mesh_dfu_cli *cli) +{ + struct blob_cli_broadcast_ctx tx = { + .send = send_update_start, + .next = transfer, + .acked = true, + }; + struct bt_mesh_dfu_target *target; + int img_idx = -1; + + /** If firmware img index is the same for all targets, we can send Firmware Update Start + * message using multicast address. Otherwise, it has to be send in a unicast way. + */ + TARGETS_FOR_EACH(cli, target) { + if (img_idx == -1) { + img_idx = target->img_idx; + } else if (target->img_idx != img_idx) { + tx.force_unicast = true; + break; + } + } + + LOG_DBG(""); + + cli->op = BT_MESH_DFU_OP_UPDATE_STATUS; + cli->xfer.state = STATE_TRANSFER; + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void skip_targets_from_broadcast(struct bt_mesh_dfu_cli *cli, bool skip) +{ + struct bt_mesh_dfu_target *target; + + TARGETS_FOR_EACH(cli, target) { + /* If distributor is in the targets list, or target is in Verify phase, + * disable it until Retrieve Capabilities and BLOB Transfer procedures + * are completed. + */ + if (bt_mesh_has_addr(target->blob.addr) || + target->phase == BT_MESH_DFU_PHASE_VERIFY) { + target->blob.skip = skip; + break; + } + } +} + +static bool transfer_skip(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfu_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (!bt_mesh_has_addr(target->blob.addr) || !target->blob.skip) { + return false; + } + } + + return true; +} + +static void transfer(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + int err; + + LOG_DBG(""); + + if (!targets_active(cli)) { + dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); + return; + } + + skip_targets_from_broadcast(cli, true); + + if (transfer_skip(cli)) { + /* If distributor only updates itself, or all targets are in Verify phase, + * proceed to the refresh step immediately. + */ + refresh(cli); + return; + } + + if (cli->xfer.flags & FLAG_RESUME) { + cli->xfer.flags ^= FLAG_RESUME; + err = bt_mesh_blob_cli_resume(b); + if (err) { + LOG_ERR("Resuming BLOB xfer failed: %d", err); + dfu_failed(cli, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); + } + } else if (cli->xfer.flags & FLAG_SKIP_CAPS_GET) { + cli->xfer.flags ^= FLAG_SKIP_CAPS_GET; + err = bt_mesh_blob_cli_send(b, b->inputs, &cli->xfer.blob, cli->xfer.io); + if (err) { + LOG_ERR("Starting BLOB xfer failed: %d", err); + dfu_failed(cli, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); + } + } else { + err = bt_mesh_blob_cli_caps_get(&cli->blob, cli->blob.inputs); + if (err) { + LOG_ERR("Failed starting blob xfer: %d", err); + dfu_failed(cli, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); + } + } +} + +static void refreshed(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + if (!targets_active(cli)) { + dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); + return; + } + + cli->xfer.state = STATE_VERIFIED; + dfu_complete(cli); +} + +static void refresh(struct bt_mesh_dfu_cli *cli) +{ + const struct blob_cli_broadcast_ctx tx = { + .send = send_update_get, + .next = refreshed, + .acked = true + }; + + LOG_DBG(""); + + cli->xfer.state = STATE_REFRESH; + cli->op = BT_MESH_DFU_OP_UPDATE_STATUS; + + /* If distributor is in the targets list, enable it again so it participates in Distribute + * Firmware procedure. + */ + skip_targets_from_broadcast(cli, false); + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void apply(struct bt_mesh_dfu_cli *cli) +{ + const struct blob_cli_broadcast_ctx tx = { + .send = send_update_apply, + .next = applied, + .acked = true + }; + + LOG_DBG(""); + + cli->xfer.state = STATE_APPLY; + cli->op = BT_MESH_DFU_OP_UPDATE_STATUS; + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void applied(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + if (!targets_active(cli)) { + dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); + return; + } + + dfu_applied(cli); +} + +static enum bt_mesh_dfu_iter target_img_cb(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + uint8_t idx, uint8_t cnt, + const struct bt_mesh_dfu_img *img, + void *cb_data) +{ + struct bt_mesh_dfu_target *target; + + if ((img->fwid_len != cli->xfer.slot->fwid_len) || + memcmp(cli->xfer.slot->fwid, img->fwid, img->fwid_len)) { + return BT_MESH_DFU_ITER_CONTINUE; + } + + target = target_get(cli, ctx->addr); + if (target) { + LOG_DBG("SUCCESS: 0x%04x applied dfu (as image %u)", ctx->addr, + idx); + target->phase = BT_MESH_DFU_PHASE_APPLY_SUCCESS; + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + } else { + LOG_WRN("Target 0x%04x not found", ctx->addr); + } + + return BT_MESH_DFU_ITER_STOP; +} + +static void confirm(struct bt_mesh_dfu_cli *cli) +{ + const struct blob_cli_broadcast_ctx tx = { + .send = send_info_get, + .next = confirmed, + .acked = true, + .optional = true, + }; + + LOG_DBG(""); + + cli->op = BT_MESH_DFU_OP_UPDATE_INFO_STATUS; + cli->req.img_cb = target_img_cb; + cli->req.ttl = cli->blob.inputs->ttl; + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void confirmed(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_dfu_target *target; + bool success = false; + + cli->req.img_cb = NULL; + + TARGETS_FOR_EACH(cli, target) { + if (target->status != BT_MESH_DFU_SUCCESS) { + /* Target either failed at earlier stage or during confirmation. In any + * case, the app is already notified. Don't consider the target here. + */ + continue; + } + + if (target->effect == BT_MESH_DFU_EFFECT_UNPROV) { + if (!target->blob.acked) { + success = true; + continue; + } + + LOG_DBG("Target 0x%04x still provisioned", target->blob.addr); + target->phase = BT_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BT_MESH_DFU_ERR_INTERNAL); + } else if (!target->blob.acked) { + LOG_DBG("Target 0x%04x failed to respond", target->blob.addr); + target->phase = BT_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BT_MESH_DFU_ERR_INTERNAL); + } else if (target->status == BT_MESH_DFU_SUCCESS) { + success = true; + } + } + + if (success) { + cli->xfer.state = STATE_IDLE; + cli->xfer.flags = FLAG_COMPLETED; + + if (cli->cb && cli->cb->confirmed) { + cli->cb->confirmed(cli); + } + } else { + dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); + } +} + +static void cancel(struct bt_mesh_dfu_cli *cli) +{ + const struct blob_cli_broadcast_ctx tx = { + .send = send_update_cancel, + .next = cancelled, + .acked = true + }; + + LOG_DBG(""); + + cli->op = BT_MESH_DFU_OP_UPDATE_STATUS; + + blob_cli_broadcast(&cli->blob, &tx); +} + +static void cancelled(struct bt_mesh_blob_cli *b) +{ + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + + cli->xfer.flags |= FLAG_CANCELLED; + dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); +} + +/******************************************************************************* + * Message handlers + ******************************************************************************/ + +static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; + enum bt_mesh_dfu_status status; + enum bt_mesh_dfu_phase phase; + struct bt_mesh_dfu_target *target; + uint8_t byte; + + byte = net_buf_simple_pull_u8(buf); + status = byte & BIT_MASK(3); + phase = byte >> 5; + + if (cli->req.type == REQ_STATUS && cli->req.addr == ctx->addr) { + if (cli->req.params) { + struct bt_mesh_dfu_target_status *rsp = cli->req.params; + + rsp->status = status; + rsp->phase = phase; + if (buf->len == 13) { + rsp->ttl = net_buf_simple_pull_u8(buf); + rsp->effect = net_buf_simple_pull_u8(buf) & BIT_MASK(5); + rsp->timeout_base = net_buf_simple_pull_le16(buf); + rsp->blob_id = net_buf_simple_pull_le64(buf); + rsp->img_idx = net_buf_simple_pull_u8(buf); + } else if (buf->len) { + return -EINVAL; + } + + rsp->ttl = 0U; + rsp->effect = BT_MESH_DFU_EFFECT_NONE; + rsp->timeout_base = 0U; + rsp->blob_id = 0U; + rsp->img_idx = 0U; + } + k_sem_give(&cli->req.sem); + } + if (cli->op != BT_MESH_DFU_OP_UPDATE_STATUS) { + return 0; + } + + target = target_get(cli, ctx->addr); + if (!target) { + LOG_WRN("Unknown target 0x%04x", ctx->addr); + return -ENOENT; + } + + LOG_DBG("%u phase: %u, cur state: %u", status, phase, cli->xfer.state); + + target->phase = phase; + + if (cli->xfer.state == STATE_APPLY && phase == BT_MESH_DFU_PHASE_IDLE && + status == BT_MESH_DFU_ERR_WRONG_PHASE) { + LOG_DBG("Response received with Idle phase"); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + + if (status != BT_MESH_DFU_SUCCESS) { + target_failed(cli, target, status); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + + if (buf->len == 13) { + net_buf_simple_pull_u8(buf); /* ttl */ + target->effect = net_buf_simple_pull_u8(buf) & BIT_MASK(5); + net_buf_simple_pull_le16(buf); /* timeout */ + + if (net_buf_simple_pull_le64(buf) != cli->xfer.blob.id) { + LOG_WRN("Invalid BLOB ID"); + target_failed(cli, target, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + + target->img_idx = net_buf_simple_pull_u8(buf); + + LOG_DBG("Target 0x%04x receiving transfer", ctx->addr); + } else if (buf->len) { + return -EINVAL; + } + + if (cli->xfer.state == STATE_REFRESH) { + if (phase == BT_MESH_DFU_PHASE_VERIFY) { + LOG_DBG("Still pending..."); + return 0; + } else if (phase == BT_MESH_DFU_PHASE_VERIFY_FAIL) { + LOG_WRN("Verification failed on target 0x%04x", + target->blob.addr); + target_failed(cli, target, BT_MESH_DFU_ERR_WRONG_PHASE); + } + } else if (cli->xfer.state == STATE_APPLY) { + if (phase != BT_MESH_DFU_PHASE_APPLYING && + (target->effect == BT_MESH_DFU_EFFECT_UNPROV || + phase != BT_MESH_DFU_PHASE_IDLE)) { + LOG_WRN("Target 0x%04x in phase %u after apply", + target->blob.addr, phase); + target_failed(cli, target, BT_MESH_DFU_ERR_WRONG_PHASE); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + return 0; + } else if (cli->xfer.state == STATE_CONFIRM) { + if (phase == BT_MESH_DFU_PHASE_APPLYING) { + LOG_DBG("Still pending..."); + return 0; + } + + if (phase != BT_MESH_DFU_PHASE_IDLE) { + LOG_WRN("Target 0x%04x in phase %u after apply", + target->blob.addr, phase); + target->phase = BT_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BT_MESH_DFU_ERR_WRONG_PHASE); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + } else if (cli->xfer.state == STATE_CANCEL) { + target->phase = BT_MESH_DFU_PHASE_TRANSFER_CANCELED; + } + + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + + return 0; +} + +static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; + struct bt_mesh_dfu_target *target; + enum bt_mesh_dfu_iter it = BT_MESH_DFU_ITER_CONTINUE; + uint8_t img_cnt, idx; + + if (!cli->req.img_cb || + (cli->req.type == REQ_IMG && cli->req.addr != ctx->addr)) { + LOG_WRN("Unexpected info status from 0x%04x", ctx->addr); + return 0; + } + + img_cnt = net_buf_simple_pull_u8(buf); + if (img_cnt < cli->req.img_cnt) { + cli->req.img_cnt = img_cnt; + } + + idx = net_buf_simple_pull_u8(buf); + if (idx >= img_cnt) { + LOG_WRN("Invalid idx %u", idx); + return -ENOENT; + } + + LOG_DBG("Image list from 0x%04x from index %u", ctx->addr, idx); + + while (buf->len && cli->req.img_cb && idx < cli->req.img_cnt) { + char uri_buf[CONFIG_BT_MESH_DFU_URI_MAXLEN + 1]; + struct bt_mesh_dfu_img img; + size_t uri_len; + + img.fwid_len = net_buf_simple_pull_u8(buf); + if (buf->len < img.fwid_len + 1) { + LOG_WRN("Invalid format: fwid"); + return -EINVAL; + } + + img.fwid = net_buf_simple_pull_mem(buf, img.fwid_len); + + uri_len = net_buf_simple_pull_u8(buf); + if (buf->len < uri_len) { + LOG_WRN("Invalid format: uri"); + return -EINVAL; + } + + LOG_DBG("\tImage %u\n\r\tfwid: %s", idx, bt_hex(img.fwid, img.fwid_len)); + + if (uri_len) { + size_t uri_buf_len = + MIN(CONFIG_BT_MESH_DFU_URI_MAXLEN, uri_len); + + memcpy(uri_buf, net_buf_simple_pull_mem(buf, uri_len), + uri_buf_len); + uri_buf[uri_buf_len] = '\0'; + img.uri = uri_buf; + } else { + img.uri = NULL; + } + + it = cli->req.img_cb(cli, ctx, idx, img_cnt, &img, + cli->req.params); + if (it != BT_MESH_DFU_ITER_CONTINUE) { + if (cli->req.type == REQ_IMG) { + k_sem_give(&cli->req.sem); + } + + return 0; + } + + idx++; + } + + if (idx < cli->req.img_cnt) { + LOG_DBG("Fetching more images (%u/%u)", idx, cli->req.img_cnt); + ctx->send_ttl = cli->req.ttl; + info_get(cli, ctx, idx, cli->req.img_cnt - idx, + (cli->req.type == REQ_IMG) ? NULL : &send_cb); + return 0; + } + + if (cli->req.type == REQ_IMG) { + k_sem_give(&cli->req.sem); + return 0; + } + + /* Confirm-procedure termination: */ + target = target_get(cli, ctx->addr); + if (target) { + LOG_WRN("Target 0x%04x failed to apply image: %s", ctx->addr, + bt_hex(cli->xfer.slot->fwid, cli->xfer.slot->fwid_len)); + target->phase = BT_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BT_MESH_DFU_ERR_INTERNAL); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + } + + return 0; +} + +static int handle_metadata_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; + struct bt_mesh_dfu_metadata_status *rsp = cli->req.params; + uint8_t hdr, idx; + + hdr = net_buf_simple_pull_u8(buf); + idx = net_buf_simple_pull_u8(buf); + + if (cli->req.type != REQ_METADATA || ctx->addr != cli->req.addr || + idx != rsp->idx) { + LOG_WRN("Unexpected metadata status from 0x%04x img %u", + ctx->addr, idx); + if (cli->req.type != REQ_METADATA) { + LOG_WRN("Expected %u", cli->req.type); + } else { + LOG_WRN("Expected 0x%04x img %u", cli->req.addr, idx); + } + + return 0; + } + + rsp->status = hdr & BIT_MASK(3); + rsp->effect = (hdr >> 3); + k_sem_give(&cli->req.sem); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[] = { + {BT_MESH_DFU_OP_UPDATE_STATUS, BT_MESH_LEN_MIN(1), handle_status}, + {BT_MESH_DFU_OP_UPDATE_INFO_STATUS, BT_MESH_LEN_MIN(2), handle_info_status}, + {BT_MESH_DFU_OP_UPDATE_METADATA_STATUS, BT_MESH_LEN_EXACT(2), handle_metadata_status}, + BT_MESH_MODEL_OP_END, +}; + +static int dfu_cli_init(const struct bt_mesh_model *mod) +{ + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; + + if (mod->rt->elem_idx != 0) { + LOG_ERR("DFU update client must be instantiated on first elem"); + return -EINVAL; + } + + cli->mod = mod; + + if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) { + bt_mesh_model_extend(mod, cli->blob.mod); + } + + k_sem_init(&cli->req.sem, 0, 1); + + return 0; +} + +static void dfu_cli_reset(const struct bt_mesh_model *mod) +{ + struct bt_mesh_dfu_cli *cli = mod->rt->user_data; + + cli->req.type = REQ_NONE; + cli->req.addr = BT_MESH_ADDR_UNASSIGNED; + cli->req.img_cnt = 0; + cli->req.img_cb = NULL; + cli->xfer.state = STATE_IDLE; + cli->xfer.flags = 0; +} + +const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb = { + .init = dfu_cli_init, + .reset = dfu_cli_reset, +}; + +/******************************************************************************* + * Public API + ******************************************************************************/ + +int bt_mesh_dfu_cli_send(struct bt_mesh_dfu_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_io *io, + const struct bt_mesh_dfu_cli_xfer *xfer) +{ + struct bt_mesh_dfu_target *target; + + if (bt_mesh_dfu_cli_is_busy(cli)) { + return -EBUSY; + } + + cli->xfer.blob.mode = xfer->mode; + cli->xfer.blob.size = xfer->slot->size; + + if (xfer->blob_id == 0) { + int err = bt_rand(&cli->xfer.blob.id, sizeof(cli->xfer.blob.id)); + + if (err) { + return err; + } + } else { + cli->xfer.blob.id = xfer->blob_id; + } + + cli->xfer.io = io; + cli->blob.inputs = inputs; + cli->xfer.slot = xfer->slot; + cli->xfer.flags = 0U; + + if (xfer->blob_params) { + cli->xfer.flags |= FLAG_SKIP_CAPS_GET; + cli->xfer.blob.block_size_log = xfer->blob_params->block_size_log; + cli->xfer.blob.chunk_size = xfer->blob_params->chunk_size; + } + + /* Phase will be set based on target status messages: */ + TARGETS_FOR_EACH(cli, target) { + target->status = BT_MESH_DFU_SUCCESS; + target->phase = BT_MESH_DFU_PHASE_UNKNOWN; + } + + initiate(cli); + return 0; +} + +int bt_mesh_dfu_cli_suspend(struct bt_mesh_dfu_cli *cli) +{ + int err; + + err = bt_mesh_blob_cli_suspend(&cli->blob); + if (!err) { + cli->xfer.state = STATE_SUSPENDED; + } + + return err; +} + +int bt_mesh_dfu_cli_resume(struct bt_mesh_dfu_cli *cli) +{ + struct bt_mesh_dfu_target *target; + + if (cli->xfer.state != STATE_SUSPENDED) { + return -EINVAL; + } + + cli->xfer.flags = FLAG_RESUME; + + /* Restore timed out targets. */ + TARGETS_FOR_EACH(cli, target) { + if (!!target->blob.timedout) { + target->status = BT_MESH_DFU_SUCCESS; + target->phase = BT_MESH_DFU_PHASE_UNKNOWN; + } + } + + initiate(cli); + return 0; +} + +int bt_mesh_dfu_cli_cancel(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx) +{ + if (ctx) { + int err; + + err = req_setup(cli, REQ_STATUS, ctx->addr, NULL); + if (err) { + return err; + } + + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_CANCEL, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_CANCEL); + + err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); + if (err) { + cli->req.type = REQ_NONE; + return err; + } + + return req_wait(cli, K_MSEC(dfu_cli_timeout)); + } + + if (cli->xfer.state == STATE_IDLE) { + return -EALREADY; + } + + cli->xfer.state = STATE_CANCEL; + blob_cli_broadcast_abort(&cli->blob); + cancel(cli); + return 0; +} + +int bt_mesh_dfu_cli_apply(struct bt_mesh_dfu_cli *cli) +{ + if (cli->xfer.state != STATE_VERIFIED) { + return -EBUSY; + } + + apply(cli); + + return 0; +} + +int bt_mesh_dfu_cli_confirm(struct bt_mesh_dfu_cli *cli) +{ + if (cli->xfer.state != STATE_APPLIED) { + return -EBUSY; + } + + cli->xfer.state = STATE_CONFIRM; + confirm(cli); + + return 0; +} + +uint8_t bt_mesh_dfu_cli_progress(struct bt_mesh_dfu_cli *cli) +{ + if (cli->xfer.state == STATE_TRANSFER) { + return bt_mesh_blob_cli_xfer_progress_active_get(&cli->blob); + } + + if (cli->xfer.state == STATE_IDLE) { + if (cli->xfer.flags & FLAG_COMPLETED) { + return 100U; + } + return 0U; + } + + return 100U; +} + +bool bt_mesh_dfu_cli_is_busy(struct bt_mesh_dfu_cli *cli) +{ + return (cli->xfer.state == STATE_TRANSFER || + cli->xfer.state == STATE_REFRESH || + cli->xfer.state == STATE_APPLY || + cli->xfer.state == STATE_CONFIRM) && + !(cli->xfer.flags & FLAG_FAILED); +} + +int bt_mesh_dfu_cli_imgs_get(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + bt_mesh_dfu_img_cb_t cb, void *cb_data, + uint8_t max_count) +{ + int err; + + if (cli->req.img_cb) { + return -EBUSY; + } + + err = req_setup(cli, REQ_IMG, ctx->addr, NULL); + if (err) { + return err; + } + + cli->req.img_cb = cb; + cli->req.params = cb_data; + cli->req.ttl = ctx->send_ttl; + cli->req.img_cnt = max_count; + + err = info_get(cli, ctx, 0, cli->req.img_cnt, NULL); + if (err) { + cli->req.img_cb = NULL; + cli->req.type = REQ_NONE; + return err; + } + + err = req_wait(cli, K_MSEC(dfu_cli_timeout)); + + cli->req.img_cb = NULL; + + return err; +} + +int bt_mesh_dfu_cli_metadata_check(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, uint8_t img_idx, + const struct bt_mesh_dfu_slot *slot, + struct bt_mesh_dfu_metadata_status *rsp) +{ + int err; + + err = req_setup(cli, REQ_METADATA, ctx->addr, rsp); + if (err) { + return err; + } + + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_METADATA_CHECK, + 1 + CONFIG_BT_MESH_DFU_METADATA_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_METADATA_CHECK); + + net_buf_simple_add_u8(&buf, img_idx); + + if (slot->metadata_len) { + net_buf_simple_add_mem(&buf, slot->metadata, + slot->metadata_len); + } + + rsp->idx = img_idx; + + err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); + if (err) { + cli->req.type = REQ_NONE; + return err; + } + + return req_wait(cli, K_MSEC(dfu_cli_timeout)); +} + +int bt_mesh_dfu_cli_status_get(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_dfu_target_status *rsp) +{ + int err; + + err = req_setup(cli, REQ_STATUS, ctx->addr, rsp); + if (err) { + return err; + } + + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_GET); + + err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); + if (err) { + cli->req.type = REQ_NONE; + return err; + } + + return req_wait(cli, K_MSEC(dfu_cli_timeout)); +} + +int32_t bt_mesh_dfu_cli_timeout_get(void) +{ + return dfu_cli_timeout; +} + +void bt_mesh_dfu_cli_timeout_set(int32_t t) +{ + dfu_cli_timeout = t; +} diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c new file mode 100644 index 0000000000..51a2cd0306 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include "crypto.h" +#include "access.h" + +int bt_mesh_dfu_metadata_decode(struct net_buf_simple *buf, + struct bt_mesh_dfu_metadata *metadata) +{ + if (buf->len < 12) { + return -EMSGSIZE; + } + + metadata->fw_ver.major = net_buf_simple_pull_u8(buf); + metadata->fw_ver.minor = net_buf_simple_pull_u8(buf); + metadata->fw_ver.revision = net_buf_simple_pull_le16(buf); + metadata->fw_ver.build_num = net_buf_simple_pull_le32(buf); + metadata->fw_size = net_buf_simple_pull_le24(buf); + metadata->fw_core_type = net_buf_simple_pull_u8(buf); + + if (metadata->fw_core_type & BT_MESH_DFU_FW_CORE_TYPE_APP) { + if (buf->len < 6) { + return -EMSGSIZE; + } + + metadata->comp_hash = net_buf_simple_pull_le32(buf); + metadata->elems = net_buf_simple_pull_le16(buf); + } + + metadata->user_data = buf->len > 0 ? buf->data : NULL; + metadata->user_data_len = buf->len; + + return 0; +} + + +int bt_mesh_dfu_metadata_encode(const struct bt_mesh_dfu_metadata *metadata, + struct net_buf_simple *buf) +{ + size_t md_len_min = 12 + metadata->user_data_len; + + if (metadata->fw_core_type & BT_MESH_DFU_FW_CORE_TYPE_APP) { + md_len_min += 6; + } + + if (net_buf_simple_tailroom(buf) < md_len_min) { + return -EMSGSIZE; + } + + net_buf_simple_add_u8(buf, metadata->fw_ver.major); + net_buf_simple_add_u8(buf, metadata->fw_ver.minor); + net_buf_simple_add_le16(buf, metadata->fw_ver.revision); + net_buf_simple_add_le32(buf, metadata->fw_ver.build_num); + net_buf_simple_add_le24(buf, metadata->fw_size); + net_buf_simple_add_u8(buf, metadata->fw_core_type); + net_buf_simple_add_le32(buf, metadata->comp_hash); + net_buf_simple_add_le16(buf, metadata->elems); + + if (metadata->user_data_len > 0) { + net_buf_simple_add_mem(buf, metadata->user_data, metadata->user_data_len); + } + + return 0; +} + +int bt_mesh_dfu_metadata_comp_hash_get(struct net_buf_simple *buf, uint8_t *key, uint32_t *hash) +{ + uint8_t mac[16]; + int err; + struct bt_mesh_sg sg = {.data = buf->data, .len = buf->len}; + + err = bt_mesh_aes_cmac_raw_key(key, &sg, 1, mac); + if (err) { + return err; + } + + *hash = sys_get_le32(mac); + + return 0; +} + +int bt_mesh_dfu_metadata_comp_hash_local_get(uint8_t *key, uint32_t *hash) +{ + NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX); + int err; + + err = bt_mesh_comp_data_get_page_0(&buf, 0); + if (err) { + return err; + } + + err = bt_mesh_dfu_metadata_comp_hash_get(&buf, key, hash); + return err; +} diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c new file mode 100644 index 0000000000..c11c16d44f --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "dfu_slot.h" +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_mesh_dfu_slot); + +#define SLOT_ENTRY_BUFLEN 25 + +#define DFU_SLOT_SETTINGS_PATH "bt/mesh-dfu/slot" + +#define HEADER_SIZE offsetof(struct slot, slot.fwid) + +#define PROP_HEADER "h" +#define PROP_FWID "id" +#define PROP_METADATA "m" + +static sys_slist_t list; + +static struct slot { + uint32_t idx; + struct bt_mesh_dfu_slot slot; + sys_snode_t n; +} slots[CONFIG_BT_MESH_DFU_SLOT_CNT]; + +static uint32_t slot_index; + +static char *slot_entry_encode(uint16_t idx, char buf[SLOT_ENTRY_BUFLEN], + const char *property) +{ + snprintf(buf, SLOT_ENTRY_BUFLEN, DFU_SLOT_SETTINGS_PATH "/%x/%s", idx, + property); + + return buf; +} + +static bool slot_eq(const struct bt_mesh_dfu_slot *slot, + const uint8_t *fwid, size_t fwid_len) +{ + return (slot->fwid_len == fwid_len) && + !memcmp(fwid, slot->fwid, fwid_len); +} + +static bool is_slot_committed(struct slot *slot_to_check) +{ + struct slot *s; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (s == slot_to_check) { + return true; + } + } + + return false; +} + +static int slot_store(const struct slot *slot_to_store) +{ + uint16_t idx = ARRAY_INDEX(slots, slot_to_store); + char buf[SLOT_ENTRY_BUFLEN]; + int err; + + err = settings_save_one(slot_entry_encode(idx, buf, PROP_HEADER), + slot_to_store, HEADER_SIZE); + if (err) { + return err; + } + + err = settings_save_one(slot_entry_encode(idx, buf, PROP_FWID), + slot_to_store->slot.fwid, slot_to_store->slot.fwid_len); + if (err) { + return err; + } + + err = settings_save_one(slot_entry_encode(idx, buf, + PROP_METADATA), + slot_to_store->slot.metadata, slot_to_store->slot.metadata_len); + + return err; +} + +static void slot_erase(struct slot *slot_to_erase) +{ + uint16_t idx = ARRAY_INDEX(slots, slot_to_erase); + char buf[SLOT_ENTRY_BUFLEN]; + + (void)settings_delete(slot_entry_encode(idx, buf, PROP_HEADER)); + (void)settings_delete(slot_entry_encode(idx, buf, PROP_FWID)); + (void)settings_delete(slot_entry_encode(idx, buf, PROP_METADATA)); +} + +static void slot_index_defrag(void) +{ + slot_index = 0; + struct slot *s; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + s->idx = ++slot_index; + slot_store(s); + } +} + +int bt_mesh_dfu_slot_count(void) +{ + int cnt = 0; + sys_snode_t *n; + + SYS_SLIST_FOR_EACH_NODE(&list, n) { + cnt++; + } + + return cnt; +} + +struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_reserve(void) +{ + struct slot *slot = NULL; + + for (int i = 0; i < ARRAY_SIZE(slots); ++i) { + if (slots[i].idx == 0) { + slot = &slots[i]; + break; + } + } + + if (!slot) { + LOG_WRN("No space"); + return NULL; + } + + if (slot_index == UINT32_MAX) { + slot_index_defrag(); + } + + slot->slot.fwid_len = 0; + slot->slot.metadata_len = 0; + slot->slot.size = 0; + slot->idx = ++slot_index; + + LOG_DBG("Reserved slot #%u", slot - &slots[0]); + + return &slot->slot; +} + +int bt_mesh_dfu_slot_info_set(struct bt_mesh_dfu_slot *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len) +{ + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (metadata_len > CONFIG_BT_MESH_DFU_METADATA_MAXLEN) { + return -EFBIG; + } + + if (slot->idx == 0 || is_slot_committed(slot)) { + return -EINVAL; + } + + slot->slot.size = size; + slot->slot.metadata_len = metadata_len; + memcpy(slot->slot.metadata, metadata, metadata_len); + return 0; +} + +int bt_mesh_dfu_slot_fwid_set(struct bt_mesh_dfu_slot *dfu_slot, + const uint8_t *fwid, size_t fwid_len) +{ + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (fwid_len > CONFIG_BT_MESH_DFU_FWID_MAXLEN) { + return -EFBIG; + } + + if (slot->idx == 0 || is_slot_committed(slot)) { + return -EINVAL; + } + + for (int i = 0; i < ARRAY_SIZE(slots); i++) { + if (slots[i].idx != 0 && + slot_eq(&slots[i].slot, fwid, fwid_len)) { + return is_slot_committed(&slots[i]) ? + -EEXIST : -EALREADY; + } + } + + slot->slot.fwid_len = fwid_len; + memcpy(slot->slot.fwid, fwid, fwid_len); + return 0; +} + +int bt_mesh_dfu_slot_commit(struct bt_mesh_dfu_slot *dfu_slot) +{ + int err; + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (slot->idx == 0 || + slot->slot.fwid_len == 0 || + slot->slot.size == 0 || + is_slot_committed(slot)) { + return -EINVAL; + } + + err = slot_store(slot); + if (err) { + LOG_WRN("Store failed (err: %d)", err); + return err; + } + + sys_slist_append(&list, &slot->n); + + LOG_DBG("Stored slot #%u: %s", ARRAY_INDEX(slots, slot), + bt_hex(slot->slot.fwid, slot->slot.fwid_len)); + return 0; +} + +void bt_mesh_dfu_slot_release(const struct bt_mesh_dfu_slot *dfu_slot) +{ + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (is_slot_committed(slot)) { + return; + } + + slot->idx = 0; +} + +int bt_mesh_dfu_slot_del(const struct bt_mesh_dfu_slot *dfu_slot) +{ + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + + if (!sys_slist_find_and_remove(&list, &slot->n)) { + return -EINVAL; + } + + int idx = ARRAY_INDEX(slots, slot); + + LOG_DBG("%u", idx); + + slot_erase(slot); + slot->idx = 0; + + return 0; +} + +void bt_mesh_dfu_slot_del_all(void) +{ + struct slot *s; + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + slot_erase(s); + s->idx = 0; + } + + sys_slist_init(&list); +} + +const struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_at(uint16_t img_idx) +{ + struct slot *s; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (!img_idx--) { + return &s->slot; + } + } + + return NULL; +} + +int bt_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, struct bt_mesh_dfu_slot **slot) +{ + struct slot *s; + int idx = 0; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (slot_eq(&s->slot, fwid, fwid_len)) { + if (slot) { + *slot = &s->slot; + } + return idx; + } + idx++; + } + + return -ENOENT; +} + +int bt_mesh_dfu_slot_img_idx_get(const struct bt_mesh_dfu_slot *dfu_slot) +{ + struct slot *s; + int idx = 0; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (&s->slot == dfu_slot) { + return idx; + } + idx++; + } + + return -ENOENT; +} + +size_t bt_mesh_dfu_slot_foreach(bt_mesh_dfu_slot_cb_t cb, void *user_data) +{ + enum bt_mesh_dfu_iter iter; + size_t cnt = 0; + struct slot *s; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + cnt++; + + if (!cb) { + continue; + } + + iter = cb(&s->slot, user_data); + if (iter != BT_MESH_DFU_ITER_CONTINUE) { + break; + } + } + + return cnt; +} + +static int slot_data_load(const char *key, size_t len_rd, + settings_read_cb read_cb, void *cb_arg) +{ + const char *prop; + size_t len; + uint16_t idx; + + idx = strtol(key, NULL, 16); + + if (idx >= ARRAY_SIZE(slots)) { + return 0; + } + + len = settings_name_next(key, &prop); + + if (!strncmp(prop, PROP_HEADER, len)) { + if (read_cb(cb_arg, &slots[idx], HEADER_SIZE) > 0) { + struct slot *s, *prev = NULL; + + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (s->idx > slots[idx].idx) { + break; + } + + prev = s; + } + + if (prev == NULL) { + sys_slist_prepend(&list, &slots[idx].n); + } else { + sys_slist_insert(&list, &prev->n, &slots[idx].n); + } + + if (slots[idx].idx >= slot_index) { + slot_index = slots[idx].idx + 1; + } + } + return 0; + } + + if (!strncmp(prop, PROP_FWID, len)) { + if (read_cb(cb_arg, &slots[idx].slot.fwid, + sizeof(slots[idx].slot.fwid)) < 0) { + slots[idx].idx = 0; + sys_slist_find_and_remove(&list, &slots[idx].n); + return 0; + } + + slots[idx].slot.fwid_len = len_rd; + return 0; + } + + if (!strncmp(prop, PROP_METADATA, len)) { + if (read_cb(cb_arg, &slots[idx].slot.metadata, + sizeof(slots[idx].slot.metadata)) < 0) { + slots[idx].idx = 0; + sys_slist_find_and_remove(&list, &slots[idx].n); + return 0; + } + + slots[idx].slot.metadata_len = len_rd; + return 0; + } + + return 0; +} + +SETTINGS_STATIC_HANDLER_DEFINE(bt_mesh_dfu_slots, DFU_SLOT_SETTINGS_PATH, NULL, + slot_data_load, NULL, NULL); diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h new file mode 100644 index 0000000000..969c6d3d25 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/** @brief Slot iteration callback. + * + * @param slot A valid DFU image slot. + * @param user_data User data passed to @ref bt_mesh_dfu_slot_foreach. + * + * @return Iteration action determining next step. + */ +typedef enum bt_mesh_dfu_iter (*bt_mesh_dfu_slot_cb_t)( + const struct bt_mesh_dfu_slot *slot, void *user_data); + +/** @brief Get the number of slots committed to the firmware list. + * + * @return Number of committed slots. + */ +int bt_mesh_dfu_slot_count(void); + +/** @brief Reserve a new DFU image slot for a distributable image. + * + * A DFU image slot represents a single distributable DFU image with all its + * metadata. The slot data must be set using @ref bt_mesh_dfu_slot_info_set and + * @ref bt_mesh_dfu_slot_fwid_set, and the slot committed using + * @ref bt_mesh_dfu_slot_commit for the slot to be considered part of the slot + * list. + * + * @return A pointer to the reserved slot, or NULL if allocation failed. + */ +struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_reserve(void); + +/** @brief Set the size and metadata for a reserved slot. + * + * @param dfu_slot Pointer to the reserved slot for which to set the + * metadata. + * @param size The size of the image. + * @param metadata Metadata or NULL. + * @param metadata_len Length of the metadata, at most @c + * CONFIG_BT_MESH_DFU_METADATA_MAXLEN. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfu_slot_info_set(struct bt_mesh_dfu_slot *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len); + +/** @brief Set the new fwid for the incoming image for a reserved slot. + * + * @param dfu_slot Pointer to the reserved slot for which to set the fwid. + * @param fwid Fwid to set. + * @param fwid_len Length of the fwid, at most @c + * CONFIG_BT_MESH_DFU_FWID_MAXLEN. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfu_slot_fwid_set(struct bt_mesh_dfu_slot *dfu_slot, + const uint8_t *fwid, size_t fwid_len); + +/** @brief Commit the reserved slot to the list of slots, and store it + * persistently. + * + * If the commit fails for any reason, the slot will still be in the reserved + * state after this call. + * + * @param dfu_slot Pointer to the reserved slot. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfu_slot_commit(struct bt_mesh_dfu_slot *dfu_slot); + +/** @brief Release a reserved slot so that it can be reserved again. + * + * @param dfu_slot Pointer to the reserved slot. + */ +void bt_mesh_dfu_slot_release(const struct bt_mesh_dfu_slot *dfu_slot); + +/** @brief Delete a committed DFU image slot. + * + * @param slot Slot to delete. Must be a valid pointer acquired from this + * module. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfu_slot_del(const struct bt_mesh_dfu_slot *slot); + +/** @brief Delete all DFU image slots. + * + * @return 0 on success, or (negative) error code on failure. + */ +void bt_mesh_dfu_slot_del_all(void); + +/** @brief Get the DFU image slot at the given firmware image list index. + * + * @param idx DFU image slot index. + * + * @return The DFU image slot at the given index, or NULL if no slot exists with the + * given index. + */ +const struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_at(uint16_t img_idx); + +/** @brief Get the committed DFU image slot for the image with the given + * firmware ID. + * + * @param fwid Firmware ID. + * @param fwid_len Firmware ID length. + * @param slot Slot pointer to fill. + * + * @return Slot index on success, or negative error code on failure. + */ +int bt_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, struct bt_mesh_dfu_slot **slot); + +/** @brief Get the index in the firmware image list for the given slot. + * + * @param slot Slot to find. + * + * @return Slot index on success, or negative error code on failure. + */ +int bt_mesh_dfu_slot_img_idx_get(const struct bt_mesh_dfu_slot *slot); + +/** @brief Iterate through all DFU image slots. + * + * Calls the callback for every DFU image slot or until the callback returns + * something other than @ref BT_MESH_DFU_ITER_CONTINUE. + * + * @param cb Callback to call for each slot, or NULL to just count the + * number of slots. + * @param user_data User data to pass to the callback. + * + * @return The number of slots iterated over. + */ +size_t bt_mesh_dfu_slot_foreach(bt_mesh_dfu_slot_cb_t cb, void *user_data); diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c new file mode 100644 index 0000000000..0cb4b5e524 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "dfu.h" +#include "blob.h" +#include "access.h" + +#define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_mesh_dfu_srv); + +#define UPDATE_IDX_NONE 0xff + +BUILD_ASSERT((DFU_UPDATE_START_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_START) + + BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, + "The Firmware Update Start message does not fit into the maximum incoming SDU size."); + +BUILD_ASSERT((DFU_UPDATE_INFO_STATUS_MSG_MINLEN + + BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_INFO_STATUS) + BT_MESH_MIC_SHORT) + <= BT_MESH_TX_SDU_MAX, + "The Firmware Update Info Status message does not fit into the maximum outgoing SDU " + "size."); + +static void store_state(struct bt_mesh_dfu_srv *srv) +{ + bt_mesh_model_data_store(srv->mod, false, NULL, &srv->update, + sizeof(srv->update)); +} + +static void erase_state(struct bt_mesh_dfu_srv *srv) +{ + bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0); +} + +static void xfer_failed(struct bt_mesh_dfu_srv *srv) +{ + if (!bt_mesh_dfu_srv_is_busy(srv) || + srv->update.idx >= srv->img_count) { + return; + } + + erase_state(srv); + + if (srv->cb->end) { + srv->cb->end(srv, &srv->imgs[srv->update.idx], false); + } +} + +static enum bt_mesh_dfu_status metadata_check(struct bt_mesh_dfu_srv *srv, + uint8_t idx, + struct net_buf_simple *buf, + enum bt_mesh_dfu_effect *effect) +{ + *effect = BT_MESH_DFU_EFFECT_NONE; + + if (idx >= srv->img_count) { + return BT_MESH_DFU_ERR_FW_IDX; + } + + if (!srv->cb->check) { + return BT_MESH_DFU_SUCCESS; + } + + if (srv->cb->check(srv, &srv->imgs[idx], buf, effect)) { + *effect = BT_MESH_DFU_EFFECT_NONE; + return BT_MESH_DFU_ERR_METADATA; + } + + return BT_MESH_DFU_SUCCESS; +} + +static void apply_rsp_sent(int err, void *cb_params) +{ + struct bt_mesh_dfu_srv *srv = cb_params; + + if (err) { + /* return phase back to give client one more chance. */ + srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_OK; + LOG_WRN("Apply response failed, wait for retry (err %d)", err); + return; + } + + LOG_DBG(""); + + if (!srv->cb->apply || srv->update.idx == UPDATE_IDX_NONE) { + srv->update.phase = BT_MESH_DFU_PHASE_IDLE; + store_state(srv); + LOG_DBG("Prerequisites for apply callback are wrong"); + return; + } + + store_state(srv); + + err = srv->cb->apply(srv, &srv->imgs[srv->update.idx]); + if (err) { + srv->update.phase = BT_MESH_DFU_PHASE_IDLE; + store_state(srv); + LOG_DBG("Application apply callback failed (err %d)", err); + } +} + +static void apply_rsp_sending(uint16_t duration, int err, void *cb_params) +{ + if (err) { + apply_rsp_sent(err, cb_params); + } +} + +static void verify(struct bt_mesh_dfu_srv *srv) +{ + srv->update.phase = BT_MESH_DFU_PHASE_VERIFY; + + if (srv->update.idx >= srv->img_count) { + bt_mesh_dfu_srv_rejected(srv); + return; + } + + if (!srv->cb->end) { + bt_mesh_dfu_srv_verified(srv); + return; + } + + srv->cb->end(srv, &srv->imgs[srv->update.idx], true); + if (srv->update.phase == BT_MESH_DFU_PHASE_VERIFY) { + store_state(srv); + } +} + +static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + uint8_t idx, limit; + + if (srv->update.phase == BT_MESH_DFU_PHASE_APPLYING) { + LOG_INF("Still applying, not responding"); + return -EBUSY; + } + + idx = net_buf_simple_pull_u8(buf); + limit = net_buf_simple_pull_u8(buf); + + LOG_DBG("from %u (limit: %u)", idx, limit); + + NET_BUF_SIMPLE_DEFINE(rsp, BT_MESH_TX_SDU_MAX); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFU_OP_UPDATE_INFO_STATUS); + net_buf_simple_add_u8(&rsp, srv->img_count); + net_buf_simple_add_u8(&rsp, idx); + + for (; idx < srv->img_count && limit > 0; ++idx) { + uint32_t entry_len; + + if (!srv->imgs[idx].fwid) { + continue; + } + + entry_len = 2 + srv->imgs[idx].fwid_len; + if (srv->imgs[idx].uri) { + entry_len += strlen(srv->imgs[idx].uri); + } + + if (net_buf_simple_tailroom(&rsp) + BT_MESH_MIC_SHORT < entry_len) { + break; + } + + net_buf_simple_add_u8(&rsp, srv->imgs[idx].fwid_len); + net_buf_simple_add_mem(&rsp, srv->imgs[idx].fwid, + srv->imgs[idx].fwid_len); + + if (srv->imgs[idx].uri) { + size_t len = strlen(srv->imgs[idx].uri); + + net_buf_simple_add_u8(&rsp, len); + net_buf_simple_add_mem(&rsp, srv->imgs[idx].uri, len); + } else { + net_buf_simple_add_u8(&rsp, 0); + } + + limit--; + } + + if (srv->update.phase != BT_MESH_DFU_PHASE_IDLE) { + ctx->send_ttl = srv->update.ttl; + } + + bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +static int handle_metadata_check(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + enum bt_mesh_dfu_status status; + enum bt_mesh_dfu_effect effect; + uint8_t idx; + + BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFU_OP_UPDATE_METADATA_STATUS, 2); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFU_OP_UPDATE_METADATA_STATUS); + + idx = net_buf_simple_pull_u8(buf); + status = metadata_check(srv, idx, buf, &effect); + + LOG_DBG("%u", idx); + + net_buf_simple_add_u8(&rsp, (status & BIT_MASK(3)) | (effect << 3)); + net_buf_simple_add_u8(&rsp, idx); + + if (srv->update.phase != BT_MESH_DFU_PHASE_IDLE) { + ctx->send_ttl = srv->update.ttl; + } + + bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +static void update_status_rsp(struct bt_mesh_dfu_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfu_status status, + const struct bt_mesh_send_cb *send_cb) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_STATUS, 14); + bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_STATUS); + + net_buf_simple_add_u8(&buf, ((status & BIT_MASK(3)) | + (srv->update.phase << 5))); + + if (srv->update.phase != BT_MESH_DFU_PHASE_IDLE) { + net_buf_simple_add_u8(&buf, srv->update.ttl); + net_buf_simple_add_u8(&buf, srv->update.effect); + net_buf_simple_add_le16(&buf, srv->update.timeout_base); + net_buf_simple_add_le64(&buf, srv->blob.state.xfer.id); + net_buf_simple_add_u8(&buf, srv->update.idx); + + ctx->send_ttl = srv->update.ttl; + } + + bt_mesh_model_send(srv->mod, ctx, &buf, send_cb, srv); +} + +static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + + LOG_DBG(""); + + update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, NULL); + + return 0; +} + +static inline bool is_active_update(struct bt_mesh_dfu_srv *srv, uint8_t idx, + uint16_t timeout_base, + const uint64_t *blob_id, uint8_t ttl, + uint16_t meta_checksum) +{ + return (srv->update.idx != idx || srv->blob.state.xfer.id != *blob_id || + srv->update.ttl != ttl || + srv->update.timeout_base != timeout_base || + srv->update.meta != meta_checksum); +} + +static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + const struct bt_mesh_blob_io *io; + uint16_t timeout_base, meta_checksum; + enum bt_mesh_dfu_status status; + uint8_t ttl, idx; + uint64_t blob_id; + int err; + struct net_buf_simple_state buf_state; + + ttl = net_buf_simple_pull_u8(buf); + timeout_base = net_buf_simple_pull_le16(buf); + blob_id = net_buf_simple_pull_le64(buf); + idx = net_buf_simple_pull_u8(buf); + meta_checksum = dfu_metadata_checksum(buf); + + LOG_DBG("%u ttl: %u extra time: %u", idx, ttl, timeout_base); + + if ((!buf->len || meta_checksum == srv->update.meta) && + srv->update.phase == BT_MESH_DFU_PHASE_TRANSFER_ERR && + srv->update.ttl == ttl && + srv->update.timeout_base == timeout_base && + srv->update.idx == idx && + srv->blob.state.xfer.id == blob_id) { + srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ACTIVE; + status = BT_MESH_DFU_SUCCESS; + store_state(srv); + /* blob srv will resume the transfer. */ + LOG_DBG("Resuming transfer"); + goto rsp; + } + + if (bt_mesh_dfu_srv_is_busy(srv)) { + if (is_active_update(srv, idx, timeout_base, &blob_id, ttl, + meta_checksum)) { + status = BT_MESH_DFU_ERR_WRONG_PHASE; + } else { + status = BT_MESH_DFU_SUCCESS; + srv->update.ttl = ttl; + srv->blob.state.xfer.id = blob_id; + } + + LOG_WRN("Busy. Phase: %u", srv->update.phase); + goto rsp; + } + + net_buf_simple_save(buf, &buf_state); + status = metadata_check(srv, idx, buf, + (enum bt_mesh_dfu_effect *)&srv->update.effect); + net_buf_simple_restore(buf, &buf_state); + if (status != BT_MESH_DFU_SUCCESS) { + goto rsp; + } + + srv->update.ttl = ttl; + srv->update.timeout_base = timeout_base; + srv->update.meta = meta_checksum; + + io = NULL; + err = srv->cb->start(srv, &srv->imgs[idx], buf, &io); + if (err == -EALREADY || (!err && bt_mesh_has_addr(ctx->addr))) { + /* This image has already been received or this is a + * self-update. Skip the transfer phase and proceed to + * verifying update. + */ + status = BT_MESH_DFU_SUCCESS; + srv->update.idx = idx; + srv->blob.state.xfer.id = blob_id; + srv->update.phase = BT_MESH_DFU_PHASE_VERIFY; + update_status_rsp(srv, ctx, status, NULL); + verify(srv); + return 0; + } + + if (err == -ENOMEM) { + status = BT_MESH_DFU_ERR_RESOURCES; + goto rsp; + } + + if (err == -EBUSY) { + status = BT_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE; + goto rsp; + } + + if (err || !io || !io->wr) { + status = BT_MESH_DFU_ERR_INTERNAL; + goto rsp; + } + + err = bt_mesh_blob_srv_recv(&srv->blob, blob_id, io, + ttl, timeout_base); + if (err) { + status = BT_MESH_DFU_ERR_BLOB_XFER_BUSY; + goto rsp; + } + + srv->update.idx = idx; + srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ACTIVE; + status = BT_MESH_DFU_SUCCESS; + store_state(srv); + +rsp: + update_status_rsp(srv, ctx, status, NULL); + + return 0; +} + +static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + + if (srv->update.idx == UPDATE_IDX_NONE) { + goto rsp; + } + + LOG_DBG(""); + + bt_mesh_blob_srv_cancel(&srv->blob); + srv->update.phase = BT_MESH_DFU_PHASE_IDLE; + xfer_failed(srv); + +rsp: + update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, NULL); + + return 0; +} + +static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + static const struct bt_mesh_send_cb send_cb = { + .start = apply_rsp_sending, + .end = apply_rsp_sent, + }; + + LOG_DBG(""); + + if (srv->update.phase == BT_MESH_DFU_PHASE_APPLYING) { + update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, NULL); + return 0; + } + + if (srv->update.phase != BT_MESH_DFU_PHASE_VERIFY_OK) { + LOG_WRN("Apply: Invalid phase %u", srv->update.phase); + update_status_rsp(srv, ctx, BT_MESH_DFU_ERR_WRONG_PHASE, NULL); + return 0; + } + + /* Postponing the apply callback until the response has been sent, in + * case it triggers a reboot: + */ + srv->update.phase = BT_MESH_DFU_PHASE_APPLYING; + update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, &send_cb); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[] = { + { BT_MESH_DFU_OP_UPDATE_INFO_GET, BT_MESH_LEN_EXACT(2), handle_info_get }, + { BT_MESH_DFU_OP_UPDATE_METADATA_CHECK, BT_MESH_LEN_MIN(1), handle_metadata_check }, + { BT_MESH_DFU_OP_UPDATE_GET, BT_MESH_LEN_EXACT(0), handle_get }, + { BT_MESH_DFU_OP_UPDATE_START, BT_MESH_LEN_MIN(12), handle_start }, + { BT_MESH_DFU_OP_UPDATE_CANCEL, BT_MESH_LEN_EXACT(0), handle_cancel }, + { BT_MESH_DFU_OP_UPDATE_APPLY, BT_MESH_LEN_EXACT(0), handle_apply }, + BT_MESH_MODEL_OP_END, +}; + +static int dfu_srv_init(const struct bt_mesh_model *mod) +{ + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + + srv->mod = mod; + srv->update.idx = UPDATE_IDX_NONE; + + if (!srv->cb || !srv->cb->start || !srv->imgs || srv->img_count == 0 || + srv->img_count == UPDATE_IDX_NONE) { + LOG_ERR("Invalid DFU Server initialization"); + return -EINVAL; + } + + if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) { + bt_mesh_model_extend(mod, srv->blob.mod); + } + + return 0; +} + +static int dfu_srv_settings_set(const struct bt_mesh_model *mod, const char *name, + size_t len_rd, settings_read_cb read_cb, + void *cb_arg) +{ + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + ssize_t len; + + if (len_rd < sizeof(srv->update)) { + return -EINVAL; + } + + len = read_cb(cb_arg, &srv->update, sizeof(srv->update)); + if (len < 0) { + return len; + } + + LOG_DBG("Recovered transfer (phase: %u, idx: %u)", srv->update.phase, + srv->update.idx); + if (srv->update.phase == BT_MESH_DFU_PHASE_TRANSFER_ACTIVE) { + LOG_DBG("Settings recovered mid-transfer, setting transfer error"); + srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ERR; + } else if (srv->update.phase == BT_MESH_DFU_PHASE_VERIFY_OK) { + LOG_DBG("Settings recovered before application, setting verification fail"); + srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_FAIL; + } + + return 0; +} + +static void dfu_srv_reset(const struct bt_mesh_model *mod) +{ + struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + + srv->update.phase = BT_MESH_DFU_PHASE_IDLE; + erase_state(srv); +} + +const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb = { + .init = dfu_srv_init, + .settings_set = dfu_srv_settings_set, + .reset = dfu_srv_reset, +}; + +static void blob_suspended(struct bt_mesh_blob_srv *b) +{ + struct bt_mesh_dfu_srv *srv = CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); + + srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ERR; + store_state(srv); +} + +static void blob_end(struct bt_mesh_blob_srv *b, uint64_t id, bool success) +{ + struct bt_mesh_dfu_srv *srv = + CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); + + LOG_DBG("success: %u", success); + + if (!success) { + srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ERR; + xfer_failed(srv); + return; + } + + verify(srv); +} + +static int blob_recover(struct bt_mesh_blob_srv *b, + struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io **io) +{ + struct bt_mesh_dfu_srv *srv = + CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); + + if (!srv->cb->recover || + srv->update.phase != BT_MESH_DFU_PHASE_TRANSFER_ERR || + srv->update.idx >= srv->img_count) { + return -ENOTSUP; + } + + return srv->cb->recover(srv, &srv->imgs[srv->update.idx], io); +} + +const struct bt_mesh_blob_srv_cb _bt_mesh_dfu_srv_blob_cb = { + .suspended = blob_suspended, + .end = blob_end, + .recover = blob_recover, +}; + +void bt_mesh_dfu_srv_verified(struct bt_mesh_dfu_srv *srv) +{ + if (srv->update.phase != BT_MESH_DFU_PHASE_VERIFY) { + LOG_WRN("Wrong state"); + return; + } + + LOG_DBG(""); + + srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_OK; + store_state(srv); +} + +void bt_mesh_dfu_srv_rejected(struct bt_mesh_dfu_srv *srv) +{ + if (srv->update.phase != BT_MESH_DFU_PHASE_VERIFY) { + LOG_WRN("Wrong state"); + return; + } + + LOG_DBG(""); + + srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_FAIL; + store_state(srv); +} + +void bt_mesh_dfu_srv_cancel(struct bt_mesh_dfu_srv *srv) +{ + if (srv->update.phase == BT_MESH_DFU_PHASE_IDLE) { + LOG_WRN("Wrong state"); + return; + } + + (void)bt_mesh_blob_srv_cancel(&srv->blob); +} + +void bt_mesh_dfu_srv_applied(struct bt_mesh_dfu_srv *srv) +{ + if (srv->update.phase != BT_MESH_DFU_PHASE_APPLYING) { + LOG_WRN("Wrong state"); + return; + } + + LOG_DBG(""); + + srv->update.phase = BT_MESH_DFU_PHASE_IDLE; + store_state(srv); +} + +bool bt_mesh_dfu_srv_is_busy(const struct bt_mesh_dfu_srv *srv) +{ + return srv->update.phase != BT_MESH_DFU_PHASE_IDLE && + srv->update.phase != BT_MESH_DFU_PHASE_TRANSFER_ERR && + srv->update.phase != BT_MESH_DFU_PHASE_VERIFY_FAIL; +} + +uint8_t bt_mesh_dfu_srv_progress(const struct bt_mesh_dfu_srv *srv) +{ + if (!bt_mesh_dfu_srv_is_busy(srv)) { + return 0U; + } + + if (srv->update.phase == BT_MESH_DFU_PHASE_TRANSFER_ACTIVE) { + return bt_mesh_blob_srv_progress(&srv->blob); + } + + return 100U; +} diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h new file mode 100644 index 0000000000..cddde76618 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_H__ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup bt_mesh_dfd Firmware Distribution models + * @ingroup bt_mesh + * @{ + */ + +/** Firmware distribution status. */ +enum bt_mesh_dfd_status { + /** The message was processed successfully. */ + BT_MESH_DFD_SUCCESS, + + /** Insufficient resources on the node. */ + BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES, + + /** The operation cannot be performed while the Server is in the current + * phase. + */ + BT_MESH_DFD_ERR_WRONG_PHASE, + + /** An internal error occurred on the node. */ + BT_MESH_DFD_ERR_INTERNAL, + + /** The requested firmware image is not stored on the Distributor. */ + BT_MESH_DFD_ERR_FW_NOT_FOUND, + + /** The AppKey identified by the AppKey Index is not known to the node. + */ + BT_MESH_DFD_ERR_INVALID_APPKEY_INDEX, + + /** There are no Target nodes in the Distribution Receivers List + * state. + */ + BT_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY, + + /** Another firmware image distribution is in progress. */ + BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION, + + /** Another upload is in progress. */ + BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD, + + /** The URI scheme name indicated by the Update URI is not supported. */ + BT_MESH_DFD_ERR_URI_NOT_SUPPORTED, + + /** The format of the Update URI is invalid. */ + BT_MESH_DFD_ERR_URI_MALFORMED, + + /** The URI is currently unreachable. */ + BT_MESH_DFD_ERR_URI_UNREACHABLE, + + /** The Check Firmware OOB procedure did not find any new firmware. */ + BT_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE, + + /** The suspension of the Distribute Firmware procedure failed. */ + BT_MESH_DFD_ERR_SUSPEND_FAILED, +}; + +/** Firmware distribution phases. */ +enum bt_mesh_dfd_phase { + /** No firmware distribution is in progress. */ + BT_MESH_DFD_PHASE_IDLE, + + /** Firmware distribution is in progress. */ + BT_MESH_DFD_PHASE_TRANSFER_ACTIVE, + + /** The Transfer BLOB procedure has completed successfully. */ + BT_MESH_DFD_PHASE_TRANSFER_SUCCESS, + + /** The Apply Firmware on Target Nodes procedure is being executed. */ + BT_MESH_DFD_PHASE_APPLYING_UPDATE, + + /** The Distribute Firmware procedure has completed successfully. */ + BT_MESH_DFD_PHASE_COMPLETED, + + /** The Distribute Firmware procedure has failed. */ + BT_MESH_DFD_PHASE_FAILED, + + /** The Cancel Firmware Update procedure is being executed. */ + BT_MESH_DFD_PHASE_CANCELING_UPDATE, + + /** The Transfer BLOB procedure is suspended. */ + BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED, +}; + +/** Firmware upload phases. */ +enum bt_mesh_dfd_upload_phase { + /** No firmware upload is in progress. */ + BT_MESH_DFD_UPLOAD_PHASE_IDLE, + + /** The Store Firmware procedure is being executed. */ + BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE, + + /** The Store Firmware procedure or Store Firmware OOB procedure failed. + */ + BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR, + + /** The Store Firmware procedure or the Store Firmware OOB procedure + * completed successfully. + */ + BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS, +}; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h new file mode 100644 index 0000000000..2abfbf0f90 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfd_srv Firmware Distribution Server model + * @ingroup bt_mesh_dfd + * @{ + * @brief API for the Firmware Distribution Server model + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_H__ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX +#define CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX 0 +#endif + +#ifndef CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE +#define CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE 0 +#endif + +#ifndef CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE +#define CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE 0 +#endif + +struct bt_mesh_dfd_srv; + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD +/** + * + * @brief Initialization parameters for the @ref bt_mesh_dfd_srv with OOB + * upload support. + * + * @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance. + * @param[in] _oob_schemes Array of OOB schemes supported by the server, + * each scheme being a code point from the + * Bluetooth SIG Assigned Numbers document. + * @param[in] _oob_schemes_count Number of schemes in @c _oob_schemes. + */ +#define BT_MESH_DFD_SRV_OOB_INIT(_cb, _oob_schemes, _oob_schemes_count) \ + { \ + .cb = _cb, \ + .dfu = BT_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb), \ + .upload = { \ + .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb }, \ + }, \ + .oob_schemes = { \ + .schemes = _oob_schemes, \ + .count = _oob_schemes_count, \ + }, \ + } +#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ + +/** + * + * @brief Initialization parameters for the @ref bt_mesh_dfd_srv. + * + * @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance. + */ +#define BT_MESH_DFD_SRV_INIT(_cb) \ + { \ + .cb = _cb, \ + .dfu = BT_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb), \ + .upload = { \ + .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb }, \ + }, \ + } + +/** + * + * @brief Firmware Distribution Server model Composition Data entry. + * + * @param _srv Pointer to a @ref bt_mesh_dfd_srv instance. + */ +#define BT_MESH_MODEL_DFD_SRV(_srv) \ + BT_MESH_MODEL_DFU_CLI(&(_srv)->dfu), \ + BT_MESH_MODEL_BLOB_SRV(&(_srv)->upload.blob), \ + BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_DFD_SRV, _bt_mesh_dfd_srv_op, NULL, \ + _srv, &_bt_mesh_dfd_srv_cb) + +/** Firmware Distribution Server callbacks: */ +struct bt_mesh_dfd_srv_cb { + + /** @brief Slot receive callback. + * + * Called at the start of an upload procedure. The callback must fill + * @c io with a pointer to a writable BLOB stream for the Firmware Distribution + * Server to write the firmware image to. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being received. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*recv)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, + const struct bt_mesh_blob_io **io); + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + /** @brief Firmware upload OOB start callback. + * + * Called at the start of an OOB firmware upload. The application must + * start a firmware check using an OOB mechanism, and then call + * @ref bt_mesh_dfd_srv_oob_check_complete. Depending on the return + * value of this function, the application must then start storing the + * firmware image using an OOB mechanism, and call + * @ref bt_mesh_dfd_srv_oob_store_complete. This callback is mandatory + * to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot Slot to be used for the upload. + * @param uri Pointer to buffer containing the URI used to + * check for new firmware. + * @param uri_len Length of the URI buffer. + * @param fwid Pointer to buffer containing the current + * firmware ID to be used when checking for + * availability of new firmware. + * @param fwid_len Length of the current firmware ID. Must be set + * to the length of the new firmware ID if it is + * available, or to 0 if new firmware is not + * available. + * + * @return BT_MESH_DFD_SUCCESS on success, or error code otherwise. + */ + int (*start_oob_upload)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, + const char *uri, uint8_t uri_len, + const uint8_t *fwid, uint16_t fwid_len); + + /** @brief Cancel store OOB callback + * + * Called when an OOB store is cancelled. The application must stop + * any ongoing OOB image transfer. This callback is mandatory to + * support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to cancel + */ + void (*cancel_oob_upload)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot); + + /** @brief Get the progress of an ongoing OOB store + * + * Called by the Firmware Distribution Server model when it needs to + * get the current progress of an ongoing OOB store from the + * application. This callback is mandatory to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to get progress for. + * + * @return The current progress of the ongoing OOB store, in percent. + */ + uint8_t (*oob_progress_get)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot); +#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ + + /** @brief Slot delete callback. + * + * Called when the Firmware Distribution Server is about to delete a DFU image slot. + * All allocated data associated with the firmware slot should be + * deleted. + * + * @param srv Firmware Update Server instance. + * @param slot DFU image slot being deleted. + */ + void (*del)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot); + + /** @brief Slot send callback. + * + * Called at the start of a distribution procedure. The callback must + * fill @c io with a pointer to a readable BLOB stream for the Firmware + * Distribution Server to read the firmware image from. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being sent. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*send)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, + const struct bt_mesh_blob_io **io); + + /** @brief Phase change callback (Optional). + * + * Called whenever the phase of the Firmware Distribution Server changes. + * + * @param srv Firmware Distribution Server model instance. + * @param phase New Firmware Distribution phase. + */ + void (*phase)(struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_phase phase); +}; + +/** Firmware Distribution Server instance. */ +struct bt_mesh_dfd_srv { + const struct bt_mesh_dfd_srv_cb *cb; + const struct bt_mesh_model *mod; + struct bt_mesh_dfu_cli dfu; + struct bt_mesh_dfu_target targets[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX]; + struct bt_mesh_blob_target_pull pull_ctxs[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX]; + const struct bt_mesh_blob_io *io; + uint16_t target_cnt; + uint16_t slot_idx; + bool apply; + enum bt_mesh_dfd_phase phase; + struct bt_mesh_blob_cli_inputs inputs; + + struct { + enum bt_mesh_dfd_upload_phase phase; + struct bt_mesh_dfu_slot *slot; + const struct flash_area *area; + struct bt_mesh_blob_srv blob; +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + bool is_oob; + bool is_pending_oob_check; + struct { + uint8_t uri_len; + uint8_t uri[CONFIG_BT_MESH_DFU_URI_MAXLEN]; + uint16_t current_fwid_len; + uint8_t current_fwid[CONFIG_BT_MESH_DFU_FWID_MAXLEN]; + struct bt_mesh_msg_ctx ctx; + } oob; +#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ + } upload; + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD + struct { + const uint8_t *schemes; + const uint8_t count; + } oob_schemes; +#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ +}; + +#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD +/** @brief Call when an OOB check has completed or failed + * + * This should be called by the application after an OOB check started by the @c start_oob_upload + * callback has completed or failed. The @p status param should be set to one of the following + * values: + * + * * @c BT_MESH_DFD_SUCCESS if the check was successful and a new firmware ID was found. + * * @c BT_MESH_DFD_ERR_URI_MALFORMED if the URI is not formatted correctly. + * * @c BT_MESH_DFD_ERR_URI_NOT_SUPPORTED if the URI scheme is not supported by the node. + * * @c BT_MESH_DFD_ERR_URI_UNREACHABLE if the URI can't be reached. + * * @c BT_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE if the check completes successfully but no new + * firmware is available. + * + * If this function returns 0, the application should then download the firmware to the + * slot. If an error code is returned, the application should abort the OOB upload. + * + * @param srv Firmware Distribution Server model instance. + * @param slot The slot used in the OOB upload. + * @param status The result of the firmware check. + * @param fwid If the check was successful and new firmware found, this should point to a + * buffer containing the new firmware ID to store. + * @param fwid_len The length of the firmware ID pointed to by @p fwid. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len); + +/** @brief Call when an OOB store has completed or failed + * + * This should be called by the application after an OOB store started after a successful call to + * @c bt_mesh_dfd_srv_oob_check_complete has completed successfully or failed. + * + * @param srv Firmware Distribution Server model instance. + * @param slot The slot used when storing the firmware image. + * @param success @c true if the OOB store completed successfully, @c false otherwise. + * @param size The size of the stored firmware image, in bytes. + * @param metadata Pointer to the metadata received OOB, or @c NULL if no metadata was + * received. + * @param metadata_len Size of the metadata pointed to by @p metadata. + * + * @return 0 on success, (negative) error code otherwise. + */ +int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len); +#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb; +extern const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb; +extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb; +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_H__ */ + +/** @} */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h new file mode 100644 index 0000000000..4745355f03 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_H__ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_H__ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup bt_mesh_dfu Bluetooth Mesh Device Firmware Update + * @ingroup bt_mesh + * @{ + */ + +#ifndef CONFIG_BT_MESH_DFU_FWID_MAXLEN +#define CONFIG_BT_MESH_DFU_FWID_MAXLEN 0 +#endif + +#ifndef CONFIG_BT_MESH_DFU_METADATA_MAXLEN +#define CONFIG_BT_MESH_DFU_METADATA_MAXLEN 0 +#endif + +#ifndef CONFIG_BT_MESH_DFU_URI_MAXLEN +#define CONFIG_BT_MESH_DFU_URI_MAXLEN 0 +#endif + +#ifndef CONFIG_BT_MESH_DFU_SLOT_CNT +#define CONFIG_BT_MESH_DFU_SLOT_CNT 0 +#endif + +/** DFU transfer phase. */ +enum bt_mesh_dfu_phase { + /** Ready to start a Receive Firmware procedure. */ + BT_MESH_DFU_PHASE_IDLE, + + /** The Transfer BLOB procedure failed. */ + BT_MESH_DFU_PHASE_TRANSFER_ERR, + + /** The Receive Firmware procedure is being executed. */ + BT_MESH_DFU_PHASE_TRANSFER_ACTIVE, + + /** The Verify Firmware procedure is being executed. */ + BT_MESH_DFU_PHASE_VERIFY, + + /** The Verify Firmware procedure completed successfully. */ + BT_MESH_DFU_PHASE_VERIFY_OK, + + /** The Verify Firmware procedure failed. */ + BT_MESH_DFU_PHASE_VERIFY_FAIL, + + /** The Apply New Firmware procedure is being executed. */ + BT_MESH_DFU_PHASE_APPLYING, + + /** Firmware transfer has been canceled. */ + BT_MESH_DFU_PHASE_TRANSFER_CANCELED, + + /** Firmware applying succeeded. */ + BT_MESH_DFU_PHASE_APPLY_SUCCESS, + + /** Firmware applying failed. */ + BT_MESH_DFU_PHASE_APPLY_FAIL, + + /** Phase of a node was not yet retrieved. */ + BT_MESH_DFU_PHASE_UNKNOWN, +}; + + +/** DFU status. */ +enum bt_mesh_dfu_status { + /** The message was processed successfully. */ + BT_MESH_DFU_SUCCESS, + + /** Insufficient resources on the node */ + BT_MESH_DFU_ERR_RESOURCES, + + /** The operation cannot be performed while the Server is in the current + * phase. + */ + BT_MESH_DFU_ERR_WRONG_PHASE, + + /** An internal error occurred on the node. */ + BT_MESH_DFU_ERR_INTERNAL, + + /** The message contains a firmware index value that is not expected. */ + BT_MESH_DFU_ERR_FW_IDX, + + /** The metadata check failed. */ + BT_MESH_DFU_ERR_METADATA, + + /** The Server cannot start a firmware update. */ + BT_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE, + + /** Another BLOB transfer is in progress. */ + BT_MESH_DFU_ERR_BLOB_XFER_BUSY, +}; + +/** Expected effect of a DFU transfer. */ +enum bt_mesh_dfu_effect { + /** No changes to node Composition Data. */ + BT_MESH_DFU_EFFECT_NONE, + + /** Node Composition Data changed and the node does not support remote + * provisioning. + */ + BT_MESH_DFU_EFFECT_COMP_CHANGE_NO_RPR, + + /** Node Composition Data changed, and remote provisioning is supported. + * The node supports remote provisioning and Composition Data Page + * 0x80. Page 0x80 contains different Composition Data than Page 0x0. + */ + BT_MESH_DFU_EFFECT_COMP_CHANGE, + + /** Node will be unprovisioned after the update. */ + BT_MESH_DFU_EFFECT_UNPROV, +}; + +/** Action for DFU iteration callbacks. */ +enum bt_mesh_dfu_iter { + /** Stop iterating. */ + BT_MESH_DFU_ITER_STOP, + + /** Continue iterating. */ + BT_MESH_DFU_ITER_CONTINUE, +}; + +/** DFU image instance. + * + * Each DFU image represents a single updatable firmware image. + */ +struct bt_mesh_dfu_img { + /** Firmware ID. */ + const void *fwid; + + /** Length of the firmware ID. */ + size_t fwid_len; + + /** Update URI, or NULL. */ + const char *uri; +}; + +/** DFU image slot for DFU distribution. */ +struct bt_mesh_dfu_slot { + /** Size of the firmware in bytes. */ + size_t size; + /** Length of the firmware ID. */ + size_t fwid_len; + /** Length of the metadata. */ + size_t metadata_len; + /** Firmware ID. */ + uint8_t fwid[CONFIG_BT_MESH_DFU_FWID_MAXLEN]; + /** Metadata. */ + uint8_t metadata[CONFIG_BT_MESH_DFU_METADATA_MAXLEN]; +}; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h new file mode 100644 index 0000000000..ad8881ebc2 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfu_cli Firmware Uppdate Client model + * @ingroup bt_mesh_dfu + * @{ + * @brief API for the Bluetooth Mesh Firmware Update Client model + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_mesh_dfu_cli; + +/** + * + * @brief Initialization parameters for the @ref bt_mesh_dfu_cli. + * + * @sa bt_mesh_dfu_cli_cb. + * + * @param _handlers Handler callback structure. + */ +#define BT_MESH_DFU_CLI_INIT(_handlers) \ + { \ + .cb = _handlers, \ + .blob = { .cb = &_bt_mesh_dfu_cli_blob_handlers }, \ + } + +/** + * + * @brief Firmware Update Client model Composition Data entry. + * + * @param _cli Pointer to a @ref bt_mesh_dfu_cli instance. + */ +#define BT_MESH_MODEL_DFU_CLI(_cli) \ + BT_MESH_MODEL_BLOB_CLI(&(_cli)->blob), \ + BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_DFU_CLI, _bt_mesh_dfu_cli_op, NULL, \ + _cli, &_bt_mesh_dfu_cli_cb) + +/** DFU Target node. */ +struct bt_mesh_dfu_target { + /** BLOB Target node */ + struct bt_mesh_blob_target blob; + /** Image index on the Target node */ + uint8_t img_idx; + /** Expected DFU effect, see @ref bt_mesh_dfu_effect. */ + uint8_t effect; + /** Current DFU status, see @ref bt_mesh_dfu_status. */ + uint8_t status; + /** Current DFU phase, see @ref bt_mesh_dfu_phase. */ + uint8_t phase; +}; + +/** Metadata status response. */ +struct bt_mesh_dfu_metadata_status { + /** Image index. */ + uint8_t idx; + /** Status code. */ + enum bt_mesh_dfu_status status; + /** Effect of transfer. */ + enum bt_mesh_dfu_effect effect; +}; + +/** DFU Target node status parameters. */ +struct bt_mesh_dfu_target_status { + /** Status of the previous operation. */ + enum bt_mesh_dfu_status status; + /** Phase of the current DFU transfer. */ + enum bt_mesh_dfu_phase phase; + /** The effect the update will have on the Target device's state. */ + enum bt_mesh_dfu_effect effect; + /** BLOB ID used in the transfer. */ + uint64_t blob_id; + /** Image index to transfer. */ + uint8_t img_idx; + /** TTL used in the transfer. */ + uint8_t ttl; + + /** Additional response time for the Target nodes, in 10-second increments. + * + * The extra time can be used to give the Target nodes more time to respond + * to messages from the Client. The actual timeout will be calculated + * according to the following formula: + * + * @verbatim + * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) + * @endverbatim + * + * If a Target node fails to respond to a message from the Client within the + * configured transfer timeout, the Target node is dropped. + */ + uint16_t timeout_base; +}; + +/** @brief DFU image callback. + * + * The image callback is called for every DFU image on the Target node when + * calling @ref bt_mesh_dfu_cli_imgs_get. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context of the received message. + * @param idx Image index. + * @param total Total number of images on the Target node. + * @param img Image information for the given image index. + * @param cb_data Callback data. + * + * @retval BT_MESH_DFU_ITER_STOP Stop iterating through the image list and + * return from @ref bt_mesh_dfu_cli_imgs_get. + * @retval BT_MESH_DFU_ITER_CONTINUE Continue iterating through the image list + * if any images remain. + */ +typedef enum bt_mesh_dfu_iter (*bt_mesh_dfu_img_cb_t)( + struct bt_mesh_dfu_cli *cli, struct bt_mesh_msg_ctx *ctx, uint8_t idx, + uint8_t total, const struct bt_mesh_dfu_img *img, void *cb_data); + +/** Firmware Update Client event callbacks. */ +struct bt_mesh_dfu_cli_cb { + /** @brief BLOB transfer is suspended. + * + * Called when the BLOB transfer is suspended due to response timeout from all Target nodes. + * + * @param cli Firmware Update Client model instance. + */ + void (*suspended)(struct bt_mesh_dfu_cli *cli); + + /** @brief DFU ended. + * + * Called when the DFU transfer ends, either because all Target nodes were + * lost or because the transfer was completed successfully. + * + * @param cli Firmware Update Client model instance. + * @param reason Reason for ending. + */ + void (*ended)(struct bt_mesh_dfu_cli *cli, + enum bt_mesh_dfu_status reason); + + /** @brief DFU transfer applied on all active Target nodes. + * + * Called at the end of the apply procedure started by @ref + * bt_mesh_dfu_cli_apply. + * + * @param cli Firmware Update Client model instance. + */ + void (*applied)(struct bt_mesh_dfu_cli *cli); + + /** @brief DFU transfer confirmed on all active Target nodes. + * + * Called at the end of the apply procedure started by @ref + * bt_mesh_dfu_cli_confirm. + * + * @param cli Firmware Update Client model instance. + */ + void (*confirmed)(struct bt_mesh_dfu_cli *cli); + + /** @brief DFU Target node was lost. + * + * A DFU Target node was dropped from the receivers list. The Target node's + * @c status is set to reflect the reason for the failure. + * + * @param cli Firmware Update Client model instance. + * @param target DFU Target node that was lost. + */ + void (*lost_target)(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_dfu_target *target); +}; + +/** Firmware Update Client model instance. + * + * Should be initialized with @ref BT_MESH_DFU_CLI_INIT. + */ +struct bt_mesh_dfu_cli { + /** Callback structure. */ + const struct bt_mesh_dfu_cli_cb *cb; + /** Underlying BLOB Transfer Client. */ + struct bt_mesh_blob_cli blob; + + /* runtime state */ + + uint32_t op; + const struct bt_mesh_model *mod; + + struct { + const struct bt_mesh_dfu_slot *slot; + const struct bt_mesh_blob_io *io; + struct bt_mesh_blob_xfer blob; + uint8_t state; + uint8_t flags; + } xfer; + + struct { + uint8_t ttl; + uint8_t type; + uint8_t img_cnt; + uint16_t addr; + struct k_sem sem; + void *params; + bt_mesh_dfu_img_cb_t img_cb; + } req; +}; + +/** BLOB parameters for Firmware Update Client transfer: */ +struct bt_mesh_dfu_cli_xfer_blob_params { + /* Logarithmic representation of the block size. */ + uint8_t block_size_log; + /** Base chunk size. May be smaller for the last chunk. */ + uint16_t chunk_size; +}; + +/** Firmware Update Client transfer parameters: */ +struct bt_mesh_dfu_cli_xfer { + /** BLOB ID to use for this transfer, or 0 to set it randomly. */ + uint64_t blob_id; + /** DFU image slot to transfer. */ + const struct bt_mesh_dfu_slot *slot; + /** Transfer mode (Push (Push BLOB Transfer Mode) or Pull (Pull BLOB Transfer Mode)) */ + enum bt_mesh_blob_xfer_mode mode; + /** BLOB parameters to be used for the transfer, or NULL to retrieve Target nodes' + * capabilities before sending a firmware. + */ + const struct bt_mesh_dfu_cli_xfer_blob_params *blob_params; +}; + +/** @brief Start distributing a DFU. + * + * Starts distribution of the firmware in the given slot to the list of DFU + * Target nodes in @c ctx. The transfer runs in the background, and its end is + * signalled through the @ref bt_mesh_dfu_cli_cb::ended callback. + * + * @note The BLOB Transfer Client transfer inputs @c targets list must point to a list of @ref + * bt_mesh_dfu_target nodes. + * + * @param cli Firmware Update Client model instance. + * @param inputs BLOB Transfer Client transfer inputs. + * @param io BLOB stream to read BLOB from. + * @param xfer Firmware Update Client transfer parameters. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_send(struct bt_mesh_dfu_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_io *io, + const struct bt_mesh_dfu_cli_xfer *xfer); + +/** @brief Suspend a DFU transfer. + * + * @param cli Firmware Update Client instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_suspend(struct bt_mesh_dfu_cli *cli); + +/** @brief Resume the suspended transfer. + * + * @param cli Firmware Update Client instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_resume(struct bt_mesh_dfu_cli *cli); + +/** @brief Cancel a DFU transfer. + * + * Will cancel the ongoing DFU transfer, or the transfer on a specific Target + * node if @c ctx is valid. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context, or NULL to cancel the ongoing DFU transfer. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_cancel(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx); + +/** @brief Apply the completed DFU transfer. + * + * A transfer can only be applied after it has ended successfully. The Firmware + * Update Client's @c applied callback is called at the end of the apply procedure. + * + * @param cli Firmware Update Client model instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_apply(struct bt_mesh_dfu_cli *cli); + +/** @brief Confirm that the active transfer has been applied on the Target nodes. + * + * A transfer can only be confirmed after it has been applied. The Firmware Update + * Client's @c confirmed callback is called at the end of the confirm + * procedure. + * + * Target nodes that have reported the effect as @ref BT_MESH_DFU_EFFECT_UNPROV + * are expected to not respond to the query, and will fail if they do. + * + * @param cli Firmware Update Client model instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_confirm(struct bt_mesh_dfu_cli *cli); + +/** @brief Get progress as a percentage of completion. + * + * @param cli Firmware Update Client model instance. + * + * @return The progress of the current transfer in percent, or 0 if no + * transfer is active. + */ +uint8_t bt_mesh_dfu_cli_progress(struct bt_mesh_dfu_cli *cli); + +/** @brief Check whether a DFU transfer is in progress. + * + * @param cli Firmware Update Client model instance. + * + * @return true if the BLOB Transfer Client is currently participating in a transfer, + * false otherwise. + */ +bool bt_mesh_dfu_cli_is_busy(struct bt_mesh_dfu_cli *cli); + +/** @brief Perform a DFU image list request. + * + * Requests the full list of DFU images on a Target node, and iterates through + * them, calling the @c cb for every image. + * + * The DFU image list request can be used to determine which image index the + * Target node holds its different firmwares in. + * + * Waits for a response until the procedure timeout expires. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context. + * @param cb Callback to call for each image index. + * @param cb_data Callback data to pass to @c cb. + * @param max_count Max number of images to return. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_imgs_get(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + bt_mesh_dfu_img_cb_t cb, void *cb_data, + uint8_t max_count); + +/** @brief Perform a metadata check for the given DFU image slot. + * + * The metadata check procedure allows the Firmware Update Client to check if a Target + * node will accept a transfer of this DFU image slot, and what the effect would be. + * + * Waits for a response until the procedure timeout expires. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context. + * @param img_idx Target node's image index to check. + * @param slot DFU image slot to check for. + * @param rsp Metadata status response buffer. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_metadata_check(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, uint8_t img_idx, + const struct bt_mesh_dfu_slot *slot, + struct bt_mesh_dfu_metadata_status *rsp); + +/** @brief Get the status of a Target node. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context. + * @param rsp Response data buffer. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_cli_status_get(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_dfu_target_status *rsp); + +/** @brief Get the current procedure timeout value. + * + * @return The configured procedure timeout. + */ +int32_t bt_mesh_dfu_cli_timeout_get(void); + +/** @brief Set the procedure timeout value. + * + * @param timeout The new procedure timeout. + */ +void bt_mesh_dfu_cli_timeout_set(int32_t timeout); + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_blob_cli_cb _bt_mesh_dfu_cli_blob_handlers; +extern const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb; +extern const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[]; +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ */ + +/** @} */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h new file mode 100644 index 0000000000..8f6430c4b0 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfu_metadata Bluetooth Mesh Device Firmware Update (DFU) metadata + * @ingroup bt_mesh_dfu + * @{ + * @brief Common types and functions for the Bluetooth Mesh DFU metadata. + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_METADATA_H__ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_METADATA_H__ + +#include + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Firmware version. */ +struct bt_mesh_dfu_metadata_fw_ver { + /** Firmware major version. */ + uint8_t major; + /** Firmware minor version. */ + uint8_t minor; + /** Firmware revision. */ + uint16_t revision; + /** Firmware build number. */ + uint32_t build_num; +}; + +/** Firmware core type. */ +enum bt_mesh_dfu_metadata_fw_core_type { + /** Application core. */ + BT_MESH_DFU_FW_CORE_TYPE_APP = BIT(0), + /** Network core. */ + BT_MESH_DFU_FW_CORE_TYPE_NETWORK = BIT(1), + /** Application-specific BLOB. */ + BT_MESH_DFU_FW_CORE_TYPE_APP_SPECIFIC_BLOB = BIT(2), +}; + +/** Firmware metadata. */ +struct bt_mesh_dfu_metadata { + /** New firmware version. */ + struct bt_mesh_dfu_metadata_fw_ver fw_ver; + /** New firmware size. */ + uint32_t fw_size; + /** New firmware core type. */ + enum bt_mesh_dfu_metadata_fw_core_type fw_core_type; + /** Hash of incoming Composition Data. */ + uint32_t comp_hash; + /** New number of node elements. */ + uint16_t elems; + /** Application-specific data for new firmware. This field is optional. */ + uint8_t *user_data; + /** Length of the application-specific field. */ + uint32_t user_data_len; +}; + +/** @brief Decode a firmware metadata from a network buffer. + * + * @param buf Buffer containing a raw metadata to be decoded. + * @param metadata Pointer to a metadata structure to be filled. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_metadata_decode(struct net_buf_simple *buf, + struct bt_mesh_dfu_metadata *metadata); + +/** @brief Encode a firmware metadata into a network buffer. + * + * @param metadata Firmware metadata to be encoded. + * @param buf Buffer to store the encoded metadata. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_metadata_encode(const struct bt_mesh_dfu_metadata *metadata, + struct net_buf_simple *buf); + +/** @brief Compute hash of the Composition Data state. + * + * The format of the Composition Data is defined in MshPRTv1.1: 4.2.2.1. + * + * @param buf Pointer to buffer holding Composition Data. + * @param key 128-bit key to be used in the hash computation. + * @param hash Pointer to a memory location to which the hash will be stored. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_metadata_comp_hash_get(struct net_buf_simple *buf, uint8_t *key, uint32_t *hash); + +/** @brief Compute hash of the Composition Data Page 0 of this device. + * + * @param key 128-bit key to be used in the hash computation. + * @param hash Pointer to a memory location to which the hash will be stored. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_dfu_metadata_comp_hash_local_get(uint8_t *key, uint32_t *hash); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_METADATA_H__ */ + +/** @} */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h new file mode 100644 index 0000000000..2beaf2d977 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfu_srv Firmware Update Server model + * @ingroup bt_mesh_dfu + * @{ + * @brief API for the Bluetooth Mesh Firmware Update Server model + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_SRV_H__ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_SRV_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_mesh_dfu_srv; + +/** + * + * @brief Initialization parameters for @ref bt_mesh_dfu_srv. + * + * @param _handlers DFU handler function structure. + * @param _imgs List of @ref bt_mesh_dfu_img managed by this Server. + * @param _img_count Number of DFU images managed by this Server. + */ +#define BT_MESH_DFU_SRV_INIT(_handlers, _imgs, _img_count) \ + { \ + .blob = { .cb = &_bt_mesh_dfu_srv_blob_cb }, .cb = _handlers, \ + .imgs = _imgs, .img_count = _img_count, \ + } + +/** + * + * @brief Firmware Update Server model entry. + * + * @param _srv Pointer to a @ref bt_mesh_dfu_srv instance. + */ +#define BT_MESH_MODEL_DFU_SRV(_srv) \ + BT_MESH_MODEL_BLOB_SRV(&(_srv)->blob), \ + BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_DFU_SRV, _bt_mesh_dfu_srv_op, NULL, \ + _srv, &_bt_mesh_dfu_srv_cb) + +/** @brief Firmware Update Server event callbacks. */ +struct bt_mesh_dfu_srv_cb { + /** @brief Transfer check callback. + * + * The transfer check can be used to validate the incoming transfer + * before it starts. The contents of the metadata is implementation + * specific, and should contain all the information the application + * needs to determine whether this image should be accepted, and what + * the effect of the transfer would be. + * + * If applying the image will have an effect on the provisioning state + * of the mesh stack, this can be communicated through the @c effect + * return parameter. + * + * The metadata check can be performed both as part of starting a new + * transfer and as a separate procedure. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image the metadata check is performed on. + * @param metadata Image metadata. + * @param effect Return parameter for the image effect on the + * provisioning state of the mesh stack. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*check)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, + struct net_buf_simple *metadata, + enum bt_mesh_dfu_effect *effect); + + /** @brief Transfer start callback. + * + * Called when the Firmware Update Server is ready to start a new DFU transfer. + * The application must provide an initialized BLOB stream to be used + * during the DFU transfer. + * + * The following error codes are treated specially, and should be used + * to communicate these issues: + * - @c -ENOMEM: The device cannot fit this image. + * - @c -EBUSY: The application is temporarily unable to accept the + * transfer. + * - @c -EALREADY: The device has already received and verified this + * image, and there's no need to transfer it again. The Firmware Update model + * will skip the transfer phase, and mark the image as verified. + * + * This handler is mandatory. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param metadata Image metadata. + * @param io BLOB stream return parameter. Must be set to a + * valid BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code otherwise. Return + * codes @c -ENOMEM, @c -EBUSY @c -EALREADY will be passed to + * the updater, other error codes are reported as internal + * errors. + */ + int (*start)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, + struct net_buf_simple *metadata, + const struct bt_mesh_blob_io **io); + + /** @brief Transfer end callback. + * + * This handler is optional. + * + * If the transfer is successful, the application should verify the + * firmware image, and call either @ref bt_mesh_dfu_srv_verified or + * @ref bt_mesh_dfu_srv_rejected depending on the outcome. + * + * If the transfer fails, the Firmware Update Server will be available for new + * transfers immediately after this function returns. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that failed the update. + * @param success Whether the DFU transfer was successful. + */ + void (*end)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, bool success); + + /** @brief Transfer recovery callback. + * + * If the device reboots in the middle of a transfer, the Firmware Update Server + * calls this function when the Bluetooth Mesh subsystem is started. + * + * This callback is optional, but transfers will not be recovered after + * a reboot without it. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param io BLOB stream return parameter. Must be set to a valid BLOB + * stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, + const struct bt_mesh_blob_io **io); + + /** @brief Transfer apply callback. + * + * Called after a transfer has been validated, and the updater sends an + * apply message to the Target nodes. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that should be applied. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*apply)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img); +}; + +/** @brief Firmware Update Server instance. + * + * Should be initialized with @ref BT_MESH_DFU_SRV_INIT. + */ +struct bt_mesh_dfu_srv { + /** Underlying BLOB Transfer Server. */ + struct bt_mesh_blob_srv blob; + /** Callback structure. */ + const struct bt_mesh_dfu_srv_cb *cb; + /** List of updatable images. */ + const struct bt_mesh_dfu_img *imgs; + /** Number of updatable images. */ + size_t img_count; + + /* Runtime state */ + const struct bt_mesh_model *mod; + struct { + /* Effect of transfer, @see bt_mesh_dfu_effect. */ + uint8_t effect; + /* Current phase, @see bt_mesh_dfu_phase. */ + uint8_t phase; + uint8_t ttl; + uint8_t idx; + uint16_t timeout_base; + uint16_t meta; + } update; +}; + +/** @brief Accept the received DFU transfer. + * + * Should be called at the end of a successful DFU transfer. + * + * If the DFU transfer completes successfully, the application should verify + * the image validity (including any image authentication or integrity checks), + * and call this function if the image is ready to be applied. + * + * @param srv Firmware Update Server instance. + */ +void bt_mesh_dfu_srv_verified(struct bt_mesh_dfu_srv *srv); + +/** @brief Reject the received DFU transfer. + * + * Should be called at the end of a successful DFU transfer. + * + * If the DFU transfer completes successfully, the application should verify + * the image validity (including any image authentication or integrity checks), + * and call this function if one of the checks fail. + * + * @param srv Firmware Update Server instance. + */ +void bt_mesh_dfu_srv_rejected(struct bt_mesh_dfu_srv *srv); + +/** @brief Cancel the ongoing DFU transfer. + * + * @param srv Firmware Update Server instance. + */ +void bt_mesh_dfu_srv_cancel(struct bt_mesh_dfu_srv *srv); + +/** @brief Confirm that the received DFU transfer was applied. + * + * Should be called as a result of the @ref bt_mesh_dfu_srv_cb.apply callback. + * + * @param srv Firmware Update Server instance. + */ +void bt_mesh_dfu_srv_applied(struct bt_mesh_dfu_srv *srv); + +/** @brief Check if the Firmware Update Server is busy processing a transfer. + * + * @param srv Firmware Update Server instance. + * + * @return true if a DFU procedure is in progress, false otherwise. + */ +bool bt_mesh_dfu_srv_is_busy(const struct bt_mesh_dfu_srv *srv); + +/** @brief Get the progress of the current DFU procedure, in percent. + * + * @param srv Firmware Update Server instance. + * + * @return The current transfer progress in percent. + */ +uint8_t bt_mesh_dfu_srv_progress(const struct bt_mesh_dfu_srv *srv); + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb; +extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfu_srv_blob_cb; +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_SRV_H__ */ + +/** @} */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h new file mode 100644 index 0000000000..18304f39f6 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_H__ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_H__ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup bt_mesh_blob Bluetooth Mesh BLOB model API + * @ingroup bt_mesh + * @{ + */ + +#ifndef CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX +#define CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX 0 +#endif + +/** BLOB transfer mode. */ +enum bt_mesh_blob_xfer_mode { + /** No valid transfer mode. */ + BT_MESH_BLOB_XFER_MODE_NONE, + /** Push mode (Push BLOB Transfer Mode). */ + BT_MESH_BLOB_XFER_MODE_PUSH, + /** Pull mode (Pull BLOB Transfer Mode). */ + BT_MESH_BLOB_XFER_MODE_PULL, + /** Both modes are valid. */ + BT_MESH_BLOB_XFER_MODE_ALL, +}; + +/** Transfer phase. */ +enum bt_mesh_blob_xfer_phase { + /** The BLOB Transfer Server is awaiting configuration. */ + BT_MESH_BLOB_XFER_PHASE_INACTIVE, + /** The BLOB Transfer Server is ready to receive a BLOB transfer. */ + BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START, + /** The BLOB Transfer Server is waiting for the next block of data. */ + BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK, + /** The BLOB Transfer Server is waiting for the next chunk of data. */ + BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK, + /** The BLOB was transferred successfully. */ + BT_MESH_BLOB_XFER_PHASE_COMPLETE, + /** The BLOB transfer is paused. */ + BT_MESH_BLOB_XFER_PHASE_SUSPENDED, +}; + +/** BLOB model status codes. */ +enum bt_mesh_blob_status { + /** The message was processed successfully. */ + BT_MESH_BLOB_SUCCESS, + /** The Block Number field value is not within the range of blocks being + * transferred. + */ + BT_MESH_BLOB_ERR_INVALID_BLOCK_NUM, + /** The block size is smaller than the size indicated by the Min Block + * Size Log state or is larger than the size indicated by the Max Block + * Size Log state. + */ + BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE, + /** The chunk size exceeds the size indicated by the Max Chunk Size + * state, or the number of chunks exceeds the number specified by the + * Max Total Chunks state. + */ + BT_MESH_BLOB_ERR_INVALID_CHUNK_SIZE, + /** The operation cannot be performed while the server is in the current + * phase. + */ + BT_MESH_BLOB_ERR_WRONG_PHASE, + /** A parameter value in the message cannot be accepted. */ + BT_MESH_BLOB_ERR_INVALID_PARAM, + /** The message contains a BLOB ID value that is not expected. */ + BT_MESH_BLOB_ERR_WRONG_BLOB_ID, + /** There is not enough space available in memory to receive the BLOB. + */ + BT_MESH_BLOB_ERR_BLOB_TOO_LARGE, + /** The transfer mode is not supported by the BLOB Transfer Server + * model. + */ + BT_MESH_BLOB_ERR_UNSUPPORTED_MODE, + /** An internal error occurred on the node. */ + BT_MESH_BLOB_ERR_INTERNAL, + /** The requested information cannot be provided while the server is in + * the current phase. + */ + BT_MESH_BLOB_ERR_INFO_UNAVAILABLE, +}; + +/** BLOB transfer data block. */ +struct bt_mesh_blob_block { + /** Block size in bytes */ + size_t size; + /** Offset in bytes from the start of the BLOB. */ + off_t offset; + /** Block number */ + uint16_t number; + /** Number of chunks in block. */ + uint16_t chunk_count; + /** Bitmap of missing chunks. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX, + 8)]; +}; + +/** BLOB data chunk. */ +struct bt_mesh_blob_chunk { + /** Offset of the chunk data from the start of the block. */ + off_t offset; + /** Chunk data size. */ + size_t size; + /** Chunk data. */ + uint8_t *data; +}; + +/** BLOB transfer. */ +struct bt_mesh_blob_xfer { + /** BLOB ID. */ + uint64_t id; + /** Total BLOB size in bytes. */ + size_t size; + /** BLOB transfer mode. */ + enum bt_mesh_blob_xfer_mode mode; + /* Logarithmic representation of the block size. */ + uint8_t block_size_log; + /** Base chunk size. May be smaller for the last chunk. */ + uint16_t chunk_size; +}; + +/** BLOB stream interaction mode. */ +enum bt_mesh_blob_io_mode { + /** Read data from the stream. */ + BT_MESH_BLOB_READ, + /** Write data to the stream. */ + BT_MESH_BLOB_WRITE, +}; + +/** BLOB stream. */ +struct bt_mesh_blob_io { + /** @brief Open callback. + * + * Called when the reader is opened for reading. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param mode Direction of the stream (read/write). + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*open)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + enum bt_mesh_blob_io_mode mode); + + /** @brief Close callback. + * + * Called when the reader is closed. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + */ + void (*close)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer); + + /** @brief Block start callback. + * + * Called when a new block is opened for sending. Each block is only + * sent once, and are always sent in increasing order. The data chunks + * inside a single block may be requested out of order and multiple + * times. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that was started. + */ + int (*block_start)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block); + + /** @brief Block end callback. + * + * Called when the current block has been transmitted in full. + * No data from this block will be requested again, and the application + * data associated with this block may be discarded. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that finished sending. + */ + void (*block_end)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block); + + /** @brief Chunk data write callback. + * + * Used by the BLOB Transfer Server on incoming data. + * + * Each block is divided into chunks of data. This callback is called + * when a new chunk of data is received. Chunks may be received in + * any order within their block. + * + * If the callback returns successfully, this chunk will be marked as + * received, and will not be received again unless the block is + * restarted due to a transfer suspension. If the callback returns a + * non-zero value, the chunk remains unreceived, and the BLOB Transfer + * Client will attempt to resend it later. + * + * Note that the Client will only perform a limited number of attempts + * at delivering a chunk before dropping a Target node from the transfer. + * The number of retries performed by the Client is implementation + * specific. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Received chunk. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*wr)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block, + const struct bt_mesh_blob_chunk *chunk); + + /** @brief Chunk data read callback. + * + * Used by the BLOB Transfer Client to fetch outgoing data. + * + * The Client calls the chunk data request callback to populate a chunk + * message going out to the Target nodes. The data request callback + * may be called out of order and multiple times for each offset, and + * cannot be used as an indication of progress. + * + * Returning a non-zero status code on the chunk data request callback + * results in termination of the transfer. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Chunk to get the data of. The buffer pointer to by the + * @c data member should be filled by the callback. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*rd)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block, + const struct bt_mesh_blob_chunk *chunk); +}; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h new file mode 100644 index 0000000000..574ec82715 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_CLI_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_CLI_H_ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup bt_mesh_blob_cli Bluetooth Mesh BLOB Transfer Client model API + * @ingroup bt_mesh + * @{ + */ + +struct bt_mesh_blob_cli; + +/** + * + * @brief BLOB Transfer Client model Composition Data entry. + * + * @param _cli Pointer to a @ref bt_mesh_blob_cli instance. + */ +#define BT_MESH_MODEL_BLOB_CLI(_cli) \ + BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_BLOB_CLI, _bt_mesh_blob_cli_op, \ + NULL, _cli, &_bt_mesh_blob_cli_cb) + +/** Target node's Pull mode (Pull BLOB Transfer Mode) context used + * while sending chunks to the Target node. + */ +struct bt_mesh_blob_target_pull { + /** Timestamp when the Block Report Timeout Timer expires for this Target node. */ + int64_t block_report_timestamp; + + /** Missing chunks reported by this Target node. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX, 8)]; +}; + +/** BLOB Transfer Client Target node. */ +struct bt_mesh_blob_target { + /** Linked list node */ + sys_snode_t n; + + /** Target node address. */ + uint16_t addr; + + /** Target node's Pull mode context. + * Needs to be initialized when sending a BLOB in Pull mode. + */ + struct bt_mesh_blob_target_pull *pull; + + /** BLOB transfer status, see @ref bt_mesh_blob_status. */ + uint8_t status; + + uint8_t procedure_complete:1, /* Procedure has been completed. */ + acked:1, /* Message has been acknowledged. Not used when sending. */ + timedout:1, /* Target node didn't respond after specified timeout. */ + skip:1; /* Skip Target node from broadcast. */ +}; + +/** BLOB transfer information. + * + * If @c phase is @ref BT_MESH_BLOB_XFER_PHASE_INACTIVE, + * the fields below @c phase are not initialized. + * If @c phase is @ref BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START, + * the fields below @c id are not initialized. + */ +struct bt_mesh_blob_xfer_info { + /** BLOB transfer status. */ + enum bt_mesh_blob_status status; + + /** BLOB transfer mode. */ + enum bt_mesh_blob_xfer_mode mode; + + /** BLOB transfer phase. */ + enum bt_mesh_blob_xfer_phase phase; + + /** BLOB ID. */ + uint64_t id; + + /** BLOB size in octets. */ + uint32_t size; + + /** Logarithmic representation of the block size. */ + uint8_t block_size_log; + + /** MTU size in octets. */ + uint16_t mtu_size; + + /** Bit field indicating blocks that were not received. */ + const uint8_t *missing_blocks; +}; + +/** BLOB Transfer Client transfer inputs. */ +struct bt_mesh_blob_cli_inputs { + /** Linked list of Target nodes. Each node should point to @ref + * bt_mesh_blob_target::n. + */ + sys_slist_t targets; + + /** AppKey index to send with. */ + uint16_t app_idx; + + /** Group address destination for the BLOB transfer, or @ref + * BT_MESH_ADDR_UNASSIGNED to send every message to each Target + * node individually. + */ + uint16_t group; + + /** Time to live value of BLOB transfer messages. */ + uint8_t ttl; + + /** Additional response time for the Target nodes, in 10-second increments. + * + * The extra time can be used to give the Target nodes more time to respond + * to messages from the Client. The actual timeout will be calculated + * according to the following formula: + * + * @verbatim + * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) + * @endverbatim + * + * If a Target node fails to respond to a message from the Client within the + * configured transfer timeout, the Target node is dropped. + */ + uint16_t timeout_base; +}; + +/** Transfer capabilities of a Target node. */ +struct bt_mesh_blob_cli_caps { + /** Max BLOB size. */ + size_t max_size; + + /** Logarithmic representation of the minimum block size. */ + uint8_t min_block_size_log; + + /** Logarithmic representation of the maximum block size. */ + uint8_t max_block_size_log; + + /** Max number of chunks per block. */ + uint16_t max_chunks; + + /** Max chunk size. */ + uint16_t max_chunk_size; + + /** Max MTU size. */ + uint16_t mtu_size; + + /** Supported transfer modes. */ + enum bt_mesh_blob_xfer_mode modes; +}; + +/** BLOB Transfer Client state. */ +enum bt_mesh_blob_cli_state { + /** No transfer is active. */ + BT_MESH_BLOB_CLI_STATE_NONE, + /** Retrieving transfer capabilities. */ + BT_MESH_BLOB_CLI_STATE_CAPS_GET, + /** Sending transfer start. */ + BT_MESH_BLOB_CLI_STATE_START, + /** Sending block start. */ + BT_MESH_BLOB_CLI_STATE_BLOCK_START, + /** Sending block chunks. */ + BT_MESH_BLOB_CLI_STATE_BLOCK_SEND, + /** Checking block status. */ + BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK, + /** Checking transfer status. */ + BT_MESH_BLOB_CLI_STATE_XFER_CHECK, + /** Cancelling transfer. */ + BT_MESH_BLOB_CLI_STATE_CANCEL, + /** Transfer is suspended. */ + BT_MESH_BLOB_CLI_STATE_SUSPENDED, + /** Checking transfer progress. */ + BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET, +}; + +/** Event handler callbacks for the BLOB Transfer Client model. + * + * All handlers are optional. + */ +struct bt_mesh_blob_cli_cb { + /** @brief Capabilities retrieval completion callback. + * + * Called when the capabilities retrieval procedure completes, indicating that + * a common set of acceptable transfer parameters have been established + * for the given list of Target nodes. All compatible Target nodes have + * status code @ref BT_MESH_BLOB_SUCCESS. + * + * @param cli BLOB Transfer Client instance. + * @param caps Safe transfer capabilities if the transfer capabilities + * of at least one Target node has satisfied the Client, or NULL otherwise. + */ + void (*caps)(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_caps *caps); + + /** @brief Target node loss callback. + * + * Called whenever a Target node has been lost due to some error in the + * transfer. Losing a Target node is not considered a fatal error for + * the Client until all Target nodes have been lost. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that was lost. + * @param reason Reason for the Target node loss. + */ + void (*lost_target)(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + enum bt_mesh_blob_status reason); + + /** @brief Transfer is suspended. + * + * Called when the transfer is suspended due to response timeout from all Target nodes. + * + * @param cli BLOB Transfer Client instance. + */ + void (*suspended)(struct bt_mesh_blob_cli *cli); + + /** @brief Transfer end callback. + * + * Called when the transfer ends. + * + * @param cli BLOB Transfer Client instance. + * @param xfer Completed transfer. + * @param success Status of the transfer. + * Is @c true if at least one Target + * node received the whole transfer. + */ + void (*end)(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_xfer *xfer, bool success); + + /** @brief Transfer progress callback + * + * The content of @c info is invalidated upon exit from the callback. + * Therefore it needs to be copied if it is planned to be used later. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that responded to the request. + * @param info BLOB transfer information. + */ + void (*xfer_progress)(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + const struct bt_mesh_blob_xfer_info *info); + + /** @brief End of Get Transfer Progress procedure. + * + * Called when all Target nodes have responded or the procedure timed-out. + * + * @param cli BLOB Transfer Client instance. + */ + void (*xfer_progress_complete)(struct bt_mesh_blob_cli *cli); +}; + +/** @cond INTERNAL_HIDDEN */ +struct blob_cli_broadcast_ctx { + /** Called for every Target node in unicast mode, or once in case of multicast mode. */ + void (*send)(struct bt_mesh_blob_cli *cli, uint16_t dst); + /** Called after every @ref blob_cli_broadcast_ctx::send callback. */ + void (*send_complete)(struct bt_mesh_blob_cli *cli, uint16_t dst); + /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes + * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called + * after transmission has been completed. + */ + void (*next)(struct bt_mesh_blob_cli *cli); + /** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before + * @ref blob_cli_broadcast_ctx::next is called. + */ + bool acked; + /** If true, the message is always sent in a unicast way. */ + bool force_unicast; + /** If true, non-responsive Target nodes won't be dropped after transfer has timed out. */ + bool optional; + /** Set to true by the BLOB Transfer Client between blob_cli_broadcast + * and broadcast_complete calls. + */ + bool is_inited; + /* Defines a time in ms by which the broadcast API postpones sending the message to a next + * target or completing the broadcast. + */ + uint32_t post_send_delay_ms; +}; +/** INTERNAL_HIDDEN @endcond */ + +/** BLOB Transfer Client model instance. */ +struct bt_mesh_blob_cli { + /** Event handler callbacks */ + const struct bt_mesh_blob_cli_cb *cb; + + /* Runtime state */ + const struct bt_mesh_model *mod; + + struct { + struct bt_mesh_blob_target *target; + struct blob_cli_broadcast_ctx ctx; + struct k_work_delayable retry; + /* Represents Client Timeout timer in a timestamp. Used in Pull mode only. */ + int64_t cli_timestamp; + struct k_work_delayable complete; + uint16_t pending; + uint8_t retries; + uint8_t sending : 1, + cancelled : 1; + } tx; + + const struct bt_mesh_blob_io *io; + const struct bt_mesh_blob_cli_inputs *inputs; + const struct bt_mesh_blob_xfer *xfer; + uint32_t chunk_interval_ms; + uint16_t block_count; + uint16_t chunk_idx; + uint16_t mtu_size; + enum bt_mesh_blob_cli_state state; + struct bt_mesh_blob_block block; + struct bt_mesh_blob_cli_caps caps; +}; + +/** @brief Retrieve transfer capabilities for a list of Target nodes. + * + * Queries the availability and capabilities of all Target nodes, producing a + * cumulative set of transfer capabilities for the Target nodes, and returning + * it through the @ref bt_mesh_blob_cli_cb::caps callback. + * + * Retrieving the capabilities may take several seconds, depending on the + * number of Target nodes and mesh network performance. The end of the procedure + * is indicated through the @ref bt_mesh_blob_cli_cb::caps callback. + * + * This procedure is not required, but strongly recommended as a + * preparation for a transfer to maximize performance and the chances of + * success. + * + * @param cli BLOB Transfer Client instance. + * @param inputs Statically allocated BLOB Transfer Client transfer inputs. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_caps_get(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs); + +/** @brief Perform a BLOB transfer. + * + * Starts sending the transfer to the Target nodes. Only Target nodes with a + * @c status of @ref BT_MESH_BLOB_SUCCESS will be considered. + * + * The transfer will keep going either until all Target nodes have been dropped, or + * the full BLOB has been sent. + * + * The BLOB transfer may take several minutes, depending on the number of + * Target nodes, size of the BLOB and mesh network performance. The end of the + * transfer is indicated through the @ref bt_mesh_blob_cli_cb::end callback. + * + * A Client only supports one transfer at the time. + * + * @param cli BLOB Transfer Client instance. + * @param inputs Statically allocated BLOB Transfer Client transfer inputs. + * @param xfer Statically allocated transfer parameters. + * @param io BLOB stream to read the transfer from. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_send(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io *io); + +/** @brief Suspend the active transfer. + * + * @param cli BLOB Transfer Client instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_suspend(struct bt_mesh_blob_cli *cli); + +/** @brief Resume the suspended transfer. + * + * @param cli BLOB Transfer Client instance. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_resume(struct bt_mesh_blob_cli *cli); + +/** @brief Cancel an ongoing transfer. + * + * @param cli BLOB Transfer Client instance. + */ +void bt_mesh_blob_cli_cancel(struct bt_mesh_blob_cli *cli); + +/** @brief Get the progress of BLOB transfer. + * + * This function can only be used if the BLOB Transfer Client is currently + * not performing a BLOB transfer. + * To get progress of the active BLOB transfer, use the + * @ref bt_mesh_blob_cli_xfer_progress_active_get function. + * + * @param cli BLOB Transfer Client instance. + * @param inputs Statically allocated BLOB Transfer Client transfer inputs. + * + * @return 0 on success, or (negative) error code otherwise. + */ +int bt_mesh_blob_cli_xfer_progress_get(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs); + +/** @brief Get the current progress of the active transfer in percent. + * + * @param cli BLOB Transfer Client instance. + * + * @return The current transfer progress, or 0 if no transfer is active. + */ +uint8_t bt_mesh_blob_cli_xfer_progress_active_get(struct bt_mesh_blob_cli *cli); + +/** @brief Get the current state of the BLOB Transfer Client. + * + * @param cli BLOB Transfer Client instance. + * + * @return true if the BLOB Transfer Client is currently participating in a transfer or + * retrieving the capabilities and false otherwise. + */ +bool bt_mesh_blob_cli_is_busy(struct bt_mesh_blob_cli *cli); + +/** @brief Set chunk sending interval in ms + * + * This function is optional, and can be used to define how fast chunks are sent in the BLOB Client + * Model. + * Without an added delay, for example a Bluetooth Mesh DFU can cause network blockage by + * constantly sending the next chunks, especially if the chunks are sent to group addresses or + * multiple unicast addresses. + * + * @note: Big intervals may cause timeouts. Increasing the @c timeout_base accordingly can + * circumvent this. + * + * @param cli BLOB Transfer Client instance. + * @param interval_ms the delay before each chunk is sent out in ms. + */ +void bt_mesh_blob_cli_set_chunk_interval_ms(struct bt_mesh_blob_cli *cli, uint32_t interval_ms); + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_model_op _bt_mesh_blob_cli_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb; +/** @endcond */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_CLI_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h new file mode 100644 index 0000000000..8a0c6b67a1 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_SRV_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_SRV_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup bt_mesh_blob_srv Bluetooth Mesh BLOB Transfer Server model API + * @ingroup bt_mesh + * @{ + */ + +struct bt_mesh_blob_srv; + +/** + * + * @brief Max number of blocks in a single transfer. + */ +#if defined(CONFIG_BT_MESH_BLOB_SRV) +#define BT_MESH_BLOB_BLOCKS_MAX \ + (DIV_ROUND_UP(CONFIG_BT_MESH_BLOB_SIZE_MAX, \ + CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN)) +#else +#define BT_MESH_BLOB_BLOCKS_MAX 1 +#endif + +/** + * + * @brief BLOB Transfer Server model composition data entry. + * + * @param _srv Pointer to a @ref bt_mesh_blob_srv instance. + */ +#define BT_MESH_MODEL_BLOB_SRV(_srv) \ + BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_BLOB_SRV, _bt_mesh_blob_srv_op, \ + NULL, _srv, &_bt_mesh_blob_srv_cb) + +/** @brief BLOB Transfer Server model event handlers. + * + * All callbacks are optional. + */ +struct bt_mesh_blob_srv_cb { + /** @brief Transfer start callback. + * + * Called when the transfer has started with the prepared BLOB ID. + * + * @param srv BLOB Transfer Server instance. + * @param ctx Message context for the incoming start message. The + * entire transfer will be sent from the same source + * address. + * @param xfer Transfer parameters. + * + * @return 0 on success, or (negative) error code to reject the + * transfer. + */ + int (*start)(struct bt_mesh_blob_srv *srv, struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_blob_xfer *xfer); + + /** @brief Transfer end callback. + * + * Called when the transfer ends, either because it was cancelled, or + * because it finished successfully. A new transfer may be prepared. + * + * @note The transfer may end before it's started if the start + * parameters are invalid. + * + * @param srv BLOB Transfer Server instance. + * @param id BLOB ID of the cancelled transfer. + * @param success Whether the transfer was successful. + */ + void (*end)(struct bt_mesh_blob_srv *srv, uint64_t id, bool success); + + /** @brief Transfer suspended callback. + * + * Called if the Server timed out while waiting for a transfer packet. + * A suspended transfer may resume later from the start of the current + * block. Any received chunks in the current block should be discarded, + * they will be received again if the transfer resumes. + * + * The transfer will call @c resumed again when resuming. + * + * @note The BLOB Transfer Server does not run a timer in the suspended state, + * and it's up to the application to determine whether the + * transfer should be permanently cancelled. Without interaction, + * the transfer will be suspended indefinitely, and the BLOB Transfer + * Server will not accept any new transfers. + * + * @param srv BLOB Transfer Server instance. + */ + void (*suspended)(struct bt_mesh_blob_srv *srv); + + /** @brief Transfer resume callback. + * + * Called if the transfer is resumed after being suspended. + * + * @param srv BLOB Transfer Server instance. + */ + void (*resume)(struct bt_mesh_blob_srv *srv); + + /** @brief Transfer recovery callback. + * + * Called when the Bluetooth Mesh subsystem is started if the device is rebooted + * in the middle of a transfer. + * + * Transfers will not be resumed after a reboot if this callback is not + * defined. + * + * @param srv BLOB Transfer Server instance. + * @param xfer Transfer to resume. + * @param io BLOB stream return parameter. Must be set to a valid + * BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(struct bt_mesh_blob_srv *srv, + struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io **io); +}; + +/** @brief BLOB Transfer Server model instance. */ +struct bt_mesh_blob_srv { + /** Event handler callbacks. */ + const struct bt_mesh_blob_srv_cb *cb; + + /* Runtime state: */ + const struct bt_mesh_blob_io *io; + struct k_work_delayable rx_timeout; + struct bt_mesh_blob_block block; + const struct bt_mesh_model *mod; + enum bt_mesh_blob_xfer_phase phase; + + struct bt_mesh_blob_srv_state { + struct bt_mesh_blob_xfer xfer; + uint16_t cli; + uint16_t app_idx; + uint16_t timeout_base; + uint16_t mtu_size; + uint8_t ttl; + + /* Bitfield of pending blocks. */ + ATOMIC_DEFINE(blocks, BT_MESH_BLOB_BLOCKS_MAX); + } state; + + /* Pull mode (Pull BLOB Transfer Mode) behavior. */ + struct { + uint16_t chunk_idx; + struct k_work_delayable report; + } pull; +}; + +/** @brief Prepare BLOB Transfer Server for an incoming transfer. + * + * Before a BLOB Transfer Server can receive a transfer, the transfer must be prepared + * through some application level mechanism. The BLOB Transfer Server will only accept + * incoming transfers with a matching BLOB ID. + * + * @param srv BLOB Transfer Server instance. + * @param id BLOB ID to accept. + * @param io BLOB stream to write the incoming BLOB to. + * @param ttl Time to live value to use in responses to the BLOB Transfer Client. + * @param timeout_base Extra time for the Client to respond in addition to the + * base 10 seconds, in 10-second increments. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_blob_srv_recv(struct bt_mesh_blob_srv *srv, uint64_t id, + const struct bt_mesh_blob_io *io, uint8_t ttl, + uint16_t timeout_base); + +/** @brief Cancel the current BLOB transfer. + * + * Tells the BLOB Transfer Client to drop this device from the list of Targets for the + * current transfer. Note that the client may continue sending the transfer to + * other Targets. + * + * @param srv BLOB Transfer Server instance. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_blob_srv_cancel(struct bt_mesh_blob_srv *srv); + +/** @brief Get the current state of the BLOB Transfer Server. + * + * @param srv BLOB Transfer Server instance. + * + * @return true if the BLOB Transfer Server is currently participating in a transfer, + * false otherwise. + */ +bool bt_mesh_blob_srv_is_busy(const struct bt_mesh_blob_srv *srv); + +/** @brief Get the current progress of the active transfer in percent. + * + * @param srv BLOB Transfer Server instance. + * + * @return The current transfer progress, or 0 if no transfer is active. + */ +uint8_t bt_mesh_blob_srv_progress(const struct bt_mesh_blob_srv *srv); + +/** @cond INTERNAL_HIDDEN */ +extern const struct bt_mesh_model_op _bt_mesh_blob_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_blob_srv_cb; +/** @endcond */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_SRV_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/mbt/blob.h b/components/bt/esp_ble_mesh/v1.1/mbt/blob.h new file mode 100644 index 0000000000..162725480e --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/mbt/blob.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define BT_MESH_BLOB_OP_XFER_GET BT_MESH_MODEL_OP_2(0x83, 0x00) +#define BT_MESH_BLOB_OP_XFER_START BT_MESH_MODEL_OP_2(0x83, 0x01) +#define BT_MESH_BLOB_OP_XFER_CANCEL BT_MESH_MODEL_OP_2(0x83, 0x02) +#define BT_MESH_BLOB_OP_XFER_STATUS BT_MESH_MODEL_OP_2(0x83, 0x03) +#define BT_MESH_BLOB_OP_BLOCK_GET BT_MESH_MODEL_OP_2(0x83, 0x05) +#define BT_MESH_BLOB_OP_BLOCK_START BT_MESH_MODEL_OP_2(0x83, 0x04) +#define BT_MESH_BLOB_OP_CHUNK BT_MESH_MODEL_OP_1(0x66) +#define BT_MESH_BLOB_OP_BLOCK_STATUS BT_MESH_MODEL_OP_1(0x67) +#define BT_MESH_BLOB_OP_BLOCK_REPORT BT_MESH_MODEL_OP_1(0x68) +#define BT_MESH_BLOB_OP_INFO_GET BT_MESH_MODEL_OP_2(0x83, 0x06) +#define BT_MESH_BLOB_OP_INFO_STATUS BT_MESH_MODEL_OP_2(0x83, 0x07) + +#define BLOB_BLOCK_NOT_SET 0xffff + +#define BLOB_CHUNK_SDU_OVERHEAD \ + (BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK) + 2 + BT_MESH_MIC_SHORT) + +#define BLOB_CHUNK_SIZE_MAX(sdu_max) ((sdu_max) - BLOB_CHUNK_SDU_OVERHEAD) +#define BLOB_CHUNK_SDU_LEN(chunk_size) (BLOB_CHUNK_SDU_OVERHEAD + (chunk_size)) + +#if CONFIG_BT_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT || \ + CONFIG_BT_MESH_RX_BLOB_CHUNK_SIZE > BLOB_CHUNK_SIZE_MAX(BT_MESH_RX_SDU_MAX) +#define BLOB_RX_CHUNK_SIZE BLOB_CHUNK_SIZE_MAX(BT_MESH_RX_SDU_MAX) +#else +#define BLOB_RX_CHUNK_SIZE CONFIG_BT_MESH_RX_BLOB_CHUNK_SIZE +#endif + +#if CONFIG_BT_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT || \ + CONFIG_BT_MESH_TX_BLOB_CHUNK_SIZE > BLOB_CHUNK_SIZE_MAX(BT_MESH_TX_SDU_MAX) +#define BLOB_TX_CHUNK_SIZE BLOB_CHUNK_SIZE_MAX(BT_MESH_TX_SDU_MAX) +#else +#define BLOB_TX_CHUNK_SIZE CONFIG_BT_MESH_TX_BLOB_CHUNK_SIZE +#endif + +/* Utility macros for calculating log2 of a number at compile time. + * Used to determine the log2 representation of the block size, which + * is configured as a raw number, but encoded as log2. + * + * The macros expand to a series of ternary expressions, effectively + * searching through power of twos until a match is found. + * According to MshMBTv1.0, the block size cannot be larger than 2^20, + * so we'll stop the search at 20. + */ +#define _BLOB_LOG_2_CEIL(l, x) ((x) <= (1U << l)) ? l : +#define _BLOB_LOG_2_FLOOR(l, x) ((x) < (1U << (l + 1))) ? l : + +#define BLOB_BLOCK_SIZE_LOG_CEIL(x) (LISTIFY(20, _BLOB_LOG_2_CEIL, (), x) 20) +#define BLOB_BLOCK_SIZE_LOG_FLOOR(x) (LISTIFY(20, _BLOB_LOG_2_FLOOR, (), x) 20) + +/* Log2 representation of the minimum block size */ +#define BLOB_BLOCK_SIZE_LOG_MIN BLOB_BLOCK_SIZE_LOG_CEIL(CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN) +/* Log2 representation of the maximum block size */ +#define BLOB_BLOCK_SIZE_LOG_MAX BLOB_BLOCK_SIZE_LOG_FLOOR(CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX) + +#if defined(CONFIG_BT_MESH_BLOB_SRV) +#define BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN ( \ + MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \ + CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT * 3)) +#define BLOB_BLOCK_STATUS_MSG_MAXLEN (5 + \ + MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \ + CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT * 3)) +#else +#define BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN sizeof(((struct bt_mesh_blob_srv *)0)->block.missing) +#define BLOB_BLOCK_STATUS_MSG_MAXLEN (5 + sizeof(((struct bt_mesh_blob_srv *)0)->block.missing)) +#endif + +#define BLOB_XFER_STATUS_MSG_MAXLEN (17 + sizeof(((struct bt_mesh_blob_srv *)0)->state.blocks)) + +enum bt_mesh_blob_chunks_missing { + BT_MESH_BLOB_CHUNKS_MISSING_ALL, + BT_MESH_BLOB_CHUNKS_MISSING_NONE, + BT_MESH_BLOB_CHUNKS_MISSING_SOME, + BT_MESH_BLOB_CHUNKS_MISSING_ENCODED, +}; + +static inline size_t blob_block_size(size_t xfer_size, uint8_t block_size_log, + uint32_t idx) +{ + if (((idx + 1U) << block_size_log) <= xfer_size) { + return (1U << block_size_log); + } + + return xfer_size & BIT_MASK(block_size_log); +} + +static inline void blob_chunk_missing_set(uint8_t *missing_chunks, + int idx, bool missing) +{ + WRITE_BIT(missing_chunks[idx / 8], idx % 8, missing); +} + +static inline bool +blob_chunk_missing_get(const uint8_t *missing_chunks, int idx) +{ + return !!(missing_chunks[idx / 8] & BIT(idx % 8)); +} + +static inline void blob_chunk_missing_set_all(struct bt_mesh_blob_block *block) +{ + size_t bytes = block->chunk_count / 8; + + memset(block->missing, 0xff, bytes); + if (block->chunk_count % 8) { + block->missing[bytes] = BIT_MASK(block->chunk_count % 8); + } +} + +static inline void blob_chunk_missing_set_none(struct bt_mesh_blob_block *block) +{ + memset(block->missing, 0, sizeof(block->missing)); +} + +/** @brief Perform a message broadcast to all BLOB Transfer Client Target nodes. + * + * Will send to a group or each Target node individually, repeating until + * all Target nodes have responded or the retry time has run out. + * + * @param cli BLOB Transfer Client instance + * @param ctx Broadcast context + */ +void blob_cli_broadcast(struct bt_mesh_blob_cli *cli, + const struct blob_cli_broadcast_ctx *ctx); + +/** @brief Register that a Target node responded to a broadcast. + * + * @param cli BLOB Transfer Client instance + * @param target Target node that responded. + */ +void blob_cli_broadcast_rsp(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target); + +/** @brief Notify the BLOB Transfer Client that the requested transmission is complete. + * + * Should be called once for each call to the @ref blob_cli_broadcast_ctx.send + * callback. + * + * @param cli BLOB Transfer Client instance. + */ +void blob_cli_broadcast_tx_complete(struct bt_mesh_blob_cli *cli); + +/** @brief Aborts any ongoing BLOB Transfer Client operations. + * + * @param cli BLOB Transfer Client instance. + */ +void blob_cli_broadcast_abort(struct bt_mesh_blob_cli *cli); diff --git a/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c b/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c new file mode 100644 index 0000000000..40d3d37a6c --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c @@ -0,0 +1,1658 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "mesh.h" +#include "blob.h" +#include "net.h" +#include "transport.h" + +#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_mesh_blob_cli); + +#define TARGETS_FOR_EACH(cli, target) \ + SYS_SLIST_FOR_EACH_CONTAINER((sys_slist_t *)&(cli)->inputs->targets, \ + target, n) + +/* The Maximum BLOB Poll Interval - T_MBPI */ +#define BLOB_POLL_TIME_MAX_SECS 30 + +#define CLIENT_TIMEOUT_MSEC(cli) (10 * MSEC_PER_SEC * (cli->inputs->timeout_base + 2) + \ + 100 * cli->inputs->ttl) +#define BLOCK_REPORT_TIME_MSEC ((BLOB_POLL_TIME_MAX_SECS * 2 + 7) * 1000) + +/* BLOB Client is running Send Data State Machine from section 6.2.4.2. */ +#define SENDING_CHUNKS_IN_PULL_MODE(cli) ((cli)->state == BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && \ + (cli)->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) +#define UNICAST_MODE(cli) ((cli)->inputs->group == BT_MESH_ADDR_UNASSIGNED || \ + (cli)->tx.ctx.force_unicast) + +BUILD_ASSERT((BLOB_XFER_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_XFER_STATUS) + + BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, + "The BLOB Transfer Status message does not fit into the maximum incoming SDU size."); + +BUILD_ASSERT((BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN + + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_REPORT) + BT_MESH_MIC_SHORT) + <= BT_MESH_RX_SDU_MAX, + "The BLOB Partial Block Report message does not fit into the maximum incoming SDU " + "size."); + +BUILD_ASSERT((BLOB_BLOCK_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_STATUS) + + BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, + "The BLOB Block Status message does not fit into the maximum incoming SDU size."); + + +struct block_status { + enum bt_mesh_blob_status status; + enum bt_mesh_blob_chunks_missing missing; + struct bt_mesh_blob_block block; +}; + +static struct bt_mesh_blob_target *next_target(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target **current); +static void transfer_cancel(struct bt_mesh_blob_cli *cli); + +static void start_retry_timer(struct bt_mesh_blob_cli *cli) +{ + k_timeout_t next_timeout; + + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + int64_t next_timeout_ms = cli->tx.cli_timestamp; + struct bt_mesh_blob_target *target = NULL; + + TARGETS_FOR_EACH(cli, target) { + if (!target->procedure_complete && + target->status == BT_MESH_BLOB_SUCCESS && + target->pull->block_report_timestamp < next_timeout_ms) { + next_timeout_ms = target->pull->block_report_timestamp; + } + } + + /* cli_timestamp and block_report_timestamp represent absolute time, while + * k_work_* functions use relative time. + */ + next_timeout_ms -= k_uptime_get(); + next_timeout = next_timeout_ms <= 0 ? K_NO_WAIT : K_MSEC(next_timeout_ms); + } else { + next_timeout = K_MSEC(CLIENT_TIMEOUT_MSEC(cli) / + CONFIG_BT_MESH_BLOB_CLI_BLOCK_RETRIES); + } + + (void)k_work_reschedule(&cli->tx.retry, next_timeout); +} + +static void cli_state_reset(struct bt_mesh_blob_cli *cli) +{ + k_work_cancel_delayable(&cli->tx.retry); + cli->xfer = NULL; + cli->state = BT_MESH_BLOB_CLI_STATE_NONE; + cli->tx.ctx.is_inited = 0; + cli->tx.cli_timestamp = 0ll; + cli->tx.sending = 0; +} + +static struct bt_mesh_blob_target *target_get(struct bt_mesh_blob_cli *cli, + uint16_t addr) +{ + struct bt_mesh_blob_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (target->addr == addr) { + return target; + } + } + + LOG_ERR("Unknown target 0x%04x", addr); + return NULL; +} + +static void target_drop(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + enum bt_mesh_blob_status reason) +{ + LOG_WRN("Dropping 0x%04x: %u", target->addr, reason); + + target->status = reason; + if (cli->cb && cli->cb->lost_target) { + cli->cb->lost_target(cli, target, reason); + } +} + +static uint32_t targets_reset(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + uint32_t count = 0; + + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_BLOB_SUCCESS) { + target->acked = 0U; + count++; + } + } + + return count; +} + +static bool targets_active(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_BLOB_SUCCESS) { + return true; + } + } + + return false; +} + +static bool targets_timedout(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + TARGETS_FOR_EACH(cli, target) { + if (!!target->timedout) { + return true; + } + } + + return false; +} + +static int io_open(struct bt_mesh_blob_cli *cli) +{ + if (!cli->io->open) { + return 0; + } + + return cli->io->open(cli->io, cli->xfer, BT_MESH_BLOB_READ); +} + +static void io_close(struct bt_mesh_blob_cli *cli) +{ + if (!cli->io->close) { + return; + } + + cli->io->close(cli->io, cli->xfer); +} + +static uint16_t next_missing_chunk(struct bt_mesh_blob_cli *cli, + const uint8_t *missing_chunks, + uint16_t idx) +{ + do { + if (blob_chunk_missing_get(missing_chunks, idx)) { + break; + } + } while (++idx < cli->block.chunk_count); + + return idx; +} + +/* Used in Pull mode to collect all missing chunks from each target in cli->block.missing. */ +static void update_missing_chunks(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + memset(cli->block.missing, 0, sizeof(cli->block.missing)); + + TARGETS_FOR_EACH(cli, target) { + if (target->procedure_complete || target->timedout) { + continue; + } + + for (size_t idx = 0; idx < cli->block.chunk_count; idx++) { + bool missing = blob_chunk_missing_get(cli->block.missing, idx) || + blob_chunk_missing_get(target->pull->missing, idx); + blob_chunk_missing_set(cli->block.missing, idx, missing); + } + } +} + +static inline size_t chunk_size(const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block, + uint16_t chunk_idx) +{ + if ((chunk_idx == block->chunk_count - 1) && + (block->size % xfer->chunk_size)) { + return block->size % xfer->chunk_size; + } + + return xfer->chunk_size; +} + +static int chunk_idx_decode(struct net_buf_simple *buf) +{ + uint16_t data; + uint8_t byte; + + if (buf->len == 0) { + return -EINVAL; + } + + byte = net_buf_simple_pull_u8(buf); + + /* utf-8 decoding */ + if ((byte & 0xf0) == 0xe0) { /* 0x800 - 0xffff */ + if (buf->len < 2) { + return -EINVAL; + } + + data = (byte & 0x0f) << 12; + data |= (net_buf_simple_pull_u8(buf) & 0x3f) << 6; + data |= (net_buf_simple_pull_u8(buf) & 0x3f); + } else if ((byte & 0xe0) == 0xc0) { /* 0x80 - 0x7ff */ + if (buf->len < 1) { + return -EINVAL; + } + + data = (byte & 0x1f) << 6; + data |= (net_buf_simple_pull_u8(buf) & 0x3f); + } else { /* 0x00 - 0x7f */ + data = byte & 0x7f; + } + + return data; +} + +static void block_set(struct bt_mesh_blob_cli *cli, uint16_t block_idx) +{ + cli->block.number = block_idx; + cli->block.offset = block_idx * (1UL << cli->xfer->block_size_log); + cli->block.size = blob_block_size(cli->xfer->size, cli->xfer->block_size_log, + block_idx); + cli->block.chunk_count = + DIV_ROUND_UP(cli->block.size, cli->xfer->chunk_size); + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + blob_chunk_missing_set_all(&cli->block); + } else { + struct bt_mesh_blob_target *target; + + /* In pull mode, the server will tell us which blocks are missing. */ + memset(cli->block.missing, 0, sizeof(cli->block.missing)); + + TARGETS_FOR_EACH(cli, target) { + memset(target->pull->missing, 0, sizeof(target->pull->missing)); + } + } + + LOG_DBG("%u size: %u chunks: %u", block_idx, cli->block.size, + cli->block.chunk_count); +} + +static void suspend(struct bt_mesh_blob_cli *cli) +{ + cli->state = BT_MESH_BLOB_CLI_STATE_SUSPENDED; + + if (cli->cb && cli->cb->suspended) { + cli->cb->suspended(cli); + } +} + +static void end(struct bt_mesh_blob_cli *cli, bool success) +{ + const struct bt_mesh_blob_xfer *xfer = cli->xfer; + + LOG_DBG("%u", success); + + io_close(cli); + cli_state_reset(cli); + if (cli->cb && cli->cb->end) { + cli->cb->end(cli, xfer, success); + } +} + +static enum bt_mesh_blob_status caps_adjust(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_caps *in) +{ + if (!(in->modes & cli->caps.modes)) { + return BT_MESH_BLOB_ERR_UNSUPPORTED_MODE; + } + + if ((in->min_block_size_log > cli->caps.max_block_size_log) || + (in->max_block_size_log < cli->caps.min_block_size_log)) { + return BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE; + } + + cli->caps.min_block_size_log = + MAX(cli->caps.min_block_size_log, in->min_block_size_log); + cli->caps.max_block_size_log = + MIN(cli->caps.max_block_size_log, in->max_block_size_log); + cli->caps.max_chunks = MIN(cli->caps.max_chunks, in->max_chunks); + cli->caps.mtu_size = MIN(cli->caps.mtu_size, in->mtu_size); + cli->caps.max_chunk_size = MIN(cli->caps.max_chunk_size, in->max_chunk_size); + cli->caps.modes &= in->modes; + cli->caps.max_size = MIN(cli->caps.max_size, in->max_size); + + return BT_MESH_BLOB_SUCCESS; +} + +/******************************************************************************* + * TX State machine + * + * All messages in the transfer are going out to all the targets, either through + * group messaging or directly to each. The TX state machine implements this + * pattern for the transfer state machine to use. It will send the messages to + * all devices (through the group or directly), repeating until it receives a + * response from each device, or the attempts run out. Messages may also be + * marked as unacked if they require no response. + ******************************************************************************/ + +static struct bt_mesh_blob_target *next_target(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target **current) +{ + if (*current) { + *current = SYS_SLIST_PEEK_NEXT_CONTAINER(*current, n); + } else { + *current = SYS_SLIST_PEEK_HEAD_CONTAINER( + (sys_slist_t *)&cli->inputs->targets, *current, n); + } + + while (*current) { + if ((*current)->acked || (*current)->procedure_complete || + (*current)->status != BT_MESH_BLOB_SUCCESS || (*current)->timedout || + (*current)->skip) { + goto next; + } + + if (SENDING_CHUNKS_IN_PULL_MODE(cli) && + (k_uptime_get() < (*current)->pull->block_report_timestamp || + !blob_chunk_missing_get((*current)->pull->missing, cli->chunk_idx))) { + /* Skip targets that didn't time out or timed out, but confirmed + * the currently transmitted chunk (cli->chunk_idx). + */ + goto next; + } + + break; + +next: + *current = SYS_SLIST_PEEK_NEXT_CONTAINER(*current, n); + } + + return *current; +} + +static void send(struct bt_mesh_blob_cli *cli) +{ + cli->tx.sending = 1U; + if (UNICAST_MODE(cli)) { + cli->tx.ctx.send(cli, cli->tx.target->addr); + } else { + cli->tx.ctx.send(cli, cli->inputs->group); + } +} + +static void broadcast_complete(struct bt_mesh_blob_cli *cli) +{ + LOG_DBG("%s", cli->tx.cancelled ? "cancelling" : "continuing"); + + cli->tx.ctx.is_inited = 0; + k_work_cancel_delayable(&cli->tx.retry); + + if (cli->tx.cancelled) { + transfer_cancel(cli); + } else { + __ASSERT(cli->tx.ctx.next, "No next callback"); + cli->tx.ctx.next(cli); + } +} + +static void tx_complete(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct bt_mesh_blob_cli *cli = CONTAINER_OF(dwork, struct bt_mesh_blob_cli, tx.complete); + + if (!cli->tx.ctx.is_inited || !cli->tx.sending) { + return; + } + + cli->tx.sending = 0U; + + if (cli->tx.cancelled) { + broadcast_complete(cli); + return; + } + + if (cli->tx.ctx.send_complete) { + cli->tx.ctx.send_complete(cli, cli->tx.target->addr); + } + + if (UNICAST_MODE(cli) && next_target(cli, &cli->tx.target)) { + send(cli); + return; + } + + if (cli->tx.ctx.acked && cli->tx.pending) { + start_retry_timer(cli); + return; + } + + broadcast_complete(cli); +} + +static void drop_remaining_targets(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + LOG_DBG(""); + + cli->tx.pending = 0; + + TARGETS_FOR_EACH(cli, target) { + if (!target->acked && !target->timedout && !target->procedure_complete && + !target->skip) { + target->timedout = 1U; + target_drop(cli, target, BT_MESH_BLOB_ERR_INTERNAL); + } + } + + /* Update missing chunks to exclude chunks from dropped targets. */ + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + update_missing_chunks(cli); + } +} + +static void retry_timeout(struct k_work *work) +{ + struct bt_mesh_blob_cli *cli = + CONTAINER_OF(work, struct bt_mesh_blob_cli, tx.retry.work); + + /* When sending chunks in Pull mode, timeout is handled differently. Client will drop all + * non-responsive servers by cli_timestamp. By calling broadcast_complete(), client will + * either retransmit the missing chunks (if any), or proceed to the next block, or suspend + * the transfer if all targets timed out. All this is handled in block_check_end(). + * Retry logic for all other procedures in Pull mode is handled as in Push mode. + */ + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + if (k_uptime_get() >= cli->tx.cli_timestamp) { + LOG_DBG("Transfer timed out."); + + if (!cli->tx.ctx.optional) { + drop_remaining_targets(cli); + } + } + + broadcast_complete(cli); + return; + } + + LOG_DBG("%u", cli->tx.retries); + + cli->tx.retries--; + cli->tx.target = NULL; + + __ASSERT(!cli->tx.sending, "still sending"); + __ASSERT(cli->tx.ctx.is_inited, "ctx is not initialized"); + + if (!cli->tx.retries) { + LOG_DBG("Transfer timed out."); + + if (!cli->tx.ctx.optional) { + drop_remaining_targets(cli); + } + + broadcast_complete(cli); + return; + } + + if (!cli->tx.ctx.acked || !next_target(cli, &cli->tx.target) || cli->tx.cancelled) { + broadcast_complete(cli); + return; + } + + send(cli); +} + +void blob_cli_broadcast(struct bt_mesh_blob_cli *cli, + const struct blob_cli_broadcast_ctx *ctx) +{ + if (cli->tx.ctx.is_inited || cli->tx.sending) { + LOG_ERR("BLOB cli busy"); + return; + } + + cli->tx.cancelled = 0U; + cli->tx.retries = CONFIG_BT_MESH_BLOB_CLI_BLOCK_RETRIES; + cli->tx.ctx = *ctx; + cli->tx.ctx.is_inited = 1U; + + cli->tx.pending = targets_reset(cli); + + LOG_DBG("%u targets", cli->tx.pending); + + cli->tx.target = NULL; + if (!next_target(cli, &cli->tx.target)) { + LOG_DBG("No active targets"); + broadcast_complete(cli); + return; + } + + send(cli); +} + +void blob_cli_broadcast_tx_complete(struct bt_mesh_blob_cli *cli) +{ + k_work_schedule(&cli->tx.complete, K_MSEC(cli->tx.ctx.post_send_delay_ms)); +} + +void blob_cli_broadcast_rsp(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target) +{ + if (target->acked) { + return; + } + + LOG_DBG("0x%04x, pending: %d", target->addr, cli->tx.pending); + + target->acked = 1U; + + if (!--cli->tx.pending && !cli->tx.sending) { + broadcast_complete(cli); + } +} + +void blob_cli_broadcast_abort(struct bt_mesh_blob_cli *cli) +{ + if (!cli->tx.ctx.is_inited) { + return; + } + + if ((cli)->state >= BT_MESH_BLOB_CLI_STATE_START) { + io_close(cli); + } + + cli_state_reset(cli); +} + +static void send_start(uint16_t duration, int err, void *cb_data); +static void send_end(int err, void *user_data); + +static int tx(struct bt_mesh_blob_cli *cli, uint16_t addr, + struct net_buf_simple *buf) +{ + static const struct bt_mesh_send_cb end_cb = { + .start = send_start, + .end = send_end, + }; + struct bt_mesh_msg_ctx ctx = { + .app_idx = cli->inputs->app_idx, + .addr = addr, + .send_ttl = cli->inputs->ttl, + }; + int err; + + err = bt_mesh_model_send(cli->mod, &ctx, buf, &end_cb, cli); + if (err) { + LOG_ERR("Send err: %d", err); + send_end(err, cli); + return err; + } + + return 0; +} + +static void send_start(uint16_t duration, int err, void *cb_data) +{ + if (err) { + LOG_ERR("TX Start failed: %d", err); + send_end(err, cb_data); + } +} + +static void send_end(int err, void *user_data) +{ + struct bt_mesh_blob_cli *cli = user_data; + + if (!cli->tx.ctx.is_inited) { + return; + } + + blob_cli_broadcast_tx_complete(cli); +} + +/******************************************************************************* + * TX + ******************************************************************************/ + +static void info_get_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_INFO_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_INFO_GET); + + tx(cli, dst, &buf); +} + +static void xfer_start_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_START, 16); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_START); + net_buf_simple_add_u8(&buf, cli->xfer->mode << 6); + net_buf_simple_add_le64(&buf, cli->xfer->id); + net_buf_simple_add_le32(&buf, cli->xfer->size); + net_buf_simple_add_u8(&buf, cli->xfer->block_size_log); + net_buf_simple_add_le16(&buf, BT_MESH_TX_SDU_MAX); + + tx(cli, dst, &buf); +} + +static void xfer_get_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_GET); + + tx(cli, dst, &buf); +} + +static void xfer_cancel_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_CANCEL, 8); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_CANCEL); + net_buf_simple_add_le64(&buf, cli->xfer->id); + + tx(cli, dst, &buf); +} + +static void block_start_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_START, 4); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_START); + net_buf_simple_add_le16(&buf, cli->block.number); + net_buf_simple_add_le16(&buf, cli->xfer->chunk_size); + + tx(cli, dst, &buf); +} + +static void chunk_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX); + struct bt_mesh_blob_chunk chunk; + int err; + + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_CHUNK); + net_buf_simple_add_le16(&buf, cli->chunk_idx); + + chunk.size = chunk_size(cli->xfer, &cli->block, cli->chunk_idx); + chunk.offset = cli->xfer->chunk_size * cli->chunk_idx; + chunk.data = net_buf_simple_add(&buf, chunk.size); + + err = cli->io->rd(cli->io, cli->xfer, &cli->block, &chunk); + if (err || cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { + bt_mesh_blob_cli_cancel(cli); + return; + } + + tx(cli, dst, &buf); +} + +static void block_get_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_GET); + + tx(cli, dst, &buf); +} + +/************************************************************************************************** + * State machine + * + * The BLOB Client state machine walks through the steps in the BLOB transfer in the following + * fashion: + * + * .---------------------------------------. + * V | + * xfer_start -> block_set -> block_start -> chunk_send -> chunk_send_end | + * A | | + * | V | + * | [more missing chunks?]-----[Yes]-----+ + * | | | + * | [No] | + * | | | + * | V | + * | [mode?] | + * | .---[Push]---' '---[Pull]---. | + * | | | | + * | V V | + * | block_check block_report_wait | + * | | | | + * | '-----------. .-------------' | + * | | | | + * | V V | + * | block_check_end | + * | | | + * | V | + * | [block completed?]------[No]------' + * | | + * | [Yes] + * | | + * | V + * '-------------------[No]------------[last block sent?] + * | + * [Yes] + * | + * V + * confirm_transfer + * | + * V + * transfer_complete + * + * In each state, the Client transmits a message to all target nodes. In each state, except when + * sending chunks (chunk_send), the Client expects a response from all target nodes, before + * proceeding to the next state. + * + * When a target node responds, the Client calls @ref blob_cli_broadcast_rsp for the corresponding + * target. Once all target nodes has responded, the Client proceeds to the next state. + * + * When sending chunks in Push mode, the Client will proceed to the next state (block_check) after + * transmitting all missing chunks. In the block_check state, the Client will request a block status + * from all target nodes. If any targets have missing chunks, the Client will resend them. + * + * When sending chunks in Pull mode, the Client addresses each target node individually using + * @ref bt_mesh_blob_target_pull structure. The Client uses @ref bt_mesh_blob_cli::block::missing + * to keep all missing chunks for the current block. Missing chunks for an individual target + * is kept in @ref bt_mesh_blob_target_pull::missing. The Client uses @ref + * bt_mesh_blob_target_pull::block_report_timeout to decide if it can send a chunk to this target. + * + * After sending all reported missing chunks to each target, the Client updates + * @ref bt_mesh_blob_target_pull::block_report_timestamp value for every target individually in + * chunk_tx_complete. The Client then proceeds to block_report_wait state and uses the earliest of + * all block_report_timestamp and cli_timestamp to schedule the retry timer. When the retry + * timer expires, the Client proceeds to the block_check_end state. + * + * In Pull mode, target nodes send a Partial Block Report message to the Client to inform about + * missing chunks. The Client doesn't control when these messages are sent by target nodes, and + * therefore it can't use @ref blob_cli_broadcast_rsp when it receives them. When the Client + * receives the Partial Block Report message, it updates missing chunks, resets + * block_report_timestamp, and explicitly calls @ref broadcast_complete to proceed to + * block_check_end state. + * + **************************************************************************************************/ +static void caps_collected(struct bt_mesh_blob_cli *cli); +static void block_start(struct bt_mesh_blob_cli *cli); +static void chunk_send(struct bt_mesh_blob_cli *cli); +static void block_check(struct bt_mesh_blob_cli *cli); +static void block_check_end(struct bt_mesh_blob_cli *cli); +static void block_report_wait(struct bt_mesh_blob_cli *cli); +static void chunk_send_end(struct bt_mesh_blob_cli *cli); +static void confirm_transfer(struct bt_mesh_blob_cli *cli); +static void transfer_complete(struct bt_mesh_blob_cli *cli); + +static void caps_get(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = info_get_tx, + .next = caps_collected, + .acked = true, + }; + + cli->state = BT_MESH_BLOB_CLI_STATE_CAPS_GET; + blob_cli_broadcast(cli, &ctx); +} + +static void caps_collected(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + bool success = false; + + cli->state = BT_MESH_BLOB_CLI_STATE_NONE; + + cli_state_reset(cli); + + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_BLOB_SUCCESS) { + success = true; + break; + } + } + + while (success && + (1UL << cli->caps.max_block_size_log) > + (cli->caps.max_chunk_size * cli->caps.max_chunks)) { + cli->caps.max_block_size_log--; + } + + if (cli->cb && cli->cb->caps) { + cli->cb->caps(cli, success ? &cli->caps : NULL); + } +} + +static int xfer_start(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_start_tx, + .next = block_start, + .acked = true, + }; + int err; + + err = io_open(cli); + if (err) { + return -EIO; + } + + cli->state = BT_MESH_BLOB_CLI_STATE_START; + + blob_cli_broadcast(cli, &ctx); + return 0; +} + +static void block_start(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = block_start_tx, + .next = chunk_send, + .acked = true, + }; + struct bt_mesh_blob_target *target; + + + if (!targets_active(cli)) { + if (targets_timedout(cli)) { + suspend(cli); + return; + } + + end(cli, false); + return; + } + + LOG_DBG("%u (%u chunks, %u/%u)", cli->block.number, + cli->block.chunk_count, cli->block.number + 1, cli->block_count); + + cli->chunk_idx = 0; + cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_START; + /* Client Timeout Timer in Send Data State Machine is initialized initially after + * transmitting the first bunch of chunks (see block_report_wait()). Next time it will be + * updated after every Partial Block Report message. + */ + cli->tx.cli_timestamp = 0ll; + + TARGETS_FOR_EACH(cli, target) { + target->procedure_complete = 0U; + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + target->pull->block_report_timestamp = 0ll; + } + } + + if (cli->io->block_start) { + cli->io->block_start(cli->io, cli->xfer, &cli->block); + if (cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { + return; + } + } + + blob_cli_broadcast(cli, &ctx); +} + +static void chunk_tx_complete(struct bt_mesh_blob_cli *cli, uint16_t dst) +{ + if (cli->xfer->mode != BT_MESH_BLOB_XFER_MODE_PULL) { + return; + } + + /* Update Block Report Timer individually for each target after sending out the last chunk + * in current iteration. + */ + uint16_t chunk_idx = next_missing_chunk(cli, cli->tx.target->pull->missing, + cli->chunk_idx + 1); + if (chunk_idx < cli->block.chunk_count) { + /* Will send more chunks to this target in this iteration. */ + return; + } + + /* This was the last chunk sent for this target. Now start the Block Report Timeout Timer. + */ + struct bt_mesh_blob_target *target; + int64_t timestamp = k_uptime_get() + BLOCK_REPORT_TIME_MSEC; + + if (!UNICAST_MODE(cli)) { + /* If using group addressing, reset timestamp for all targets after all chunks are + * sent to the group address + */ + TARGETS_FOR_EACH(cli, target) { + target->pull->block_report_timestamp = timestamp; + } + return; + } + + cli->tx.target->pull->block_report_timestamp = timestamp; +} + +static void chunk_send(struct bt_mesh_blob_cli *cli) +{ + struct blob_cli_broadcast_ctx ctx = { + .send = chunk_tx, + .next = chunk_send_end, + .acked = false, + .post_send_delay_ms = cli->chunk_interval_ms, + }; + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + ctx.send_complete = chunk_tx_complete; + } + + if (!targets_active(cli)) { + if (targets_timedout(cli)) { + suspend(cli); + return; + } + + end(cli, false); + return; + } + + LOG_DBG("%u / %u size: %u", cli->chunk_idx + 1, cli->block.chunk_count, + chunk_size(cli->xfer, &cli->block, cli->chunk_idx)); + + cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_SEND; + blob_cli_broadcast(cli, &ctx); +} + +static void chunk_send_end(struct bt_mesh_blob_cli *cli) +{ + /* In pull mode, the partial block reports are used to confirm which + * chunks have been received, while in push mode, we just assume that a + * sent chunk has been received. + */ + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + blob_chunk_missing_set(cli->block.missing, cli->chunk_idx, false); + } + + cli->chunk_idx = next_missing_chunk(cli, cli->block.missing, cli->chunk_idx + 1); + if (cli->chunk_idx < cli->block.chunk_count) { + chunk_send(cli); + return; + } + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + block_check(cli); + } else { + block_report_wait(cli); + } +} + +/* The block checking pair(block_check - block_check_end) + * is relevant only for Push mode. + */ +static void block_check(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = block_get_tx, + .next = block_check_end, + .acked = true, + }; + + cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK; + + LOG_DBG(""); + + blob_cli_broadcast(cli, &ctx); +} + +static void block_report_wait(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .next = block_check_end, + .acked = false, + }; + + /* Check if all servers already confirmed all chunks during the transmission. */ + if (next_missing_chunk(cli, cli->block.missing, 0) >= cli->block.chunk_count) { + block_check_end(cli); + return; + } + + LOG_DBG("Waiting for partial block report..."); + cli->tx.ctx = ctx; + + /* Start Client Timeout Timer in Send Data sub-procedure for the first time. */ + if (!cli->tx.cli_timestamp) { + cli->tx.cli_timestamp = k_uptime_get() + CLIENT_TIMEOUT_MSEC(cli); + } + + start_retry_timer(cli); +} + +static void block_check_end(struct bt_mesh_blob_cli *cli) +{ + LOG_DBG(""); + + if (!targets_active(cli)) { + if (targets_timedout(cli)) { + suspend(cli); + return; + } + + end(cli, false); + return; + } + + cli->chunk_idx = next_missing_chunk(cli, cli->block.missing, 0); + if (cli->chunk_idx < cli->block.chunk_count) { + chunk_send(cli); + return; + } + + LOG_DBG("No more missing chunks for block %u", cli->block.number); + + if (cli->io->block_end) { + cli->io->block_end(cli->io, cli->xfer, &cli->block); + if (cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { + return; + } + } + + if (cli->block.number == cli->block_count - 1) { + struct bt_mesh_blob_target *target; + + TARGETS_FOR_EACH(cli, target) { + target->procedure_complete = 0U; + } + + confirm_transfer(cli); + return; + } + + block_set(cli, cli->block.number + 1); + block_start(cli); +} + +static void confirm_transfer(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_get_tx, + .next = transfer_complete, + .acked = true, + }; + + LOG_DBG(""); + + cli->state = BT_MESH_BLOB_CLI_STATE_XFER_CHECK; + + blob_cli_broadcast(cli, &ctx); +} + +static void progress_checked(struct bt_mesh_blob_cli *cli) +{ + LOG_DBG(""); + + cli->state = BT_MESH_BLOB_CLI_STATE_NONE; + + if (cli->cb && cli->cb->end) { + cli->cb->xfer_progress_complete(cli); + } +} + +static void check_transfer(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_get_tx, + .next = progress_checked, + .acked = true, + }; + + LOG_DBG(""); + + cli->state = BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET; + + blob_cli_broadcast(cli, &ctx); +} + +static void transfer_cancel(struct bt_mesh_blob_cli *cli) +{ + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_cancel_tx, + .next = transfer_complete, + .acked = true, + }; + + LOG_DBG(""); + + cli->state = BT_MESH_BLOB_CLI_STATE_CANCEL; + + blob_cli_broadcast(cli, &ctx); +} + +static void transfer_complete(struct bt_mesh_blob_cli *cli) +{ + bool success = targets_active(cli) && + cli->state == BT_MESH_BLOB_CLI_STATE_XFER_CHECK; + + end(cli, success); +} + +/******************************************************************************* + * RX + ******************************************************************************/ + +static void rx_block_status(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + struct block_status *block) +{ + if (cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_START && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK) { + LOG_WRN("Invalid state %u", cli->state); + return; + } + + LOG_DBG("0x%04x: block: %u status: %u", target->addr, block->block.number, block->status); + + if (block->status != BT_MESH_BLOB_SUCCESS) { + target_drop(cli, target, block->status); + blob_cli_broadcast_rsp(cli, target); + return; + } + + if (block->block.number != cli->block.number) { + LOG_DBG("Invalid block num (expected %u)", cli->block.number); + return; + } + + if (block->missing == BT_MESH_BLOB_CHUNKS_MISSING_NONE) { + target->procedure_complete = 1U; + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + memset(target->pull->missing, 0, sizeof(target->pull->missing)); + update_missing_chunks(cli); + } + + LOG_DBG("Target 0x%04x received all chunks", target->addr); + } else if (block->missing == BT_MESH_BLOB_CHUNKS_MISSING_ALL) { + blob_chunk_missing_set_all(&cli->block); + } else if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + memcpy(target->pull->missing, block->block.missing, sizeof(block->block.missing)); + + LOG_DBG("Missing: %s", bt_hex(target->pull->missing, cli->block.chunk_count)); + + update_missing_chunks(cli); + + /* Target has responded. Reset the timestamp so that client can start transmitting + * missing chunks to it. + */ + target->pull->block_report_timestamp = 0ll; + } else { + for (int i = 0; i < ARRAY_SIZE(block->block.missing); ++i) { + cli->block.missing[i] |= block->block.missing[i]; + } + } + + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + if (!cli->tx.sending) { + /* If not sending, then the retry timer is running. Call + * broadcast_complete() to proceed to block_check_end() and start + * transmitting missing chunks. + */ + broadcast_complete(cli); + } + + /* When sending chunks in Pull mode, we don't confirm transaction when receiving + * Partial Block Report message. + */ + return; + } + + blob_cli_broadcast_rsp(cli, target); +} + +static int handle_xfer_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_cli *cli = mod->rt->user_data; + enum bt_mesh_blob_xfer_phase expected_phase; + struct bt_mesh_blob_target *target; + struct bt_mesh_blob_xfer_info info = { 0 }; + uint8_t status_and_mode; + + status_and_mode = net_buf_simple_pull_u8(buf); + info.status = status_and_mode & BIT_MASK(4); + info.mode = status_and_mode >> 6; + info.phase = net_buf_simple_pull_u8(buf); + + if (buf->len) { + info.id = net_buf_simple_pull_le64(buf); + } + + if (buf->len >= 7) { + info.size = net_buf_simple_pull_le32(buf); + info.block_size_log = net_buf_simple_pull_u8(buf); + info.mtu_size = net_buf_simple_pull_le16(buf); + info.missing_blocks = net_buf_simple_pull(buf, buf->len); + } + + LOG_DBG("status: %u %s phase: %u %s", info.status, + info.mode == BT_MESH_BLOB_XFER_MODE_PUSH ? "push" : "pull", + info.phase, bt_hex(&info.id, 8)); + + + if (cli->state != BT_MESH_BLOB_CLI_STATE_START && + cli->state != BT_MESH_BLOB_CLI_STATE_XFER_CHECK && + cli->state != BT_MESH_BLOB_CLI_STATE_CANCEL && + cli->state != BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET) { + LOG_WRN("Wrong state: %d", cli->state); + return -EBUSY; + } + + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } + + if (cli->state == BT_MESH_BLOB_CLI_STATE_START) { + expected_phase = BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK; + } else if (cli->state == BT_MESH_BLOB_CLI_STATE_XFER_CHECK) { + expected_phase = BT_MESH_BLOB_XFER_PHASE_COMPLETE; + } else if (cli->state != BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET) { + expected_phase = BT_MESH_BLOB_XFER_PHASE_INACTIVE; + } else { /* cli->state == BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET */ + blob_cli_broadcast_rsp(cli, target); + if (cli->cb && cli->cb->xfer_progress) { + cli->cb->xfer_progress(cli, target, &info); + } + return 0; + } + + if (info.status != BT_MESH_BLOB_SUCCESS) { + target_drop(cli, target, info.status); + } else if (info.phase != expected_phase) { + LOG_WRN("Wrong phase: %u != %u", expected_phase, info.phase); + return -EINVAL; + } else if (info.phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE && + info.id != cli->xfer->id) { + target_drop(cli, target, BT_MESH_BLOB_ERR_WRONG_BLOB_ID); + } + + blob_cli_broadcast_rsp(cli, target); + + return 0; +} + +static int handle_block_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_cli *cli = mod->rt->user_data; + struct block_status status = { + .status = BT_MESH_BLOB_SUCCESS, + .block.number = cli->block.number, + .missing = (buf->len ? BT_MESH_BLOB_CHUNKS_MISSING_ENCODED : + BT_MESH_BLOB_CHUNKS_MISSING_NONE), + }; + struct bt_mesh_blob_target *target; + + if (!cli->xfer) { + return -EINVAL; + } + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + LOG_WRN("Unexpected encoded block report in push mode"); + return -EINVAL; + } + + LOG_DBG(""); + + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } + + while (buf->len) { + int idx; + + idx = chunk_idx_decode(buf); + if (idx < 0) { + return idx; + } + + blob_chunk_missing_set(status.block.missing, idx, true); + } + + /* If all chunks were already confirmed by this target, Send Data State Machine is in Final + * state for this target. Therefore, the message should be ignored. + */ + if (next_missing_chunk(cli, target->pull->missing, 0) >= cli->block.chunk_count) { + LOG_DBG("All chunks already confirmed"); + return 0; + } + + cli->tx.cli_timestamp = k_uptime_get() + CLIENT_TIMEOUT_MSEC(cli); + + rx_block_status(cli, target, &status); + + return 0; +} + +static int handle_block_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_cli *cli = mod->rt->user_data; + struct bt_mesh_blob_target *target; + struct block_status status = { 0 }; + uint8_t status_and_format; + uint16_t chunk_size; + size_t len; + int idx; + + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } + + status_and_format = net_buf_simple_pull_u8(buf); + status.status = status_and_format & BIT_MASK(4); + status.missing = status_and_format >> 6; + status.block.number = net_buf_simple_pull_le16(buf); + chunk_size = net_buf_simple_pull_le16(buf); + status.block.chunk_count = + DIV_ROUND_UP(cli->block.size, chunk_size); + + LOG_DBG("status: %u block: %u encoding: %u", status.status, + status.block.number, status.missing); + + switch (status.missing) { + case BT_MESH_BLOB_CHUNKS_MISSING_ALL: + blob_chunk_missing_set_all(&status.block); + break; + case BT_MESH_BLOB_CHUNKS_MISSING_NONE: + break; + case BT_MESH_BLOB_CHUNKS_MISSING_SOME: + if (buf->len > sizeof(status.block.missing)) { + return -EINVAL; + } + + len = buf->len; + memcpy(status.block.missing, net_buf_simple_pull_mem(buf, len), + len); + + LOG_DBG("Missing: %s", bt_hex(status.block.missing, len)); + break; + case BT_MESH_BLOB_CHUNKS_MISSING_ENCODED: + /** MshMBTv1.0: 5.3.8: An empty Missing Chunks field entails that there are no + * missing chunks for this block. + */ + if (!buf->len) { + status.missing = BT_MESH_BLOB_CHUNKS_MISSING_NONE; + } + + while (buf->len) { + idx = chunk_idx_decode(buf); + if (idx < 0 || idx >= status.block.chunk_count) { + LOG_ERR("Invalid encoding"); + return -EINVAL; + } + + LOG_DBG("Missing %d", idx); + + blob_chunk_missing_set(status.block.missing, idx, true); + } + break; + } + + rx_block_status(cli, target, &status); + + return 0; +} + +static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_cli *cli = mod->rt->user_data; + struct bt_mesh_blob_cli_caps caps; + enum bt_mesh_blob_status status; + struct bt_mesh_blob_target *target; + + if (cli->state != BT_MESH_BLOB_CLI_STATE_CAPS_GET) { + return -EBUSY; + } + + caps.min_block_size_log = net_buf_simple_pull_u8(buf); + caps.max_block_size_log = net_buf_simple_pull_u8(buf); + caps.max_chunks = net_buf_simple_pull_le16(buf); + caps.max_chunk_size = net_buf_simple_pull_le16(buf); + caps.max_size = net_buf_simple_pull_le32(buf); + caps.mtu_size = net_buf_simple_pull_le16(buf); + caps.modes = net_buf_simple_pull_u8(buf); + + if (caps.min_block_size_log < 0x06 || + caps.max_block_size_log > 0x20 || + caps.max_block_size_log < caps.min_block_size_log || + caps.max_chunks == 0 || caps.max_chunk_size < 8 || + caps.max_size == 0 || caps.mtu_size < 0x14) { + return -EINVAL; + } + + LOG_DBG("0x%04x\n\tblock size: %u - %u\n\tchunks: %u\n\tchunk size: %u\n" + "\tblob size: %u\n\tmtu size: %u\n\tmodes: %x", + ctx->addr, caps.min_block_size_log, caps.max_block_size_log, + caps.max_chunks, caps.max_chunk_size, caps.max_size, + caps.mtu_size, caps.modes); + + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } + + status = caps_adjust(cli, &caps); + if (status != BT_MESH_BLOB_SUCCESS) { + target_drop(cli, target, status); + } + + blob_cli_broadcast_rsp(cli, target); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_blob_cli_op[] = { + { BT_MESH_BLOB_OP_XFER_STATUS, BT_MESH_LEN_MIN(2), handle_xfer_status }, + { BT_MESH_BLOB_OP_BLOCK_REPORT, BT_MESH_LEN_MIN(0), handle_block_report }, + { BT_MESH_BLOB_OP_BLOCK_STATUS, BT_MESH_LEN_MIN(5), handle_block_status }, + { BT_MESH_BLOB_OP_INFO_STATUS, BT_MESH_LEN_EXACT(13), handle_info_status }, + BT_MESH_MODEL_OP_END, +}; + +static int blob_cli_init(const struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_cli *cli = mod->rt->user_data; + + cli->mod = mod; + + bt_mesh_blob_cli_set_chunk_interval_ms(cli, CONFIG_BT_MESH_TX_BLOB_CHUNK_SEND_INTERVAL); + cli->tx.cli_timestamp = 0ll; + k_work_init_delayable(&cli->tx.retry, retry_timeout); + k_work_init_delayable(&cli->tx.complete, tx_complete); + + return 0; +} + +static void blob_cli_reset(const struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_cli *cli = mod->rt->user_data; + + cli_state_reset(cli); +} + +const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb = { + .init = blob_cli_init, + .reset = blob_cli_reset, +}; + + +int bt_mesh_blob_cli_caps_get(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs) +{ + if (bt_mesh_blob_cli_is_busy(cli)) { + return -EBUSY; + } + + cli->inputs = inputs; + + cli->caps.min_block_size_log = 0x06; + cli->caps.max_block_size_log = 0x20; + cli->caps.max_chunks = CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX; + cli->caps.max_chunk_size = BLOB_TX_CHUNK_SIZE; + cli->caps.max_size = 0xffffffff; + cli->caps.mtu_size = 0xffff; + cli->caps.modes = BT_MESH_BLOB_XFER_MODE_ALL; + + if (!targets_reset(cli)) { + LOG_ERR("No valid targets"); + return -ENODEV; + } + + caps_get(cli); + + return 0; +} + +int bt_mesh_blob_cli_send(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io *io) +{ + if (bt_mesh_blob_cli_is_busy(cli)) { + LOG_ERR("BLOB Client is busy"); + return -EBUSY; + } + + if (!(xfer->mode & BT_MESH_BLOB_XFER_MODE_ALL) || xfer->block_size_log < 0x06 || + xfer->block_size_log > 0x20 || xfer->chunk_size < 8 || + xfer->chunk_size > BLOB_TX_CHUNK_SIZE) { + LOG_ERR("Incompatible transfer parameters"); + return -EINVAL; + } + + cli->xfer = xfer; + cli->inputs = inputs; + cli->io = io; + + if (cli->xfer->block_size_log == 0x20) { + cli->block_count = 1; + } else { + cli->block_count = DIV_ROUND_UP(cli->xfer->size, (1U << cli->xfer->block_size_log)); + } + + block_set(cli, 0); + + if (cli->block.chunk_count > CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX) { + LOG_ERR("Too many chunks"); + return -EINVAL; + } + + if (!targets_reset(cli)) { + LOG_ERR("No valid targets"); + return -ENODEV; + } + + LOG_DBG("\n\tblock size log: %u\n\tchunk size: %u\n" + "\tblob size: %u\n\tmode: %x", + cli->xfer->block_size_log, cli->xfer->chunk_size, + cli->xfer->size, cli->xfer->mode); + + return xfer_start(cli); +} + +int bt_mesh_blob_cli_suspend(struct bt_mesh_blob_cli *cli) +{ + if (cli->state == BT_MESH_BLOB_CLI_STATE_SUSPENDED) { + return 0; + } + + if (cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_START && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK) { + LOG_WRN("BLOB xfer not started: %d", cli->state); + return -EINVAL; + } + + cli->state = BT_MESH_BLOB_CLI_STATE_SUSPENDED; + (void)k_work_cancel_delayable(&cli->tx.retry); + cli->tx.ctx.is_inited = 0; + cli->tx.sending = 0; + cli->tx.cli_timestamp = 0ll; + return 0; +} + +int bt_mesh_blob_cli_resume(struct bt_mesh_blob_cli *cli) +{ + struct bt_mesh_blob_target *target; + + if (cli->state != BT_MESH_BLOB_CLI_STATE_SUSPENDED) { + LOG_WRN("Not suspended"); + return -EINVAL; + } + + /* Restore timed out targets. */ + TARGETS_FOR_EACH(cli, target) { + if (!!target->timedout) { + target->status = BT_MESH_BLOB_SUCCESS; + target->timedout = 0U; + } + } + + if (!targets_reset(cli)) { + LOG_ERR("No valid targets"); + return -ENODEV; + } + + block_set(cli, 0); + return xfer_start(cli); +} + +void bt_mesh_blob_cli_cancel(struct bt_mesh_blob_cli *cli) +{ + if (!bt_mesh_blob_cli_is_busy(cli)) { + LOG_WRN("BLOB xfer already cancelled"); + return; + } + + LOG_DBG(""); + + if (cli->state == BT_MESH_BLOB_CLI_STATE_CAPS_GET || + cli->state == BT_MESH_BLOB_CLI_STATE_SUSPENDED) { + cli_state_reset(cli); + return; + } + + cli->tx.cancelled = 1U; + cli->state = BT_MESH_BLOB_CLI_STATE_CANCEL; +} + +int bt_mesh_blob_cli_xfer_progress_get(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_inputs *inputs) +{ + if (bt_mesh_blob_cli_is_busy(cli)) { + return -EBUSY; + } + + cli->inputs = inputs; + + check_transfer(cli); + + return 0; +} + +uint8_t bt_mesh_blob_cli_xfer_progress_active_get(struct bt_mesh_blob_cli *cli) +{ + if (cli->state < BT_MESH_BLOB_CLI_STATE_START) { + return 0; + } + + return (100U * cli->block.number) / cli->block_count; +} + +bool bt_mesh_blob_cli_is_busy(struct bt_mesh_blob_cli *cli) +{ + return cli->state != BT_MESH_BLOB_CLI_STATE_NONE; +} + +void bt_mesh_blob_cli_set_chunk_interval_ms(struct bt_mesh_blob_cli *cli, uint32_t interval_ms) +{ + cli->chunk_interval_ms = interval_ms; +} diff --git a/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c b/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c new file mode 100644 index 0000000000..2d4ec561f8 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c @@ -0,0 +1,1013 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "net.h" +#include "access.h" +#include "transport.h" +#include "lpn.h" +#include "blob.h" + +#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_mesh_blob_srv); + +#define MTU_SIZE_MAX (BT_MESH_RX_SDU_MAX - BT_MESH_MIC_SHORT) + +/* The Receive BLOB Timeout Timer */ +#define SERVER_TIMEOUT_SECS(srv) (10 * (1 + (srv)->state.timeout_base)) +/* The initial timer value used by an instance of the Pull BLOB State machine - T_BPI */ +#define REPORT_TIMER_TIMEOUT K_SECONDS(CONFIG_BT_MESH_BLOB_REPORT_TIMEOUT) + +BUILD_ASSERT(BLOB_BLOCK_SIZE_LOG_MIN <= BLOB_BLOCK_SIZE_LOG_MAX, + "The must be at least one number between the min and " + "max block size that is the power of two."); + +BUILD_ASSERT((BLOB_XFER_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_XFER_STATUS) + + BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, + "The BLOB Transfer Status message does not fit into the maximum outgoing SDU size."); + +BUILD_ASSERT((BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN + + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_REPORT) + BT_MESH_MIC_SHORT) + <= BT_MESH_TX_SDU_MAX, + "The BLOB Partial Block Report message does not fit into the maximum outgoing SDU " + "size."); + +BUILD_ASSERT((BLOB_BLOCK_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_STATUS) + + BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, + "The BLOB Block Status message does not fit into the maximum outgoing SDU size."); + +static void cancel(struct bt_mesh_blob_srv *srv); +static void suspend(struct bt_mesh_blob_srv *srv); + +static inline uint32_t block_count_get(const struct bt_mesh_blob_srv *srv) +{ + return DIV_ROUND_UP(srv->state.xfer.size, + (1U << srv->state.xfer.block_size_log)); +} + +static inline uint32_t max_chunk_size(const struct bt_mesh_blob_srv *srv) +{ + return MIN((srv->state.mtu_size - 2 - BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK)), + BLOB_RX_CHUNK_SIZE); +} + +static inline uint32_t max_chunk_count(const struct bt_mesh_blob_srv *srv) +{ + return MIN(8 * (srv->state.mtu_size - 6), + CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX); +} + +static inline uint32_t missing_chunks(const struct bt_mesh_blob_block *block) +{ + int i; + uint32_t count = 0; + + for (i = 0; i < ARRAY_SIZE(block->missing); ++i) { + count += POPCOUNT(block->missing[i]); + } + + return count; +} + +static void store_state(const struct bt_mesh_blob_srv *srv) +{ + if (!IS_ENABLED(CONFIG_BT_SETTINGS)) { + return; + } + + /* Convert bit count to byte count: */ + uint32_t block_len = DIV_ROUND_UP(block_count_get(srv), 8); + + bt_mesh_model_data_store( + srv->mod, false, NULL, &srv->state, + offsetof(struct bt_mesh_blob_srv_state, blocks) + block_len); +} + +static void erase_state(struct bt_mesh_blob_srv *srv) +{ + if (!IS_ENABLED(CONFIG_BT_SETTINGS)) { + return; + } + + bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0); +} + +static int io_open(struct bt_mesh_blob_srv *srv) +{ + if (!srv->io->open) { + return 0; + } + + return srv->io->open(srv->io, &srv->state.xfer, BT_MESH_BLOB_WRITE); +} + +static void io_close(struct bt_mesh_blob_srv *srv) +{ + if (!srv->io->close) { + return; + } + + srv->io->close(srv->io, &srv->state.xfer); +} + +static void reset_timer(struct bt_mesh_blob_srv *srv) +{ + uint32_t timeout_secs = + srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL ? + MAX(SERVER_TIMEOUT_SECS(srv), + CONFIG_BT_MESH_BLOB_REPORT_TIMEOUT + 1) : + SERVER_TIMEOUT_SECS(srv); + k_work_reschedule(&srv->rx_timeout, K_SECONDS(timeout_secs)); +} + +static void buf_chunk_index_add(struct net_buf_simple *buf, uint16_t chunk) +{ + /* utf-8 encoded: */ + if (chunk < 0x80) { + net_buf_simple_add_u8(buf, chunk); + } else if (chunk < 0x8000) { + net_buf_simple_add_u8(buf, 0xc0 | chunk >> 6); + net_buf_simple_add_u8(buf, 0x80 | (chunk & BIT_MASK(6))); + } else { + net_buf_simple_add_u8(buf, 0xe0 | chunk >> 12); + net_buf_simple_add_u8(buf, 0x80 | ((chunk >> 6) & BIT_MASK(6))); + net_buf_simple_add_u8(buf, 0x80 | (chunk & BIT_MASK(6))); + } +} + +static int pull_req_max(const struct bt_mesh_blob_srv *srv) +{ + int count = CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT; + +#if defined(CONFIG_BT_MESH_LOW_POWER) + /* No point in requesting more than the friend node can hold: */ + if (bt_mesh_lpn_established()) { + uint32_t segments_per_chunk = DIV_ROUND_UP( + BLOB_CHUNK_SDU_LEN(srv->state.xfer.chunk_size), + BT_MESH_APP_SEG_SDU_MAX); + + count = MIN(CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT, + bt_mesh.lpn.queue_size / segments_per_chunk); + } +#endif + + return MIN(count, missing_chunks(&srv->block)); +} + +static void report_sent(int err, void *cb_data) +{ + struct bt_mesh_blob_srv *srv = cb_data; + + LOG_DBG(""); + + if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && bt_mesh_lpn_established()) { + bt_mesh_lpn_poll(); + } + + if (k_work_delayable_is_pending(&srv->rx_timeout)) { + k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); + } +} + +static void block_report(struct bt_mesh_blob_srv *srv) +{ + static const struct bt_mesh_send_cb report_cb = { .end = report_sent }; + struct bt_mesh_msg_ctx ctx = { + .app_idx = srv->state.app_idx, + .send_ttl = srv->state.ttl, + .addr = srv->state.cli, + }; + int count; + int i; + + LOG_DBG("rx BLOB Timeout Timer: %i", k_work_delayable_is_pending(&srv->rx_timeout)); + + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_REPORT, + BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_REPORT); + + count = pull_req_max(srv); + + for (i = 0; i < srv->block.chunk_count && count; ++i) { + if (blob_chunk_missing_get(srv->block.missing, i)) { + buf_chunk_index_add(&buf, i); + count--; + } + } + + (void)bt_mesh_model_send(srv->mod, &ctx, &buf, &report_cb, srv); +} + +static void phase_set(struct bt_mesh_blob_srv *srv, + enum bt_mesh_blob_xfer_phase phase) +{ + srv->phase = phase; + LOG_DBG("Phase: %u", phase); +} + +static void cancel(struct bt_mesh_blob_srv *srv) +{ + /* TODO: Could this state be preserved instead somehow? Wiping the + * entire transfer state is a bit overkill + */ + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); + srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; + srv->state.ttl = BT_MESH_TTL_DEFAULT; + srv->block.number = 0xffff; + memset(srv->block.missing, 0, sizeof(srv->block.missing)); + srv->state.xfer.chunk_size = 0xffff; + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + io_close(srv); + erase_state(srv); + + if (srv->cb && srv->cb->end) { + srv->cb->end(srv, srv->state.xfer.id, false); + } +} + +static void suspend(struct bt_mesh_blob_srv *srv) +{ + LOG_DBG(""); + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_SUSPENDED); + if (srv->cb && srv->cb->suspended) { + srv->cb->suspended(srv); + } +} + +static void resume(struct bt_mesh_blob_srv *srv) +{ + LOG_DBG("Resuming"); + + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); + reset_timer(srv); +} + +static void end(struct bt_mesh_blob_srv *srv) +{ + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_COMPLETE); + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + io_close(srv); + erase_state(srv); + + if (srv->cb && srv->cb->end) { + srv->cb->end(srv, srv->state.xfer.id, true); + } +} + +static bool all_blocks_received(struct bt_mesh_blob_srv *srv) +{ + for (int i = 0; i < ARRAY_SIZE(srv->state.blocks); ++i) { + if (srv->state.blocks[i]) { + return false; + } + } + + return true; +} + +static bool pull_mode_xfer_complete(struct bt_mesh_blob_srv *srv) +{ + return srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL && + srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK && + all_blocks_received(srv); +} + +static void timeout(struct k_work *work) +{ + struct bt_mesh_blob_srv *srv = + CONTAINER_OF(work, struct bt_mesh_blob_srv, rx_timeout.work); + + LOG_DBG(""); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + cancel(srv); + } else if (pull_mode_xfer_complete(srv)) { + end(srv); + } else { + suspend(srv); + } +} + +static void report_timeout(struct k_work *work) +{ + struct bt_mesh_blob_srv *srv = + CONTAINER_OF(work, struct bt_mesh_blob_srv, pull.report.work); + + LOG_DBG(""); + + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK && + srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { + return; + } + + block_report(srv); +} + +/******************************************************************************* + * Message handling + ******************************************************************************/ + +static void xfer_status_rsp(struct bt_mesh_blob_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_blob_status status) +{ + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_STATUS, + BLOB_XFER_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_STATUS); + + net_buf_simple_add_u8(&buf, ((status & BIT_MASK(4)) | + (srv->state.xfer.mode << 6))); + net_buf_simple_add_u8(&buf, srv->phase); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + goto send; + } + + net_buf_simple_add_le64(&buf, srv->state.xfer.id); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + goto send; + } + + net_buf_simple_add_le32(&buf, srv->state.xfer.size); + net_buf_simple_add_u8(&buf, srv->state.xfer.block_size_log); + net_buf_simple_add_le16(&buf, srv->state.mtu_size); + net_buf_simple_add_mem(&buf, srv->state.blocks, + DIV_ROUND_UP(block_count_get(srv), 8)); + +send: + ctx->send_ttl = srv->state.ttl; + (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); +} + +static void block_status_rsp(struct bt_mesh_blob_srv *srv, + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_blob_status status) +{ + enum bt_mesh_blob_chunks_missing format; + uint32_t missing; + int i; + + BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_STATUS, + BLOB_BLOCK_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_STATUS); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || + srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + missing = srv->block.chunk_count; + } else if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE) { + missing = 0U; + } else { + missing = missing_chunks(&srv->block); + } + + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + format = BT_MESH_BLOB_CHUNKS_MISSING_ENCODED; + } else if (missing == srv->block.chunk_count) { + format = BT_MESH_BLOB_CHUNKS_MISSING_ALL; + } else if (missing == 0) { + format = BT_MESH_BLOB_CHUNKS_MISSING_NONE; + } else { + format = BT_MESH_BLOB_CHUNKS_MISSING_SOME; + } + + LOG_DBG("Status: %u, missing: %u/%u", status, missing, srv->block.chunk_count); + + net_buf_simple_add_u8(&buf, (status & BIT_MASK(4)) | (format << 6)); + net_buf_simple_add_le16(&buf, srv->block.number); + net_buf_simple_add_le16(&buf, srv->state.xfer.chunk_size); + + if (format == BT_MESH_BLOB_CHUNKS_MISSING_SOME) { + net_buf_simple_add_mem(&buf, srv->block.missing, + DIV_ROUND_UP(srv->block.chunk_count, + 8)); + + LOG_DBG("Bits: %s", + bt_hex(srv->block.missing, + DIV_ROUND_UP(srv->block.chunk_count, 8))); + + } else if (format == BT_MESH_BLOB_CHUNKS_MISSING_ENCODED) { + int count = pull_req_max(srv); + + for (i = 0; (i < srv->block.chunk_count) && count; ++i) { + if (blob_chunk_missing_get(srv->block.missing, i)) { + LOG_DBG("Missing %u", i); + buf_chunk_index_add(&buf, i); + count--; + } + } + } + + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + ctx->send_ttl = srv->state.ttl; + } + + (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); +} + +static int handle_xfer_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + + LOG_DBG(""); + + if (pull_mode_xfer_complete(srv)) { + /* The client requested transfer. If we are in Pull mode and all blocks were + * received, we should change the Transfer state here to Complete so that the client + * receives the correct state. + */ + end(srv); + } + + xfer_status_rsp(srv, ctx, BT_MESH_BLOB_SUCCESS); + + return 0; +} + +static int handle_xfer_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + enum bt_mesh_blob_status status; + enum bt_mesh_blob_xfer_mode mode; + uint64_t id; + size_t size; + uint8_t block_size_log; + uint32_t block_count; + uint16_t mtu_size; + int err; + + mode = (net_buf_simple_pull_u8(buf) >> 6); + id = net_buf_simple_pull_le64(buf); + size = net_buf_simple_pull_le32(buf); + block_size_log = net_buf_simple_pull_u8(buf); + mtu_size = net_buf_simple_pull_le16(buf); + + LOG_DBG("\n\tsize: %u block size: %u\n\tmtu_size: %u\n\tmode: %s", + size, (1U << block_size_log), mtu_size, + mode == BT_MESH_BLOB_XFER_MODE_PUSH ? "push" : "pull"); + + if (mode != BT_MESH_BLOB_XFER_MODE_PULL && + mode != BT_MESH_BLOB_XFER_MODE_PUSH) { + LOG_WRN("Invalid mode 0x%x", mode); + return -EINVAL; + } + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + LOG_WRN("Uninitialized"); + goto rsp; + } + + if (srv->state.xfer.id != id) { + status = BT_MESH_BLOB_ERR_WRONG_BLOB_ID; + /* bt_hex uses static array for the resulting hex string. + * Not possible to use bt_hex in the same logging function twice. + */ + LOG_WRN("Invalid ID: %s", bt_hex(&id, sizeof(uint64_t))); + LOG_WRN("Expected ID: %s", bt_hex(&srv->state.xfer.id, sizeof(uint64_t))); + goto rsp; + } + + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + if (srv->state.xfer.mode != mode || + srv->state.xfer.size != size || + srv->state.xfer.block_size_log != block_size_log || + srv->state.mtu_size > mtu_size) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + LOG_WRN("Busy"); + goto rsp; + } + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) { + resume(srv); + store_state(srv); + } else { + LOG_DBG("Duplicate"); + } + + status = BT_MESH_BLOB_SUCCESS; + goto rsp; + } + + if (size > CONFIG_BT_MESH_BLOB_SIZE_MAX) { + LOG_WRN("Too large"); + status = BT_MESH_BLOB_ERR_BLOB_TOO_LARGE; + goto rsp; + } + + if (((1U << block_size_log) < CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN) || + ((1U << block_size_log) > CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX)) { + LOG_WRN("Invalid block size: %u", block_size_log); + status = BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE; + goto rsp; + } + + srv->state.cli = ctx->addr; + srv->state.app_idx = ctx->app_idx; + srv->state.mtu_size = MIN(mtu_size, MTU_SIZE_MAX); + srv->state.xfer.id = id; + srv->state.xfer.size = size; + srv->state.xfer.mode = mode; + srv->state.xfer.block_size_log = block_size_log; + srv->state.xfer.chunk_size = 0xffff; + srv->block.number = 0xffff; + + block_count = block_count_get(srv); + if (block_count > BT_MESH_BLOB_BLOCKS_MAX) { + LOG_WRN("Invalid block count (%u)", block_count); + status = BT_MESH_BLOB_ERR_INVALID_PARAM; + cancel(srv); + goto rsp; + } + + memset(srv->state.blocks, 0, sizeof(srv->state.blocks)); + for (int i = 0; i < block_count; i++) { + atomic_set_bit(srv->state.blocks, i); + } + + err = io_open(srv); + if (err) { + LOG_ERR("Couldn't open stream (err: %d)", err); + status = BT_MESH_BLOB_ERR_INTERNAL; + cancel(srv); + goto rsp; + } + + if (srv->cb && srv->cb->start) { + err = srv->cb->start(srv, ctx, &srv->state.xfer); + if (err) { + LOG_ERR("Couldn't start transfer (err: %d)", err); + status = BT_MESH_BLOB_ERR_INTERNAL; + cancel(srv); + goto rsp; + } + } + + reset_timer(srv); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); + store_state(srv); + status = BT_MESH_BLOB_SUCCESS; + +rsp: + xfer_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_xfer_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + enum bt_mesh_blob_status status = BT_MESH_BLOB_SUCCESS; + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + uint64_t id; + + id = net_buf_simple_pull_le64(buf); + + LOG_DBG("%u", (uint32_t)id); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + goto rsp; + } + + if (srv->state.xfer.id != id) { + status = BT_MESH_BLOB_ERR_WRONG_BLOB_ID; + goto rsp; + } + + cancel(srv); + +rsp: + xfer_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_block_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + enum bt_mesh_blob_status status; + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + + switch (srv->phase) { + case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK: + case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK: + case BT_MESH_BLOB_XFER_PHASE_COMPLETE: + status = BT_MESH_BLOB_SUCCESS; + break; + case BT_MESH_BLOB_XFER_PHASE_SUSPENDED: + status = BT_MESH_BLOB_ERR_INFO_UNAVAILABLE; + break; + case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START: + case BT_MESH_BLOB_XFER_PHASE_INACTIVE: + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + break; + default: + status = BT_MESH_BLOB_ERR_INTERNAL; + break; + } + + LOG_DBG(""); + + block_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_block_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + enum bt_mesh_blob_status status; + uint16_t block_number, chunk_size; + int err; + + block_number = net_buf_simple_pull_le16(buf); + chunk_size = net_buf_simple_pull_le16(buf); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START || + srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + goto rsp; + } + + reset_timer(srv); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { + if (block_number != srv->block.number || + chunk_size != srv->state.xfer.chunk_size) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + } else { + status = BT_MESH_BLOB_SUCCESS; + } + + goto rsp; + } + + if (block_number >= block_count_get(srv)) { + status = BT_MESH_BLOB_ERR_INVALID_BLOCK_NUM; + goto rsp; + } + + if (!chunk_size || chunk_size > max_chunk_size(srv) || + (DIV_ROUND_UP((1 << srv->state.xfer.block_size_log), chunk_size) > + max_chunk_count(srv))) { + LOG_WRN("Invalid chunk size: (chunk size: %u, max: %u, block log: %u, count: %u)", + chunk_size, max_chunk_size(srv), + srv->state.xfer.block_size_log, + max_chunk_count(srv)); + status = BT_MESH_BLOB_ERR_INVALID_CHUNK_SIZE; + goto rsp; + } + + srv->block.size = blob_block_size( + srv->state.xfer.size, srv->state.xfer.block_size_log, block_number); + srv->block.number = block_number; + srv->block.chunk_count = DIV_ROUND_UP(srv->block.size, chunk_size); + srv->state.xfer.chunk_size = chunk_size; + srv->block.offset = block_number * (1UL << srv->state.xfer.block_size_log); + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE || + !atomic_test_bit(srv->state.blocks, block_number)) { + memset(srv->block.missing, 0, sizeof(srv->block.missing)); + status = BT_MESH_BLOB_SUCCESS; + goto rsp; + } + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED && srv->cb && + srv->cb->resume) { + srv->cb->resume(srv); + } + + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK); + blob_chunk_missing_set_all(&srv->block); + + LOG_DBG("%u: (%u/%u)\n\tsize: %u\n\tchunk size: %u\n\tchunk count: %u", + srv->block.number, srv->block.number + 1, block_count_get(srv), + srv->block.size, chunk_size, srv->block.chunk_count); + + if (srv->io->block_start) { + err = srv->io->block_start(srv->io, &srv->state.xfer, + &srv->block); + if (err) { + cancel(srv); + status = BT_MESH_BLOB_ERR_INTERNAL; + goto rsp; + } + } + + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + /* Wait for the client to send the first chunk */ + k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); + } + + status = BT_MESH_BLOB_SUCCESS; + +rsp: + block_status_rsp(srv, ctx, status); + + return 0; +} + +static int handle_chunk(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + struct bt_mesh_blob_chunk chunk; + size_t expected_size = 0; + uint16_t idx; + int err; + + idx = net_buf_simple_pull_le16(buf); + chunk.size = buf->len; + chunk.data = net_buf_simple_pull_mem(buf, chunk.size); + chunk.offset = idx * srv->state.xfer.chunk_size; + + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK || + idx >= srv->block.chunk_count) { + LOG_ERR("Invalid phase or index (%u %u)", srv->phase, + idx); + return -EINVAL; + } + + if (idx == srv->block.chunk_count - 1) { + expected_size = srv->block.size % srv->state.xfer.chunk_size; + } + + if (expected_size == 0) { + expected_size = srv->state.xfer.chunk_size; + } + + if (chunk.size != expected_size) { + LOG_ERR("Unexpected size: %u != %u", expected_size, chunk.size); + return -EINVAL; + } + + LOG_DBG("%u/%u (%u bytes)", idx + 1, srv->block.chunk_count, + chunk.size); + + reset_timer(srv); + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); + } + + if (!blob_chunk_missing_get(srv->block.missing, idx)) { + LOG_DBG("Duplicate chunk %u", idx); + return -EALREADY; + } + + err = srv->io->wr(srv->io, &srv->state.xfer, &srv->block, &chunk); + if (err) { + return err; + } + + blob_chunk_missing_set(srv->block.missing, idx, false); + if (missing_chunks(&srv->block)) { + return 0; + } + + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + block_report(srv); + } + + if (srv->io->block_end) { + srv->io->block_end(srv->io, &srv->state.xfer, &srv->block); + } + + atomic_clear_bit(srv->state.blocks, srv->block.number); + + if (!all_blocks_received(srv)) { + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); + store_state(srv); + return 0; + } + + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + /* By spec (section 5.2.4), the BLOB Server stops sending BLOB Partial Block Report + * messages "If the current block is the last block, then the server determines that + * the client knows the transfer is complete. For example, a higher-layer model may + * indicate that the client considers the transfer complete." + * + * We don't have any way for higher-layer model to indicate that the transfer is + * complete. Therefore we need to keep sending Partial Block Report messages until + * the client sends BLOB Transfer Get message or the Block Timer expires. + */ + return 0; + } + + end(srv); + return 0; +} + +static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + + LOG_DBG(""); + + BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_BLOB_OP_INFO_STATUS, 15); + bt_mesh_model_msg_init(&rsp, BT_MESH_BLOB_OP_INFO_STATUS); + net_buf_simple_add_u8(&rsp, BLOB_BLOCK_SIZE_LOG_MIN); + net_buf_simple_add_u8(&rsp, BLOB_BLOCK_SIZE_LOG_MAX); + net_buf_simple_add_le16(&rsp, CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX); + net_buf_simple_add_le16(&rsp, BLOB_RX_CHUNK_SIZE); + net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_BLOB_SIZE_MAX); + net_buf_simple_add_le16(&rsp, MTU_SIZE_MAX); + net_buf_simple_add_u8(&rsp, BT_MESH_BLOB_XFER_MODE_ALL); + + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + ctx->send_ttl = srv->state.ttl; + } + + (void)bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + + return 0; +} + +const struct bt_mesh_model_op _bt_mesh_blob_srv_op[] = { + { BT_MESH_BLOB_OP_XFER_GET, BT_MESH_LEN_EXACT(0), handle_xfer_get }, + { BT_MESH_BLOB_OP_XFER_START, BT_MESH_LEN_EXACT(16), handle_xfer_start }, + { BT_MESH_BLOB_OP_XFER_CANCEL, BT_MESH_LEN_EXACT(8), handle_xfer_cancel }, + { BT_MESH_BLOB_OP_BLOCK_GET, BT_MESH_LEN_EXACT(0), handle_block_get }, + { BT_MESH_BLOB_OP_BLOCK_START, BT_MESH_LEN_EXACT(4), handle_block_start }, + { BT_MESH_BLOB_OP_CHUNK, BT_MESH_LEN_MIN(2), handle_chunk }, + { BT_MESH_BLOB_OP_INFO_GET, BT_MESH_LEN_EXACT(0), handle_info_get }, + BT_MESH_MODEL_OP_END, +}; + +static int blob_srv_init(const struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + + srv->mod = mod; + srv->state.ttl = BT_MESH_TTL_DEFAULT; + srv->block.number = 0xffff; + srv->state.xfer.chunk_size = 0xffff; + k_work_init_delayable(&srv->rx_timeout, timeout); + k_work_init_delayable(&srv->pull.report, report_timeout); + + return 0; +} + +static int blob_srv_settings_set(const struct bt_mesh_model *mod, const char *name, + size_t len_rd, settings_read_cb read_cb, + void *cb_arg) +{ + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + ssize_t len; + + if (len_rd < offsetof(struct bt_mesh_blob_srv_state, blocks)) { + return -EINVAL; + } + + len = read_cb(cb_arg, &srv->state, sizeof(srv->state)); + if (len < 0) { + return len; + } + + srv->block.number = 0xffff; + srv->state.xfer.chunk_size = 0xffff; + + if (block_count_get(srv) > BT_MESH_BLOB_BLOCKS_MAX) { + LOG_WRN("Loaded block count too high (%u, max: %u)", + block_count_get(srv), BT_MESH_BLOB_BLOCKS_MAX); + return 0; + } + + /* If device restarted before it handled `XFER_START` server we restore state into + * BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START phase, so `XFER_START` can be accepted + * as it would before reboot + */ + if (srv->state.cli == BT_MESH_ADDR_UNASSIGNED) { + LOG_DBG("Transfer (id=%llu) waiting for start", srv->state.xfer.id); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START); + } else { + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_SUSPENDED); + + LOG_DBG("Recovered transfer from 0x%04x (%llu)", srv->state.cli, + srv->state.xfer.id); + } + + return 0; +} + +static int blob_srv_start(const struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + int err = -ENOTSUP; + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + return 0; + } + + if (srv->cb && srv->cb->recover) { + srv->io = NULL; + err = srv->cb->recover(srv, &srv->state.xfer, &srv->io); + if (!err && srv->io) { + err = io_open(srv); + } + } + + if (err || !srv->io) { + LOG_WRN("Abandoning transfer."); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); + srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; + srv->state.ttl = BT_MESH_TTL_DEFAULT; + erase_state(srv); + } + + return 0; +} + +static void blob_srv_reset(const struct bt_mesh_model *mod) +{ + struct bt_mesh_blob_srv *srv = mod->rt->user_data; + + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); + srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + erase_state(srv); +} + +const struct bt_mesh_model_cb _bt_mesh_blob_srv_cb = { + .init = blob_srv_init, + .settings_set = blob_srv_settings_set, + .start = blob_srv_start, + .reset = blob_srv_reset, +}; + +int bt_mesh_blob_srv_recv(struct bt_mesh_blob_srv *srv, uint64_t id, + const struct bt_mesh_blob_io *io, uint8_t ttl, + uint16_t timeout_base) +{ + if (bt_mesh_blob_srv_is_busy(srv)) { + return -EBUSY; + } + + if (!io || !io->wr) { + return -EINVAL; + } + + srv->state.xfer.id = id; + srv->state.ttl = ttl; + srv->state.timeout_base = timeout_base; + srv->io = io; + srv->block.number = 0xffff; + srv->state.xfer.chunk_size = 0xffff; + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START); + store_state(srv); + + return 0; +} + +int bt_mesh_blob_srv_cancel(struct bt_mesh_blob_srv *srv) +{ + if (!bt_mesh_blob_srv_is_busy(srv)) { + return -EALREADY; + } + + cancel(srv); + + return 0; +} + +bool bt_mesh_blob_srv_is_busy(const struct bt_mesh_blob_srv *srv) +{ + return srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE && + srv->phase != BT_MESH_BLOB_XFER_PHASE_SUSPENDED && + srv->phase != BT_MESH_BLOB_XFER_PHASE_COMPLETE; +} + +uint8_t bt_mesh_blob_srv_progress(const struct bt_mesh_blob_srv *srv) +{ + uint32_t total; + uint32_t received; + + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || + srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + return 0; + } + + total = block_count_get(srv); + + received = 0; + for (int i = 0; i < total; ++i) { + if (!atomic_test_bit(srv->state.blocks, i)) { + received++; + } + } + + return (100U * received) / total; +} From f19c2a36f2ebe41d05b40f9dffde68c46a5ba266 Mon Sep 17 00:00:00 2001 From: luoxu Date: Tue, 19 Nov 2024 17:57:17 +0800 Subject: [PATCH 138/156] feat(ble_mesh): Adapt DFU/MBT to esp-idf --- components/bt/CMakeLists.txt | 13 + components/bt/common/btc/core/btc_task.c | 4 + .../bt/common/btc/include/btc/btc_task.h | 4 + components/bt/esp_ble_mesh/Kconfig.in | 207 +- .../bt/esp_ble_mesh/api/esp_ble_mesh_defs.h | 8 +- .../bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c | 62 +- .../esp_ble_mesh/common/include/mesh/kernel.h | 2 +- .../esp_ble_mesh/common/include/mesh/timer.h | 134 +- .../esp_ble_mesh/common/include/mesh/utils.h | 106 + components/bt/esp_ble_mesh/common/timer.c | 24 +- components/bt/esp_ble_mesh/core/access.c | 33 +- components/bt/esp_ble_mesh/core/access.h | 2 + .../esp_ble_mesh/core/include/mesh/access.h | 18 +- .../bt/esp_ble_mesh/core/storage/settings.c | 41 +- .../bt/esp_ble_mesh/core/storage/settings.h | 4 + components/bt/esp_ble_mesh/core/transport.h | 1 + .../api/models/esp_ble_mesh_dfu_model_api.c | 148 ++ .../api/models/esp_ble_mesh_dfu_slot_api.c | 102 + .../api/models/esp_ble_mesh_mbt_model_api.c | 56 +- .../include/esp_ble_mesh_blob_model_api.h | 696 ++++++ .../include/esp_ble_mesh_dfu_model_api.h | 999 ++++++++ .../include/esp_ble_mesh_dfu_slot_api.h | 148 ++ .../include/esp_ble_mesh_mbt_model_api.h | 533 +++-- .../v1.1/btc/btc_ble_mesh_dfu_model.c | 414 ++++ .../v1.1/btc/btc_ble_mesh_dfu_slot.c | 79 + .../v1.1/btc/include/btc_ble_mesh_dfu_model.h | 74 + .../v1.1/btc/include/btc_ble_mesh_dfu_slot.h | 36 + .../v1.1/btc/include/btc_ble_mesh_mbt_model.h | 11 +- components/bt/esp_ble_mesh/v1.1/dfu/dfd.h | 54 +- components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c | 1757 +++++++------- .../esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h | 30 +- components/bt/esp_ble_mesh/v1.1/dfu/dfu.h | 57 +- components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c | 1892 ++++++++------- .../bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c | 127 +- .../bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c | 530 +++-- .../bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h | 22 +- components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c | 806 +++---- .../v1.1/include/mesh_v1.1/dfu/dfd.h | 131 +- .../v1.1/include/mesh_v1.1/dfu/dfd_srv.h | 373 +-- .../v1.1/include/mesh_v1.1/dfu/dfu.h | 178 +- .../v1.1/include/mesh_v1.1/dfu/dfu_cli.h | 353 +-- .../v1.1/include/mesh_v1.1/dfu/dfu_metadata.h | 72 +- .../v1.1/include/mesh_v1.1/dfu/dfu_srv.h | 300 ++- .../v1.1/include/mesh_v1.1/mbt/blob.h | 408 ++-- .../v1.1/include/mesh_v1.1/mbt/blob_cli.h | 455 ++-- .../v1.1/include/mesh_v1.1/mbt/blob_srv.h | 227 +- components/bt/esp_ble_mesh/v1.1/mbt/blob.h | 114 +- .../bt/esp_ble_mesh/v1.1/mbt/blob_cli.c | 2063 +++++++++-------- .../bt/esp_ble_mesh/v1.1/mbt/blob_srv.c | 1434 ++++++------ docs/doxygen/Doxyfile | 2 + .../esp-ble-mesh/ble-mesh-feature-list.rst | 9 + .../api-reference/bluetooth/esp-ble-mesh.rst | 9 + 52 files changed, 9633 insertions(+), 5729 deletions(-) create mode 100644 components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_slot_api.c create mode 100644 components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_blob_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_slot_api.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_slot.c create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h create mode 100644 components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_slot.h diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 1f942a3a21..7d4cc40fd3 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -47,6 +47,9 @@ set(ble_mesh_v11_include_dirs "esp_ble_mesh/v1.1/api/core/include" "esp_ble_mesh/v1.1/api/models/include" "esp_ble_mesh/v1.1/btc/include" + "esp_ble_mesh/v1.1/include" + "esp_ble_mesh/v1.1/dfu" + "esp_ble_mesh/v1.1/mbt" ) if(CONFIG_IDF_DOC_BUILD) @@ -623,9 +626,13 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_sar_model_api.c" "esp_ble_mesh/v1.1/api/core/esp_ble_mesh_srpl_model_api.c" "esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c" + "esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c" + "esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_slot_api.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_agg_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_brc_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_df_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c" + "esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_slot.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_lcd_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_mbt_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_odp_model.c" @@ -633,6 +640,12 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/v1.1/btc/btc_ble_mesh_rpr_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_sar_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_srpl_model.c" + "esp_ble_mesh/v1.1/mbt/blob_srv.c" + "esp_ble_mesh/v1.1/mbt/blob_cli.c" + "esp_ble_mesh/v1.1/dfu/dfu_cli.c" + "esp_ble_mesh/v1.1/dfu/dfu_srv.c" + "esp_ble_mesh/v1.1/dfu/dfu_slot.c" + "esp_ble_mesh/v1.1/dfu/dfu_metadata.c" "esp_ble_mesh/lib/ext.c") if(CONFIG_BLE_MESH_SAR_ENHANCEMENT) list(APPEND srcs "esp_ble_mesh/core/transport.enh.c") diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index 41c0b4368e..3bc91c9659 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -89,6 +89,7 @@ #include "btc_ble_mesh_rpr_model.h" #include "btc_ble_mesh_sar_model.h" #include "btc_ble_mesh_srpl_model.h" +#include "btc_ble_mesh_dfu_model.h" #endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #endif /* #if CONFIG_BLE_MESH */ @@ -262,6 +263,9 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = { #if CONFIG_BLE_MESH_MBT_SRV [BTC_PID_MBT_SERVER] = {btc_ble_mesh_mbt_server_call_handler, btc_ble_mesh_mbt_server_cb_handler }, #endif /* CONFIG_BLE_MESH_MBT_SRV */ +#if CONFIG_BLE_MESH_DFU_CLI + [BTC_PID_DFU_CLIENT] = {btc_ble_mesh_dfu_client_call_handler, btc_ble_mesh_dfu_client_cb_handler}, +#endif /* CONFIG_BLE_MESH_DFU_CLI */ #if CONFIG_BLE_MESH_BLE_COEX_SUPPORT || CONFIG_BLE_MESH_USE_BLE_50 [BTC_PID_BLE_MESH_BLE_COEX] = {btc_ble_mesh_ble_call_handler, btc_ble_mesh_ble_cb_handler }, #endif /* CONFIG_BLE_MESH_BLE_COEX_SUPPORT || CONFIG_BLE_MESH_USE_BLE_50 */ diff --git a/components/bt/common/btc/include/btc/btc_task.h b/components/bt/common/btc/include/btc/btc_task.h index 0436558242..e87ce59311 100644 --- a/components/bt/common/btc/include/btc/btc_task.h +++ b/components/bt/common/btc/include/btc/btc_task.h @@ -106,6 +106,10 @@ typedef enum { BTC_PID_TIME_SCENE_SERVER, BTC_PID_MBT_CLIENT, BTC_PID_MBT_SERVER, + BTC_PID_BLOB_CLIENT, + BTC_PID_BLOB_SERVER, + BTC_PID_DFU_CLIENT, + BTC_PID_DFU_SERVER, BTC_PID_BLE_MESH_BLE_COEX, #endif /* CONFIG_BLE_MESH */ #if (BLE_FEAT_ISO_EN == TRUE) diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index 3f8f0a37d7..c1beb54857 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -1636,11 +1636,13 @@ if BLE_MESH Enable support for Lighting server models. config BLE_MESH_MBT_CLI - bool "BLOB Transfer Client model" + bool "BLOB Transfer Client model(Deprecated)" depends on BLE_MESH_V11_SUPPORT default n help Enable support for BLOB Transfer Client model. + Warn: This version of the Mesh Binary Large Object Transfer Model will be deprecated, + and a new version will be released in the future. if BLE_MESH_MBT_CLI @@ -1655,11 +1657,212 @@ if BLE_MESH endif # BLE_MESH_MBT_CLI config BLE_MESH_MBT_SRV - bool "BLOB Transfer Server model" + bool "BLOB Transfer Server model(Deprecated)" depends on BLE_MESH_V11_SUPPORT default n help Enable support for BLOB Transfer Server model. + Warn: This version of the Mesh Binary Large Object Transfer Model will be deprecated, + and a new version will be released in the future. + + menu "Binary Larger Object Transfer model" + + config BLE_MESH_BLOB_SRV + bool "Support for BLOB Transfer Server model" + depends on BLE_MESH_V11_SUPPORT + help + Enable the Binary Large Object (BLOB) Transfer Server model. + + if BLE_MESH_BLOB_SRV + + config BLE_MESH_BLOB_SRV_PULL_REQ_COUNT + int "Number of chunks to request for each pull" + default 4 + range 1 16 + help + In Pull mode (Pull BLOB Transfer Mode), the BLOB Transfer Server + requests a fixed number of chunks from the Client. Use this option to + control the chunk count in the request. If the BLOB Transfer Server + is instantiated on a Low Power node, the pull request count will be + trimmed to not overflow the Friend queue. + + config BLE_MESH_BLOB_SIZE_MAX + int "Largest BLOB size in bytes" + default 524288 + range 1 3257617792 + help + The maximum object size a BLOB Transfer Server can receive. + + config BLE_MESH_BLOB_BLOCK_SIZE_MIN + int "Minimum block size" + default 4096 + range 64 1048576 # 2^6 - 2^20 + help + Minimum acceptable block size in a BLOB transfer. The transfer block + size will be some number that is a power of two, and is between block + size min and block size max. If no such number exists, a compile + time warning will be issued. + + config BLE_MESH_BLOB_BLOCK_SIZE_MAX + int "Maximum block size" + default 4096 + range BLE_MESH_BLOB_BLOCK_SIZE_MIN 1048576 + help + Maximum acceptable block size in a BLOB transfer. The transfer block + size will be some number that is a power of two, and is between block + size min and block size max. If no such number exists, a compile + time warning will be issued. + + config BLE_MESH_BLOB_REPORT_TIMEOUT + int "Partial Block Report interval in Pull mode" + default 10 + range 1 31 + help + The timer value that Pull BLOB Transfer Server uses to report missed chunks. + + config BLE_MESH_RX_BLOB_CHUNK_SIZE + depends on !BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT + int "BLOB Server chunk size" + default 8 + range 8 377 + help + Set the chunk size for the BLOB Server. + The actual maximum chunk size depends on how many segments are + possible and will be clamped to the max possible if set above. + see also: BLE_MESH_RX_SEG_MAX, + and the maximum SDU a node can receive. + + endif # BLE_MESH_BLOB_SRV + + config BLE_MESH_BLOB_CLI + bool "Support for BLOB Transfer Client model" + depends on BLE_MESH_V11_SUPPORT + help + Enable the Binary Large Object (BLOB) Transfer Client model. + + if BLE_MESH_BLOB_CLI + + config BLE_MESH_BLOB_CLI_BLOCK_RETRIES + int "Number of retries per block" + default 5 + help + Controls the number of times the client will attempt to resend missing + chunks to the BLOB receivers for every block. + + config BLE_MESH_TX_BLOB_CHUNK_SIZE + depends on !BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT + int "BLOB Client chunk size" + default 8 + range 1 377 + help + Set the chunk size for the BLOB Client. + The actual maximum chunk size depends on how many segments are + possible and will be clamped to the max possible if set above. + see also: BLE_MESH_TX_SEG_MAX, + and the maximum SDU a node can receive. + + config BLE_MESH_TX_BLOB_CHUNK_SEND_INTERVAL + int "BLOB Client chunk send interval" + default 0 + range 0 2147483647 + help + Set the interval in milliseconds in which chunks are sent during the BLOB transfer. + Note: Without a delay between each sent chunk, the network might become too busy with the + BLOB transfer for other communications to succeed. + Note: Timing restrictions, like the timeout base, should be considered or changed + accordingly when setting this interval. Otherwise, the interval might be too big for the + timeout settings and cause timeouts. + + endif # BLE_MESH_BLOB_CLI + + menu "BLOB models common configuration" + visible if BLE_MESH_BLOB_SRV || BLE_MESH_BLOB_CLI + + config BLE_MESH_BLOB_CHUNK_COUNT_MAX + int "Maximum chunk count per block" + default 256 + range 1 2992 + help + A BLOB transfer contains several blocks. Each block is made up of + several chunks. This option controls the maximum chunk count per + block. + + config BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT + bool "Align chunk size to max segmented message size" + default y + + endmenu #BLOB models common configuration + + endmenu # Binary Larger Object Transfer model + + menu "Device Firmware Update model" + + config BLE_MESH_DFU_SRV + bool "Support for Firmware Update Server model" + depends on BLE_MESH_BLOB_SRV + help + Enable the Firmware Update Server model. + + config BLE_MESH_DFU_CLI + bool "Support for Firmware Update Client model" + depends on BLE_MESH_BLOB_CLI + help + Enable the Firmware Update Client model. + + menu "Firmware Update model configuration" + visible if BLE_MESH_DFU_SRV || BLE_MESH_DFU_CLI + + config BLE_MESH_DFU_FWID_MAXLEN + int "DFU FWID max length" + default 16 + range 0 106 + help + This value defines the maximum length of an image's firmware ID. + + config BLE_MESH_DFU_METADATA_MAXLEN + int "DFU metadata max length" + default 32 + range 18 255 if BLE_MESH_DFU_METADATA + range 0 255 + help + This value defines the maximum length of an image's metadata. + + config BLE_MESH_DFU_METADATA + bool "Support for the default metadata format" + help + This option adds a set of functions that can be used to encode and decode a firmware + metadata using the format defined in the Bluetooth mesh DFU subsystem. + + config BLE_MESH_DFU_URI_MAXLEN + int "DFU URI max length" + default 32 + range 0 255 + help + This value defines the maximum length of an image's URI, not including + a string terminator. + + endmenu #Firmware Update model configuration + + config BLE_MESH_DFU_SLOTS + bool "Firmware image slot manager" + default y if BLE_MESH_DFU_CLI + help + Enable the DFU image slot manager, for managing firmware distribution slots + for the Firmware Update Client model. + + if BLE_MESH_DFU_SLOTS + + config BLE_MESH_DFU_SLOT_CNT + int "Number of firmware image slots" + default 1 + range 1 32767 + help + This value defines the number of firmware slots the DFU image slot manager + can keep simultaneously. + + endif #BLE_MESH_DFU_SLOTS + + endmenu # Device Firmware Update model endmenu #Support for BLE Mesh Client/Server models diff --git a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h index 7d4b0ed170..8b7ff38ed7 100644 --- a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h +++ b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h @@ -1982,8 +1982,12 @@ typedef union { #define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f #define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV 0x1310 #define ESP_BLE_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 -#define ESP_BLE_MESH_MODEL_ID_MBT_SRV 0x1400 -#define ESP_BLE_MESH_MODEL_ID_MBT_CLI 0x1401 +#define ESP_BLE_MESH_MODEL_ID_MBT_SRV 0x14fe +#define ESP_BLE_MESH_MODEL_ID_MBT_CLI 0x14ff +#define ESP_BLE_MESH_MODEL_ID_BLOB_SRV 0x1400 +#define ESP_BLE_MESH_MODEL_ID_BLOB_CLI 0x1401 +#define ESP_BLE_MESH_MODEL_ID_DFU_SRV 0x1402 +#define ESP_BLE_MESH_MODEL_ID_DFU_CLI 0x1403 /** * esp_ble_mesh_opcode_config_client_get_t belongs to esp_ble_mesh_opcode_t, this typedef is only diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index 72d1774d5e..babbdf5408 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -1410,6 +1410,23 @@ typedef bt_mesh_client_user_data_t bt_mesh_mbt_client_t; extern const struct bt_mesh_model_op bt_mesh_mbt_cli_op[]; extern const struct bt_mesh_model_cb bt_mesh_mbt_cli_cb; #endif /* CONFIG_BLE_MESH_MBT_CLI */ +#if CONFIG_BLE_MESH_BLOB_SRV +extern const struct bt_mesh_model_op _bt_mesh_blob_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_blob_srv_cb; +#endif /* CONFIG_BLE_MESH_BLOB_SRV */ +#if CONFIG_BLE_MESH_BLOB_CLI +typedef bt_mesh_client_user_data_t bt_mesh_blob_client_t; +extern const struct bt_mesh_model_op _bt_mesh_blob_cli_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb; +#endif /* CONFIG_BLE_MESH_BLOB_CLI */ +#if CONFIG_BLE_MESH_DFU_SRV +extern const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb; +#endif /* CONFIG_BLE_MESH_DFU_SRV */ +#if CONFIG_BLE_MESH_DFU_CLI +extern const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb; +#endif /* CONFIG_BLE_MESH_DFU_CLI */ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) { @@ -2205,9 +2222,9 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) case BLE_MESH_MODEL_ID_MBT_CLI: model->op = (esp_ble_mesh_model_op_t *)bt_mesh_mbt_cli_op; model->cb = (esp_ble_mesh_model_cbs_t *)&bt_mesh_mbt_cli_cb; - bt_mesh_mbt_client_t *cli = (bt_mesh_mbt_client_t *)model->user_data; - if (cli) { - cli->publish_status = btc_ble_mesh_mbt_client_publish_callback; + bt_mesh_mbt_client_t *mbt_cli = (bt_mesh_mbt_client_t *)model->user_data; + if (mbt_cli) { + mbt_cli->publish_status = btc_ble_mesh_mbt_client_publish_callback; } break; #endif /* CONFIG_BLE_MESH_MBT_CLI */ @@ -2220,6 +2237,43 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) } break; #endif /* CONFIG_BLE_MESH_MBT_SRV */ +#if CONFIG_BLE_MESH_BLOB_CLI + case BLE_MESH_MODEL_ID_BLOB_CLI: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_blob_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_blob_cli_cb; + bt_mesh_blob_client_t *blob_cli = (bt_mesh_blob_client_t *)model->user_data; + if (blob_cli) { + /* TBD: do we need publish callback for Blob Transfer Client model? */ + } + break; +#endif /* CONFIG_BLE_MESH_BLOB_CLI */ +#if CONFIG_BLE_MESH_BLOB_SRV + case BLE_MESH_MODEL_ID_BLOB_SRV: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_blob_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_blob_srv_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_BLOB_SRV */ +#if CONFIG_BLE_MESH_DFU_CLI + case BLE_MESH_MODEL_ID_DFU_CLI: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfu_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfu_cli_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_DFU_CLI */ +#if CONFIG_BLE_MESH_DFU_SRV + case BLE_MESH_MODEL_ID_DFU_SRV: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfu_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfu_srv_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_DFU_SRV */ default: goto set_vnd_op; } diff --git a/components/bt/esp_ble_mesh/common/include/mesh/kernel.h b/components/bt/esp_ble_mesh/common/include/mesh/kernel.h index 95624cf736..a24772a47d 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/kernel.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/kernel.h @@ -37,7 +37,7 @@ extern "C" { #endif #endif -#define BLE_MESH_ADV_TASK_STACK_SIZE 3072 +#define BLE_MESH_ADV_TASK_STACK_SIZE (3072) #define BLE_MESH_ADV_TASK_NAME "mesh_adv_task" #define BLE_MESH_ADV_TASK_PRIO (configMAX_PRIORITIES - 5) diff --git a/components/bt/esp_ble_mesh/common/include/mesh/timer.h b/components/bt/esp_ble_mesh/common/include/mesh/timer.h index e1296aa820..30b400aee4 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/timer.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/timer.h @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: 2016 Wind River Systems, Inc. - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -49,6 +49,8 @@ struct k_work; */ typedef void (*k_work_handler_t)(struct k_work *work); +typedef int32_t k_timeout_t; + struct k_work { k_work_handler_t handler; int index; @@ -141,6 +143,65 @@ struct k_work { */ #define K_FOREVER (-1) +/** + * @brief Define for delayable work type. + * + * This macro maps the Zephyr delayable work type `k_work_delayable` + * to the ESP-IDF type `k_delayed_work`. + */ +#define k_work_delayable k_delayed_work + +/** + * @brief Reschedule a delayable work item. + * + * This macro maps to `k_delayed_work_submit`, which cancels + * any existing pending submission of the work item and reschedules + * it with the new timeout delay. + * + * @param work Pointer to delayable work item. + * @param delay Timeout delay value. + * @return See implementation of `k_delayed_work_submit`. + */ +#define k_work_reschedule k_delayed_work_submit + +/** + * @brief Schedule a delayable work item. + * + * This macro maps to `k_delayed_work_submit`, + * which schedules a work item to be processed + * after the specified timeout delay. If the work + * is already pending, the new delay is applied. + * + * @param work Pointer to delayable work item. + * @param delay Timeout delay value. + * @return See implementation of `k_delayed_work_submit`. + */ +#define k_work_schedule k_delayed_work_submit + +/** + * @brief Cancel a delayable work item. + * + * This macro maps to `k_delayed_work_cancel`, + * which cancels a pending work submission + * associated with a delayable work item. + * + * @param work Pointer to delayable work item. + * @return See implementation of `k_delayed_work_cancel`. + */ +#define k_work_cancel_delayable k_delayed_work_cancel + +/** + * @brief Initialize a delayable work item. + * + * This macro maps to `k_delayed_work_init`, + * which initializes a delayable work item with + * the provided handler function. + * + * @param work Pointer to delayable work item. + * @param handler Work item handler function. + */ +#define k_work_init_delayable k_delayed_work_init + /** * @brief Get system uptime (32-bit version). * @@ -160,6 +221,27 @@ struct k_delayed_work { struct k_work work; }; +#define _K_DELAYABLE_WORK_INITIALIZER(work_handler) { \ + .work = { \ + .handler = work_handler, \ + }, \ +} + +/** + * @brief Convert a work item to its containing delayable work structure. + * + * This function uses container_of to derive the address of the containing + * k_work_delayable structure from the address of the embedded k_work structure. + * + * @param work Pointer to the embedded k_work structure within a k_work_delayable. + * @return Pointer to the containing k_work_delayable structure. + */ +static inline struct k_work_delayable * +k_work_delayable_from_work(struct k_work *work) +{ + return CONTAINER_OF(work, struct k_work_delayable, work); +} + /** * @brief Submit a delayed work item to the system workqueue. * @@ -209,6 +291,21 @@ int k_delayed_work_submit_periodic(struct k_delayed_work *work, int32_t period); */ int32_t k_delayed_work_remaining_get(struct k_delayed_work *work); +/** + * @brief Check if a delayable work item is pending execution. + * + * This function checks whether a delayable work item has been scheduled + * and is waiting to be processed. It returns true if the work item is in + * pending state (waiting for timeout expiration or being in work queue). + * + * @param dwork Pointer to delayable work item. + * @return true if work is pending, false otherwise. + */ +static inline bool k_work_delayable_is_pending(struct k_work_delayable *dwork) +{ + return k_delayed_work_remaining_get(dwork); +} + /** * @brief Submit a work item to the system workqueue. * @@ -267,10 +364,45 @@ int k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler); * @return Current uptime. */ int64_t k_uptime_get(void); +int64_t k_uptime_delta(int64_t *reftime); void bt_mesh_timer_init(void); void bt_mesh_timer_deinit(void); +/** + * @brief Initialize a statically-defined work item. + * + * This macro can be used to initialize a statically-defined workqueue work + * item, prior to its first use. For example, + * + * @code static K_WORK_DEFINE(, ); @endcode + * + * @param work Symbol name for work item object + * @param work_handler Function to invoke each time work item is processed. + */ +#define K_WORK_DEFINE(work, work_handler) \ + struct k_work work = _K_WORK_INITIALIZER(work_handler) + +/** + * @brief Initialize a statically-defined delayable work item. + * + * This macro can be used to initialize a statically-defined delayable + * work item, prior to its first use. For example, + * + * @code static K_WORK_DELAYABLE_DEFINE(, ); @endcode + * + * Note that if the runtime dependencies support initialization with + * k_work_init_delayable() using that will eliminate the initialized + * object in ROM that is produced by this macro and copied in at + * system startup. + * + * @param work Symbol name for delayable work item object + * @param work_handler Function to invoke each time work item is processed. + */ +#define K_WORK_DELAYABLE_DEFINE(work, work_handler) \ + struct k_delayed_work work \ + = _K_DELAYABLE_WORK_INITIALIZER(work_handler) + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/common/include/mesh/utils.h b/components/bt/esp_ble_mesh/common/include/mesh/utils.h index 967fed2e0c..4ef522ee32 100644 --- a/components/bt/esp_ble_mesh/common/include/mesh/utils.h +++ b/components/bt/esp_ble_mesh/common/include/mesh/utils.h @@ -15,6 +15,8 @@ #define _BLE_MESH_UTILS_H_ #include +#include +#include #include "esp_bit_defs.h" #include "mesh/types.h" #include "utils_loops.h" @@ -94,6 +96,81 @@ extern "C" { #define WB_DN(x) ROUND_DOWN(x, sizeof(void *)) #endif +/** + * @brief Whether @p ptr is an element of @p array + * + * This macro can be seen as a slightly stricter version of @ref PART_OF_ARRAY + * in that it also ensures that @p ptr is aligned to an array-element boundary + * of @p array. + * + * In C, passing a pointer as @p array causes a compile error. + * + * @param array the array in question + * @param ptr the pointer to check + * + * @return 1 if @p ptr is part of @p array, 0 otherwise + */ +#define IS_ARRAY_ELEMENT(array, ptr) \ + ((ptr) && POINTER_TO_UINT(array) <= POINTER_TO_UINT(ptr) && \ + POINTER_TO_UINT(ptr) < POINTER_TO_UINT(&(array)[ARRAY_SIZE(array)]) && \ + (POINTER_TO_UINT(ptr) - POINTER_TO_UINT(array)) % sizeof((array)[0]) == 0) + +/** + * @brief Index of @p ptr within @p array + * + * With `CONFIG_ASSERT=y`, this macro will trigger a runtime assertion + * when @p ptr does not fall into the range of @p array or when @p ptr + * is not aligned to an array-element boundary of @p array. + * + * In C, passing a pointer as @p array causes a compile error. + * + * @param array the array in question + * @param ptr pointer to an element of @p array + * + * @return the array index of @p ptr within @p array, on success + */ +#define ARRAY_INDEX(array, ptr) \ + ({ \ + __ASSERT_NO_MSG(IS_ARRAY_ELEMENT(array, ptr)); \ + (__typeof__((array)[0]) *)(ptr) - (array); \ + }) + + +/** + * @brief Divide and round up. + * + * Example: + * @code{.c} + * DIV_ROUND_UP(1, 2); // 1 + * DIV_ROUND_UP(3, 2); // 2 + * @endcode + * + * @param n Numerator. + * @param d Denominator. + * + * @return The result of @p n / @p d, rounded up. + */ +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +/** + * @brief Divide and round to the nearest integer. + * + * Example: + * @code{.c} + * DIV_ROUND_CLOSEST(5, 2); // 3 + * DIV_ROUND_CLOSEST(5, -2); // -3 + * DIV_ROUND_CLOSEST(5, 3); // 2 + * @endcode + * + * @param n Numerator. + * @param d Denominator. + * + * @return The result of @p n / @p d, rounded to the nearest integer. + */ +#define DIV_ROUND_CLOSEST(n, d) \ + ((((n) < 0) ^ ((d) < 0)) ? ((n) - ((d) / 2)) / (d) : \ + ((n) + ((d) / 2)) / (d)) + #ifndef ceiling_fraction #define ceiling_fraction(numerator, divider) \ (((numerator) + ((divider) - 1)) / (divider)) @@ -125,6 +202,21 @@ extern "C" { #define BIT(n) (1UL << (n)) #endif +/** + * @brief Set or clear a bit depending on a boolean value + * + * The argument @p var is a variable whose value is written to as a + * side effect. + * + * @param var Variable to be altered + * @param bit Bit number + * @param set if 0, clears @p bit in @p var; any other value sets @p bit + */ +#ifndef WRITE_BIT +#define WRITE_BIT(var, bit, set) \ + ((var) = (set) ? ((var) | BIT(bit)) : ((var) & ~BIT(bit))) +#endif + #ifndef BIT_MASK #define BIT_MASK(n) (BIT(n) - 1) #endif @@ -219,6 +311,20 @@ const char *bt_hex(const void *buf, size_t len); void mem_rcopy(uint8_t *dst, uint8_t const *src, uint16_t len); +/** + * @brief Checks if a value is within range. + * + * @note @p val is evaluated twice. + * + * @param val Value to be checked. + * @param min Lower bound (inclusive). + * @param max Upper bound (inclusive). + * + * @retval true If value is within range + * @retval false If the value is not within range + */ +#define IN_RANGE(val, min, max) ((val) >= (min) && (val) <= (max)) + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/common/timer.c b/components/bt/esp_ble_mesh/common/timer.c index 0d65bd3a10..248480e70b 100644 --- a/components/bt/esp_ble_mesh/common/timer.c +++ b/components/bt/esp_ble_mesh/common/timer.c @@ -1,7 +1,7 @@ /* * SPDX-FileCopyrightText: 2016 Intel Corporation * SPDX-FileCopyrightText: 2016 Wind River Systems, Inc. - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -43,6 +43,28 @@ uint32_t k_uptime_get_32(void) return (uint32_t)(esp_timer_get_time() / 1000); } +/** + * @brief Get elapsed time. + * + * This routine computes the elapsed time between the current system uptime + * and an earlier reference time, in milliseconds. + * + * @param reftime Pointer to a reference time, which is updated to the current + * uptime upon return. + * + * @return Elapsed time. + */ +int64_t k_uptime_delta(int64_t *reftime) +{ + int64_t uptime, delta; + + uptime = k_uptime_get(); + delta = uptime - *reftime; + *reftime = uptime; + + return delta; +} + void bt_mesh_timer_init(void) { bm_alarm_hash_map = hash_map_new(BLE_MESH_ALARM_HASH_MAP_SIZE, diff --git a/components/bt/esp_ble_mesh/core/access.c b/components/bt/esp_ble_mesh/core/access.c index 86d80139d0..73363c2f99 100644 --- a/components/bt/esp_ble_mesh/core/access.c +++ b/components/bt/esp_ble_mesh/core/access.c @@ -37,7 +37,7 @@ extern const struct bt_mesh_comp *comp_0; static uint16_t dev_primary_addr; -static int model_send(struct bt_mesh_model *model, +static int model_send(const struct bt_mesh_model *model, struct bt_mesh_net_tx *tx, bool implicit_bind, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data); @@ -300,7 +300,7 @@ static void mod_publish(struct k_work *work) } } -struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod) +struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod) { return &comp_0->elem[mod->elem_idx]; } @@ -548,12 +548,31 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) return NULL; } +bool bt_mesh_has_addr(uint16_t addr) +{ + uint16_t index; + + if (BLE_MESH_ADDR_IS_UNICAST(addr)) { + return bt_mesh_elem_find(addr) != NULL; + } + + for (index = 0; index < comp_0->elem_count; index++) { + struct bt_mesh_elem *elem = &comp_0->elem[index]; + + if (bt_mesh_elem_find_group(elem, addr)) { + return true; + } + } + + return false; +} + uint8_t bt_mesh_elem_count(void) { return comp_0->elem_count; } -static bool model_has_key(struct bt_mesh_model *mod, uint16_t key) +static bool model_has_key(const struct bt_mesh_model *mod, uint16_t key) { int i; @@ -635,7 +654,7 @@ static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_bu if (pull_buf) { *opcode = net_buf_simple_pull_u8(buf) << 16; /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 + * little-endian in the mesh spec and using BLE_MESH_MODEL_OP_3 * will declare the opcode in this way. */ *opcode |= net_buf_simple_pull_le16(buf); @@ -793,7 +812,7 @@ void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) case 3: net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 + * little-endian in the mesh spec and using BLE_MESH_MODEL_OP_3 * will declare the opcode in this way. */ net_buf_simple_add_le16(msg, opcode & 0xffff); @@ -951,7 +970,7 @@ void bt_mesh_choose_better_security_cred(struct bt_mesh_net_tx *tx) } #endif /* !CONFIG_BLE_MESH_V11_SUPPORT */ -static int model_send(struct bt_mesh_model *model, +static int model_send(const struct bt_mesh_model *model, struct bt_mesh_net_tx *tx, bool implicit_bind, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data) @@ -1041,7 +1060,7 @@ int bt_mesh_model_send_implicit(struct bt_mesh_model *model, return model_send(model, &tx, implicit_bind, msg, cb, cb_data); } -int bt_mesh_model_send(struct bt_mesh_model *model, +int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, void *cb_data) diff --git a/components/bt/esp_ble_mesh/core/access.h b/components/bt/esp_ble_mesh/core/access.h index 672a9a2c7b..669cff788c 100644 --- a/components/bt/esp_ble_mesh/core/access.h +++ b/components/bt/esp_ble_mesh/core/access.h @@ -29,6 +29,8 @@ uint8_t bt_mesh_elem_count(void); /* Find local element based on unicast or group address */ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); +bool bt_mesh_has_addr(uint16_t addr); + uint16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, uint16_t addr); int bt_mesh_get_opcode(struct net_buf_simple *buf, diff --git a/components/bt/esp_ble_mesh/core/include/mesh/access.h b/components/bt/esp_ble_mesh/core/include/mesh/access.h index 38be1a6cac..6aa64080bd 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/access.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/access.h @@ -14,6 +14,7 @@ #include "mesh/config.h" #include "mesh/buf.h" #include "mesh/timer.h" +#include "sys/types.h" /** * @brief Bluetooth Mesh Access Layer @@ -151,8 +152,15 @@ struct bt_mesh_elem { #define BLE_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f #define BLE_MESH_MODEL_ID_LIGHT_LC_SETUP_SRV 0x1310 #define BLE_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 -#define BLE_MESH_MODEL_ID_MBT_SRV 0x1400 -#define BLE_MESH_MODEL_ID_MBT_CLI 0x1401 +#define BLE_MESH_MODEL_ID_BLOB_SRV 0x1400 +#define BLE_MESH_MODEL_ID_BLOB_CLI 0x1401 +#define BLE_MESH_MODEL_ID_DFU_SRV 0x1402 +#define BLE_MESH_MODEL_ID_DFU_CLI 0x1403 +#define BLE_MESH_MODEL_ID_DFD_SRV 0x1404 +#define BLE_MESH_MODEL_ID_DFD_CLI 0x1405 + +#define BLE_MESH_MODEL_ID_MBT_SRV BLE_MESH_MODEL_ID_BLOB_SRV +#define BLE_MESH_MODEL_ID_MBT_CLI BLE_MESH_MODEL_ID_BLOB_CLI typedef struct { uint32_t adv_itvl; @@ -520,6 +528,8 @@ struct bt_mesh_model_pub { .update = _update, \ } +typedef ssize_t (*settings_read_cb)(void *cb_arg, void *data, size_t len); + /** Model callback functions. */ struct bt_mesh_model_cb { /** @brief Model init callback. @@ -613,7 +623,7 @@ void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode); * * @return 0 on success, or (negative) error code on failure. */ -int bt_mesh_model_send(struct bt_mesh_model *model, +int bt_mesh_model_send(const struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *msg, const struct bt_mesh_send_cb *cb, @@ -642,7 +652,7 @@ int bt_mesh_model_publish(struct bt_mesh_model *model); * * @return Pointer to the element that the given model belongs to. */ -struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod); +struct bt_mesh_elem *bt_mesh_model_elem(const struct bt_mesh_model *mod); /** @brief Find a SIG model. * diff --git a/components/bt/esp_ble_mesh/core/storage/settings.c b/components/bt/esp_ble_mesh/core/storage/settings.c index 40cf117f2e..437c3d9b07 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings.c +++ b/components/bt/esp_ble_mesh/core/storage/settings.c @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: 2018 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -45,10 +45,12 @@ * key: "mesh/s/xxxx/b" -> write/read to set/get SIG MODEL Bind AppKey List * key: "mesh/s/xxxx/s" -> write/read to set/get SIG MODEL Subscription List * key: "mesh/s/xxxx/p" -> write/read to set/get SIG MODEL Publication + * key: "mesh/s/xxxx/d" -> write/read to set/get SIG MODEL Data * key: "mesh/vnd" -> write/read to set/get all VENDOR MODEL model_keys. * key: "mesh/v/xxxx/b" -> write/read to set/get VENDOR MODEL Bind AppKey List * key: "mesh/v/xxxx/s" -> write/read to set/get VENDOR MODEL Subscription List * key: "mesh/v/xxxx/p" -> write/read to set/get VENDOR MODEL Publication + * key: "mesh/v/xxxx/d" -> write/read to set/get VENDOR MODEL Data * key: "mesh/vaddr" -> write/read to set/get all virtual addresses * key: "mesh/va/xxxx" -> write/read to set/get the "xxxx" virtual address * key: "mesh/dkca" -> write/read to set/get Device Key Candidate @@ -2731,3 +2733,40 @@ void bt_mesh_settings_reset(bool erase) } #endif /* CONFIG_BLE_MESH_SETTINGS */ + +#define SETTINGS_MAX_DIR_DEPTH 8 + +int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, + const char *name, const void *data, + size_t data_len) +{ + int err = 0; + + char path[30] = {'\0'}; + uint16_t model_key = 0U; + + model_key = BLE_MESH_GET_MODEL_KEY(mod->elem_idx, mod->model_idx); + sprintf(path, "mesh/%s/%04x/d", vnd ? "v" : "s", model_key); + if (name) { + strcat(path, "/"); + strncat(path, name, SETTINGS_MAX_DIR_DEPTH); + } + + if (data_len) { + err = bt_mesh_save_core_settings(path, data, data_len); + if (err) { + BT_ERR("Failed to store %s", path); + return err; + } + + err = bt_mesh_add_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); + if (err) { + BT_ERR("Failed to add model data to %s, model_key 0x%04x", + vnd ? "mesh/vnd" : "mesh/sig", model_key); + } + } else { + bt_mesh_erase_core_settings(path); + bt_mesh_remove_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); + } + return err; +} diff --git a/components/bt/esp_ble_mesh/core/storage/settings.h b/components/bt/esp_ble_mesh/core/storage/settings.h index 255eb2c343..7ad8cf3cd6 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings.h +++ b/components/bt/esp_ble_mesh/core/storage/settings.h @@ -35,6 +35,10 @@ void bt_mesh_store_mod_sub(struct bt_mesh_model *mod); void bt_mesh_store_mod_pub(struct bt_mesh_model *mod); void bt_mesh_store_label(void); +int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, + const char *name, const void *data, + size_t data_len); + void bt_mesh_clear_role(void); void bt_mesh_clear_net(void); void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub); diff --git a/components/bt/esp_ble_mesh/core/transport.h b/components/bt/esp_ble_mesh/core/transport.h index d8d32f81b6..e4487fa9fd 100644 --- a/components/bt/esp_ble_mesh/core/transport.h +++ b/components/bt/esp_ble_mesh/core/transport.h @@ -11,6 +11,7 @@ #define _TRANSPORT_H_ #include "net.h" +#include "access.h" #ifdef __cplusplus extern "C" { diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c new file mode 100644 index 0000000000..feb082cd66 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "btc/btc_manage.h" + +#include "btc_ble_mesh_dfu_model.h" +#include "esp_ble_mesh_dfu_model_api.h" + +#if CONFIG_BLE_MESH_DFU_CLI + +static bool is_get_param_needed(esp_ble_mesh_opcode_t opcode) +{ + switch (opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + case ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK: + case ESP_BLE_MESH_DFU_OP_UPDATE_START: + return true; + default: + return false; + } +} + +esp_err_t esp_ble_mesh_dfu_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfu_client_get_t *get) +{ + btc_ble_mesh_dfu_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (is_get_param_needed(params->opcode) && get == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DFU_CLIENT; + msg.act = BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE; + + arg.dfu_get.params = params; + arg.dfu_get.get = get; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfu_client_args_t), + btc_ble_mesh_dfu_client_arg_deep_copy, + btc_ble_mesh_dfu_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_dfu_cli_img_send(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_blob_cli_inputs_t *inputs, + esp_ble_mesh_blob_io_t *io, + esp_ble_mesh_dfu_cli_xfer_t *xfer) +{ + btc_ble_mesh_dfu_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (cli == NULL || inputs == NULL || + io == NULL || xfer == NULL) { + return ESP_ERR_INVALID_ARG; + } + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DFU_CLIENT; + msg.act = BTC_BLE_MESH_ACT_DFU_CLIENT_IMG_SEND; + + arg.send_arg.cli = cli; + arg.send_arg.inputs = inputs; + arg.send_arg.io = io; + arg.send_arg.xfer = xfer; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfu_client_args_t), + NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +uint8_t esp_ble_mesh_dfu_cli_progress(esp_ble_mesh_dfu_cli_t *cli) +{ + if (!cli) { + return 0; + } + return btc_ble_mesh_dfu_cli_progress(cli); +} + +esp_err_t esp_ble_mesh_register_dfu_client_callback(esp_ble_mesh_dfu_client_cb_t callback) +{ + return (btc_profile_cb_set(BTC_PID_DFU_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV +void esp_ble_mesh_dfu_srv_verified(esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return; + } + + btc_ble_mesh_dfu_srv_verified(srv); +} + +void esp_ble_mesh_dfu_srv_rejected(esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return; + } + + btc_ble_mesh_dfu_srv_rejected(srv); +} + +void esp_ble_mesh_dfu_srv_cancel(esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return; + } + + btc_ble_mesh_dfu_srv_cancel(srv); +} + +void esp_ble_mesh_dfu_srv_applied(esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return; + } + + btc_ble_mesh_dfu_srv_applied(srv); +} + +bool esp_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return false; + } + + return btc_ble_mesh_dfu_srv_is_busy(srv); +} + +uint8_t esp_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv) +{ + if (!srv) { + return 0; + } + + return btc_ble_mesh_dfu_srv_progress(srv); +} +#endif /* CONFIG_BLE_MESH_DFU_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_slot_api.c b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_slot_api.c new file mode 100644 index 0000000000..8cc17d28fa --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_slot_api.c @@ -0,0 +1,102 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "esp_ble_mesh_dfu_slot_api.h" +#include "btc_ble_mesh_dfu_slot.h" + +int esp_ble_mesh_dfu_slot_count(void) +{ + return btc_ble_mesh_dfu_slot_count(); +} + +esp_ble_mesh_dfu_slot_t *esp_ble_mesh_dfu_slot_reserve(void) +{ + return btc_ble_mesh_dfu_slot_reserve(); +} + +int esp_ble_mesh_dfu_slot_info_set(esp_ble_mesh_dfu_slot_t *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len) +{ + if (!dfu_slot || !metadata || + metadata_len == 0 || + metadata_len > CONFIG_BLE_MESH_DFU_METADATA_MAXLEN) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_info_set(dfu_slot, size, + metadata, metadata_len); +} + +int esp_ble_mesh_dfu_slot_fwid_set(esp_ble_mesh_dfu_slot_t *dfu_slot, + const uint8_t *fwid, size_t fwid_len) +{ + if (!dfu_slot || !fwid || fwid_len == 0 || + fwid_len > CONFIG_BLE_MESH_DFU_FWID_MAXLEN) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_fwid_set(dfu_slot, fwid, + fwid_len); +} + +int esp_ble_mesh_dfu_slot_commit(esp_ble_mesh_dfu_slot_t *dfu_slot) +{ + if (!dfu_slot) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_commit(dfu_slot); +} + +void esp_ble_mesh_dfu_slot_release(const esp_ble_mesh_dfu_slot_t *dfu_slot) +{ + if (!dfu_slot) { + return; + } + + btc_ble_mesh_dfu_slot_release(dfu_slot); +} + +int esp_ble_mesh_dfu_slot_del(const esp_ble_mesh_dfu_slot_t *slot) +{ + if (!slot) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_del(slot); +} + +void esp_ble_mesh_dfu_slot_del_all(void) +{ + btc_ble_mesh_dfu_slot_del_all(); +} + +const esp_ble_mesh_dfu_slot_t *esp_ble_mesh_dfu_slot_at(uint16_t img_idx) +{ + return btc_ble_mesh_dfu_slot_at(img_idx); +} + +int esp_ble_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, esp_ble_mesh_dfu_slot_t **slot) +{ + if (!fwid || fwid_len == 0 || + fwid_len > CONFIG_BLE_MESH_DFU_FWID_MAXLEN || + !slot || !*slot) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_get(fwid, fwid_len, slot); +} + +int esp_ble_mesh_dfu_slot_img_idx_get(const esp_ble_mesh_dfu_slot_t *slot) +{ + if (!slot) { + return ESP_ERR_INVALID_ARG; + } + + return btc_ble_mesh_dfu_slot_img_idx_get(slot); +} diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c index e5aed197ae..70763ba2ec 100644 --- a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c +++ b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_mbt_model_api.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,20 +20,20 @@ extern int bt_mesh_get_transfer_progress(void *model, uint16_t unicast_addr, uint8_t *block_percent, uint8_t *chunk_percent); extern int bt_mesh_get_blob_reception_progress(void *model, uint8_t *reception_progress); -esp_err_t esp_ble_mesh_register_mbt_client_callback(esp_ble_mesh_mbt_client_cb_t callback) +esp_err_t esp_ble_mesh_register_mbt_client_callback(esp_ble_mesh_mbt_client_cb_t callback) __attribute__((deprecated)) { ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); return (btc_profile_cb_set(BTC_PID_MBT_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input) +esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; if (input == NULL || input->model == NULL || - (input->unicast_addr_count && input->unicast_addr == NULL)) { + (input->unicast_addr_count && input->unicast_addr == NULL)) { return ESP_ERR_INVALID_ARG; } @@ -51,14 +51,14 @@ esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_ca == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input) +esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; if (input == NULL || input->model == NULL || - (input->unicast_addr_count && input->unicast_addr == NULL) || - input->blob_data == NULL) { + (input->unicast_addr_count && input->unicast_addr == NULL) || + input->blob_data == NULL) { return ESP_ERR_INVALID_ARG; } @@ -76,7 +76,7 @@ esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *in == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input) +esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -97,7 +97,7 @@ esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input) +esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -118,7 +118,7 @@ esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input) +esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -139,13 +139,13 @@ esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_ == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input) +esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; if (input == NULL || input->model == NULL || - (input->unicast_addr_count && input->unicast_addr == NULL)) { + (input->unicast_addr_count && input->unicast_addr == NULL)) { return ESP_ERR_INVALID_ARG; } @@ -163,13 +163,13 @@ esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determi == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input) +esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; if (input == NULL || input->model == NULL || - (input->unicast_addr_count && input->unicast_addr == NULL)) { + (input->unicast_addr_count && input->unicast_addr == NULL)) { return ESP_ERR_INVALID_ARG; } @@ -188,13 +188,13 @@ esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t } const esp_ble_mesh_blob_receiver_t *esp_ble_mesh_mbt_client_get_blob_receiver(esp_ble_mesh_model_t *model, - uint16_t unicast_addr) + uint16_t unicast_addr) __attribute__((deprecated)) { return (const esp_ble_mesh_blob_receiver_t *)bt_mesh_get_blob_receiver((struct bt_mesh_model *)model, unicast_addr); } -const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model) +const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model) __attribute__((deprecated)) { return (const esp_ble_mesh_blob_receiver_t **)bt_mesh_get_active_blob_receiver((struct bt_mesh_model *)model); } @@ -202,14 +202,14 @@ const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_rec esp_err_t esp_ble_mesh_mbt_client_get_transfer_progress(esp_ble_mesh_model_t *model, uint16_t unicast_addr, uint8_t *block_percent, - uint8_t *chunk_percent) + uint8_t *chunk_percent) __attribute__((deprecated)) { return (bt_mesh_get_transfer_progress((struct bt_mesh_model *)model, unicast_addr, block_percent, chunk_percent) == 0 ? ESP_OK : ESP_FAIL); } esp_err_t esp_ble_mesh_mbt_client_set_transfer_ttl(esp_ble_mesh_model_t *model, - uint8_t transfer_ttl) + uint8_t transfer_ttl) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -231,7 +231,7 @@ esp_err_t esp_ble_mesh_mbt_client_set_transfer_ttl(esp_ble_mesh_model_t *model, == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model) +esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -253,7 +253,7 @@ esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model } esp_err_t esp_ble_mesh_mbt_client_set_app_idx(esp_ble_mesh_model_t *model, - uint16_t app_idx) + uint16_t app_idx) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -275,7 +275,7 @@ esp_err_t esp_ble_mesh_mbt_client_set_app_idx(esp_ble_mesh_model_t *model, == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model) +esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -297,7 +297,7 @@ esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model) } esp_err_t esp_ble_mesh_mbt_client_set_multicast_addr(esp_ble_mesh_model_t *model, - uint16_t multicast_addr) + uint16_t multicast_addr) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -319,7 +319,7 @@ esp_err_t esp_ble_mesh_mbt_client_set_multicast_addr(esp_ble_mesh_model_t *model == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model) +esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model) __attribute__((deprecated)) { btc_ble_mesh_mbt_client_args_t arg = {0}; btc_msg_t msg = {0}; @@ -342,14 +342,14 @@ esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *mod #endif /* CONFIG_BLE_MESH_MBT_CLI */ #if CONFIG_BLE_MESH_MBT_SRV -esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback) +esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback) __attribute__((deprecated)) { ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); return (btc_profile_cb_set(BTC_PID_MBT_SERVER, callback) == 0 ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input) +esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_server_args_t arg = {0}; btc_msg_t msg = {0}; @@ -370,7 +370,7 @@ esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initializ == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input) +esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_server_args_t arg = {0}; btc_msg_t msg = {0}; @@ -391,7 +391,7 @@ esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_r == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } -esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input) +esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input) __attribute__((deprecated)) { btc_ble_mesh_mbt_server_args_t arg = {0}; btc_msg_t msg = {0}; @@ -413,7 +413,7 @@ esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_ca } esp_err_t esp_ble_mesh_mbt_server_get_blob_reception_progress(esp_ble_mesh_model_t *model, - uint8_t *reception_progress) + uint8_t *reception_progress) __attribute__((deprecated)) { return (bt_mesh_get_blob_reception_progress((struct bt_mesh_model *)model, reception_progress) == 0 ? ESP_OK : ESP_FAIL); diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_blob_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_blob_model_api.h new file mode 100644 index 0000000000..165450ed56 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_blob_model_api.h @@ -0,0 +1,696 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_BLOB_MODEL_API_H_ +#define _ESP_BLE_MESH_BLOB_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_blob_model_api.h" + +#if CONFIG_BLE_MESH_BLOB_CLI || CONFIG_BLE_MESH_BLOB_SRV +#ifndef _BLE_MESH_BLOB_DEPRECATE_WARN +#define _BLE_MESH_BLOB_DEPRECATE_WARN +#warning Please note: All APIs published in this document are in Preview version and may undergo significant changes in the future. +#endif +#endif /* CONFIG_BLE_MESH_BLOB_CLI || CONFIG_BLE_MESH_BLOB_SRV */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_BLOB_ID_SIZE 8 + +/** @def ESP_BLE_MESH_MODEL_BLOB_CLI + * + * @brief Define a new BLOB Transfer Client model. + * + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Client model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New BLOB Transfer Client model instance. + */ +#define ESP_BLE_MESH_MODEL_BLOB_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_BLOB_CLI, \ + NULL, cli_pub, cli_data) + +/** @def ESP_BLE_MESH_MODEL_BLOB_SRV + * + * @brief Define a new BLOB Transfer Server model. + * + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Server model. + * + * @param srv_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param srv_data Pointer to the unique struct esp_ble_mesh_blob_trans_srv_t. + * + * @return New BLOB Transfer Server model instance. + */ +#define ESP_BLE_MESH_MODEL_BLOB_SRV(srv_pub, srv_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_BLOB_SRV, \ + NULL, srv_pub, srv_data) + + +/** BLOB stream. */ +typedef struct esp_ble_mesh_blob_io esp_ble_mesh_blob_io_t; + +/** @brief BLOB Transfer Server instance. */ +typedef struct esp_ble_mesh_blob_srv esp_ble_mesh_blob_srv_t; + +/** @brief BLOB Transfer Server model event handlers. */ +typedef struct esp_ble_mesh_blob_srv_cb esp_ble_mesh_blob_srv_cb_t; + +/** Target node's Pull mode (Pull BLOB Transfer Mode) context used + * while sending chunks to the Target node. + */ +typedef struct esp_ble_mesh_blob_target_pull esp_ble_mesh_blob_target_pull_t; + +/** BLOB Transfer Client Target node. */ +typedef struct esp_ble_mesh_blob_target esp_ble_mesh_blob_target_t; + +/** BLOB transfer information. */ +typedef struct esp_ble_mesh_blob_xfer_info esp_ble_mesh_blob_xfer_info_t; + +/** BLOB Transfer Client transfer inputs. */ +typedef struct esp_ble_mesh_blob_cli_inputs esp_ble_mesh_blob_cli_inputs_t; + +/** Transfer capabilities of a Target node. */ +typedef struct esp_ble_mesh_blob_cli_caps esp_ble_mesh_blob_cli_caps_t; + +/** + * @brief BLOB Transfer Client model instance. + * @note Preview version, the contents of this struct may change in the future. + */ +typedef struct esp_ble_mesh_blob_cli esp_ble_mesh_blob_cli_t; + +/** Event handler callbacks for the BLOB Transfer Client model. */ +typedef struct esp_ble_mesh_blob_cli_cb esp_ble_mesh_blob_cli_cb_t; + +/** BLOB transfer. */ +typedef struct esp_ble_mesh_blob_xfer esp_ble_mesh_blob_xfer_t; + +/** BLOB transfer data block. */ +typedef struct esp_ble_mesh_blob_block esp_ble_mesh_blob_block_t; + +/** BLOB data chunk. */ +typedef struct esp_ble_mesh_blob_chunk esp_ble_mesh_blob_chunk_t; + +/** Transfer phase. */ +typedef enum esp_ble_mesh_blob_xfer_phase { + ESP_BLE_MESH_BLOB_XFER_PHASE_INACTIVE, /*!< The BLOB Transfer Server is awaiting configuration. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_WAITING_FOR_START, /*!< The BLOB Transfer Server is ready to receive a BLOB transfer. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK, /*!< The BLOB Transfer Server is waiting for the next block of data. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK, /*!< The BLOB Transfer Server is waiting for the next chunk of data. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_COMPLETE, /*!< The BLOB was transferred successfully. */ + ESP_BLE_MESH_BLOB_XFER_PHASE_SUSPENDED, /*!< The BLOB transfer is paused. */ +} esp_ble_mesh_blob_xfer_phase_t; + +/** BLOB transfer mode. */ +typedef enum esp_ble_mesh_blob_xfer_mode { + ESP_BLE_MESH_BLOB_XFER_MODE_NONE, /*!< No valid transfer mode. */ + ESP_BLE_MESH_BLOB_XFER_MODE_PUSH, /*!< Push mode (Push BLOB Transfer Mode). */ + ESP_BLE_MESH_BLOB_XFER_MODE_PULL, /*!< Pull mode (Pull BLOB Transfer Mode). */ + ESP_BLE_MESH_BLOB_XFER_MODE_ALL, /*!< Both modes are valid. */ +} esp_ble_mesh_blob_xfer_mode_t; + +/** BLOB model status codes. */ +typedef enum esp_ble_mesh_blob_status { + /** The message was processed successfully. */ + ESP_BLE_MESH_BLOB_SUCCESS, + /** The Block Number field value is not within the range of blocks being + * transferred. + */ + ESP_BLE_MESH_BLOB_ERR_INVALID_BLOCK_NUM, + /** The block size is smaller than the size indicated by the Min Block + * Size Log state or is larger than the size indicated by the Max Block + * Size Log state. + */ + ESP_BLE_MESH_BLOB_ERR_INVALID_BLOCK_SIZE, + /** The chunk size exceeds the size indicated by the Max Chunk Size + * state, or the number of chunks exceeds the number specified by the + * Max Total Chunks state. + */ + ESP_BLE_MESH_BLOB_ERR_INVALID_CHUNK_SIZE, + /** The operation cannot be performed while the server is in the current + * phase. + */ + ESP_BLE_MESH_BLOB_ERR_WRONG_PHASE, + /** A parameter value in the message cannot be accepted. */ + ESP_BLE_MESH_BLOB_ERR_INVALID_PARAM, + /** The message contains a BLOB ID value that is not expected. */ + ESP_BLE_MESH_BLOB_ERR_WRONG_BLOB_ID, + /** There is not enough space available in memory to receive the BLOB. + */ + ESP_BLE_MESH_BLOB_ERR_BLOB_TOO_LARGE, + /** The transfer mode is not supported by the BLOB Transfer Server + * model. + */ + ESP_BLE_MESH_BLOB_ERR_UNSUPPORTED_MODE, + /** An internal error occurred on the node. */ + ESP_BLE_MESH_BLOB_ERR_INTERNAL, + /** The requested information cannot be provided while the server is in + * the current phase. + */ + ESP_BLE_MESH_BLOB_ERR_INFO_UNAVAILABLE, +} esp_ble_mesh_blob_status_t; + +/** BLOB Transfer Client state. */ +typedef enum esp_ble_mesh_blob_cli_state { + ESP_BLE_MESH_BLOB_CLI_STATE_NONE, /*!< No transfer is active. */ + ESP_BLE_MESH_BLOB_CLI_STATE_CAPS_GET, /*!< Retrieving transfer capabilities. */ + ESP_BLE_MESH_BLOB_CLI_STATE_START, /*!< Sending transfer start. */ + ESP_BLE_MESH_BLOB_CLI_STATE_BLOCK_START, /*!< Sending block start. */ + ESP_BLE_MESH_BLOB_CLI_STATE_BLOCK_SEND, /*!< Sending block chunks. */ + ESP_BLE_MESH_BLOB_CLI_STATE_BLOCK_CHECK, /*!< Checking block status. */ + ESP_BLE_MESH_BLOB_CLI_STATE_XFER_CHECK, /*!< Checking transfer status. */ + ESP_BLE_MESH_BLOB_CLI_STATE_CANCEL, /*!< Cancelling transfer. */ + ESP_BLE_MESH_BLOB_CLI_STATE_SUSPENDED, /*!< Transfer is suspended. */ + ESP_BLE_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET, /*!< Checking transfer progress. */ +} esp_ble_mesh_blob_cli_state_t; + +/** BLOB stream interaction mode. */ +typedef enum esp_ble_mesh_blob_io_mode { + ESP_BLE_MESH_BLOB_READ, /*!< Read data from the stream. */ + ESP_BLE_MESH_BLOB_WRITE, /*!< Write data to the stream. */ +} esp_ble_mesh_blob_io_mode_t; + +/** BLOB transfer. */ +struct esp_ble_mesh_blob_xfer { + uint64_t id; /*!< BLOB ID. */ + size_t size; /*!< Total BLOB size in bytes. */ + esp_ble_mesh_blob_xfer_mode_t mode; /*!< BLOB transfer mode. */ + uint8_t block_size_log; /*!< Logarithmic representation of the block size. */ + uint16_t chunk_size; /*!< Base chunk size. May be smaller for the last chunk. */ +}; + +/** BLOB transfer data block. */ +struct esp_ble_mesh_blob_block { + size_t size; /*!< Block size in bytes */ + off_t offset; /*!< Offset in bytes from the start of the BLOB. */ + uint16_t number; /*!< Block number */ + uint16_t chunk_count; /*!< Number of chunks in block. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX, + 8)]; /*!< Bitmap of missing chunks. */ +}; + +/** BLOB data chunk. */ +struct esp_ble_mesh_blob_chunk { + off_t offset; /*!< Offset of the chunk data from the start of the block. */ + size_t size; /*!< Chunk data size. */ + uint8_t *data; /*!< Chunk data. */ +}; + +/** BLOB stream. */ +struct esp_ble_mesh_blob_io { + /** @brief Open callback. + * + * Called when the reader is opened for reading. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param mode Direction of the stream (read/write). + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*open)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + esp_ble_mesh_blob_io_mode_t mode); + + /** @brief Close callback. + * + * Called when the reader is closed. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + */ + void (*close)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer); + + /** @brief Block start callback. + * + * Called when a new block is opened for sending. Each block is only + * sent once, and are always sent in increasing order. The data chunks + * inside a single block may be requested out of order and multiple + * times. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that was started. + */ + int (*block_start)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + const esp_ble_mesh_blob_block_t *block); + + /** @brief Block end callback. + * + * Called when the current block has been transmitted in full. + * No data from this block will be requested again, and the application + * data associated with this block may be discarded. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that finished sending. + */ + void (*block_end)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + const esp_ble_mesh_blob_block_t *block); + + /** @brief Chunk data write callback. + * + * Used by the BLOB Transfer Server on incoming data. + * + * Each block is divided into chunks of data. This callback is called + * when a new chunk of data is received. Chunks may be received in + * any order within their block. + * + * If the callback returns successfully, this chunk will be marked as + * received, and will not be received again unless the block is + * restarted due to a transfer suspension. If the callback returns a + * non-zero value, the chunk remains unreceived, and the BLOB Transfer + * Client will attempt to resend it later. + * + * Note that the Client will only perform a limited number of attempts + * at delivering a chunk before dropping a Target node from the transfer. + * The number of retries performed by the Client is implementation + * specific. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Received chunk. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*write)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + const esp_ble_mesh_blob_block_t *block, + const esp_ble_mesh_blob_chunk_t *chunk); + + /** @brief Chunk data read callback. + * + * Used by the BLOB Transfer Client to fetch outgoing data. + * + * The Client calls the chunk data request callback to populate a chunk + * message going out to the Target nodes. The data request callback + * may be called out of order and multiple times for each offset, and + * cannot be used as an indication of progress. + * + * Returning a non-zero status code on the chunk data request callback + * results in termination of the transfer. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Chunk to get the data of. The buffer pointer to by the + * @c data member should be filled by the callback. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*read)(const esp_ble_mesh_blob_io_t *io, + const esp_ble_mesh_blob_xfer_t *xfer, + const esp_ble_mesh_blob_block_t *block, + const esp_ble_mesh_blob_chunk_t *chunk); +}; + +/** @brief BLOB Transfer Server model event handlers. + * + * All callbacks are optional. + */ +struct esp_ble_mesh_blob_srv_cb { + /** @brief Transfer start callback. + * + * Called when the transfer has started with the prepared BLOB ID. + * + * @param srv BLOB Transfer Server instance. + * @param ctx Message context for the incoming start message. The + * entire transfer will be sent from the same source + * address. + * @param xfer Transfer parameters. + * + * @return 0 on success, or (negative) error code to reject the + * transfer. + */ + int (*start)(esp_ble_mesh_blob_srv_t *srv, esp_ble_mesh_msg_ctx_t *ctx, + esp_ble_mesh_blob_xfer_t *xfer); + + /** @brief Transfer end callback. + * + * Called when the transfer ends, either because it was cancelled, or + * because it finished successfully. A new transfer may be prepared. + * + * @note The transfer may end before it's started if the start + * parameters are invalid. + * + * @param srv BLOB Transfer Server instance. + * @param id BLOB ID of the cancelled transfer. + * @param success Whether the transfer was successful. + */ + void (*end)(esp_ble_mesh_blob_srv_t *srv, uint64_t id, bool success); + + /** @brief Transfer suspended callback. + * + * Called if the Server timed out while waiting for a transfer packet. + * A suspended transfer may resume later from the start of the current + * block. Any received chunks in the current block should be discarded, + * they will be received again if the transfer resumes. + * + * The transfer will call @c resumed again when resuming. + * + * @note The BLOB Transfer Server does not run a timer in the suspended state, + * and it's up to the application to determine whether the + * transfer should be permanently cancelled. Without interaction, + * the transfer will be suspended indefinitely, and the BLOB Transfer + * Server will not accept any new transfers. + * + * @param srv BLOB Transfer Server instance. + */ + void (*suspend)(esp_ble_mesh_blob_srv_t *srv); + + /** @brief Transfer resume callback. + * + * Called if the transfer is resumed after being suspended. + * + * @param srv BLOB Transfer Server instance. + */ + void (*resume)(esp_ble_mesh_blob_srv_t *srv); + + /** @brief Transfer recovery callback. + * + * Called when the Bluetooth mesh subsystem is started if the device is rebooted + * in the middle of a transfer. + * + * Transfers will not be resumed after a reboot if this callback is not + * defined. + * + * @param srv BLOB Transfer Server instance. + * @param xfer Transfer to resume. + * @param io BLOB stream return parameter. Must be set to a valid + * BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(esp_ble_mesh_blob_srv_t *srv, + esp_ble_mesh_blob_xfer_t *xfer, + esp_ble_mesh_blob_io_t **io); +}; + +#if defined(CONFIG_BLE_MESH_BLOB_SRV) +#define ESP_BLE_MESH_BLOB_BLOCKS_MAX \ + (DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_SIZE_MAX, \ + CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MIN)) +#else +#define ESP_BLE_MESH_BLOB_BLOCKS_MAX 1 +#endif + +/** @brief BLOB Transfer Server instance. */ +struct esp_ble_mesh_blob_srv { + /** Event handler callbacks. */ + esp_ble_mesh_blob_srv_cb_t *cb; + + /** Runtime state: */ + esp_ble_mesh_blob_io_t *io; + struct k_delayed_work rx_timeout; + esp_ble_mesh_blob_block_t block; + esp_ble_mesh_model_t *mod; + esp_ble_mesh_blob_xfer_phase_t phase; + + /** State of blob serber. */ + struct esp_ble_mesh_blob_srv_state { + esp_ble_mesh_blob_xfer_t xfer; + uint16_t cli; + uint16_t app_idx; + uint16_t timeout_base; + uint16_t mtu_size; + uint8_t ttl; + + /* Bitfield of pending blocks. */ + BLE_MESH_ATOMIC_DEFINE(blocks, ESP_BLE_MESH_BLOB_BLOCKS_MAX); + } state; + + /* Pull mode (Pull BLOB Transfer Mode) behavior. */ + struct { + uint16_t chunk_idx; + struct k_delayed_work report; + } pull; +}; + +/** Target node's Pull mode (Pull BLOB Transfer Mode) context used + * while sending chunks to the Target node. + */ +struct esp_ble_mesh_blob_target_pull { + int64_t block_report_timestamp; /*!< Timestamp when the Block Report Timeout Timer expires for this Target node. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX, 8)]; /*!< Missing chunks reported by this Target node. */ +}; + +/** BLOB Transfer Client Target node. */ +struct esp_ble_mesh_blob_target { + sys_snode_t n; /*!< Linked list node */ + + uint16_t addr; /*!< Target node address. */ + + /** Target node's Pull mode context. + * Needs to be initialized when sending a BLOB in Pull mode. + */ + esp_ble_mesh_blob_target_pull_t *pull; + + uint8_t status; /*!< BLOB transfer status, see esp_ble_mesh_blob_status. */ + + uint8_t procedure_complete: 1, /*!< Procedure has been completed. */ + acked: 1, /*!< Message has been acknowledged. Not used when sending. */ + timedout: 1, /*!< Target node didn't respond after specified timeout. */ + skip: 1; /*!< Skip Target node from broadcast. */ +}; + + +/** BLOB transfer information. */ +struct esp_ble_mesh_blob_xfer_info { + esp_ble_mesh_blob_status_t status; /*!< BLOB transfer status. */ + esp_ble_mesh_blob_xfer_mode_t mode; /*!< BLOB transfer mode. */ + esp_ble_mesh_blob_xfer_phase_t phase; /*!< BLOB transfer phase. */ + uint64_t id; /*!< BLOB ID. */ + uint32_t size; /*!< BLOB size in octets. */ + uint8_t block_size_log; /*!< Logarithmic representation of the block size. */ + uint16_t mtu_size; /*!< MTU size in octets. */ + const uint8_t *missing_blocks; /*!< Bit field indicating blocks that were not received. */ +}; + + +/** BLOB Transfer Client transfer inputs. */ +struct esp_ble_mesh_blob_cli_inputs { + /** Linked list of Target nodes. Each node should point to + * esp_ble_mesh_blob_target_t::n. + */ + sys_slist_t targets; + + /** AppKey index to send with. */ + uint16_t app_idx; + + /** Group address destination for the BLOB transfer, or + * ESP_BLE_MESH_ADDR_UNASSIGNED to send every message to each Target + * node individually. + */ + uint16_t group; + + /** Time to live value of BLOB transfer messages. */ + uint8_t ttl; + + /** Additional response time for the Target nodes, in 10-second increments. + * + * The extra time can be used to give the Target nodes more time to respond + * to messages from the Client. The actual timeout will be calculated + * according to the following formula: + * + * @verbatim + * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) + * @endverbatim + * + * If a Target node fails to respond to a message from the Client within the + * configured transfer timeout, the Target node is dropped. + */ + uint16_t timeout_base; +}; + +/** Transfer capabilities of a Target node. */ +struct esp_ble_mesh_blob_cli_caps { + size_t max_size; /*!< Max BLOB size. */ + uint8_t min_block_size_log; /*!< Logarithmic representation of the minimum block size. */ + uint8_t max_block_size_log; /*!< Logarithmic representation of the maximum block size. */ + uint16_t max_chunks; /*!< Max number of chunks per block. */ + uint16_t max_chunk_size; /*!< Max chunk size. */ + uint16_t mtu_size; /*!< Max MTU size. */ + esp_ble_mesh_blob_xfer_mode_t modes; /*!< Supported transfer modes. */ +}; + +/** Event handler callbacks for the BLOB Transfer Client model. + * + * All handlers are optional. + */ +struct esp_ble_mesh_blob_cli_cb { + /** @brief Capabilities retrieval completion callback. + * + * Called when the capabilities retrieval procedure completes, indicating that + * a common set of acceptable transfer parameters have been established + * for the given list of Target nodes. All compatible Target nodes have + * status code ESP_BLE_MESH_BLOB_SUCCESS. + * + * @param cli BLOB Transfer Client instance. + * @param caps Safe transfer capabilities if the transfer capabilities + * of at least one Target node has satisfied the Client, or NULL otherwise. + */ + void (*caps)(esp_ble_mesh_blob_cli_t *cli, + const esp_ble_mesh_blob_cli_caps_t *caps); + + /** @brief Target node loss callback. + * + * Called whenever a Target node has been lost due to some error in the + * transfer. Losing a Target node is not considered a fatal error for + * the Client until all Target nodes have been lost. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that was lost. + * @param reason Reason for the Target node loss. + */ + void (*lost_target)(esp_ble_mesh_blob_cli_t *cli, + esp_ble_mesh_blob_target_t *target, + esp_ble_mesh_blob_status_t reason); + + /** @brief Transfer is suspended. + * + * Called when the transfer is suspended due to response timeout from all Target nodes. + * + * @param cli BLOB Transfer Client instance. + */ + void (*suspend)(esp_ble_mesh_blob_cli_t *cli); + + /** @brief Transfer end callback. + * + * Called when the transfer ends. + * + * @param cli BLOB Transfer Client instance. + * @param xfer Completed transfer. + * @param success Status of the transfer. + * Is @c true if at least one Target + * node received the whole transfer. + */ + void (*end)(esp_ble_mesh_blob_cli_t *cli, + const esp_ble_mesh_blob_xfer_t *xfer, bool success); + + /** @brief Transfer progress callback + * + * The content of @c info is invalidated upon exit from the callback. + * Therefore it needs to be copied if it is planned to be used later. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that responded to the request. + * @param info BLOB transfer information. + */ + void (*xfer_progress)(esp_ble_mesh_blob_cli_t *cli, + esp_ble_mesh_blob_target_t *target, + const esp_ble_mesh_blob_xfer_info_t *info); + + /** @brief End of Get Transfer Progress procedure. + * + * Called when all Target nodes have responded or the procedure timed-out. + * + * @param cli BLOB Transfer Client instance. + */ + void (*xfer_progress_complete)(esp_ble_mesh_blob_cli_t *cli); +}; + +/** @cond INTERNAL_HIDDEN */ +typedef struct { + /** Called for every Target node in unicast mode, or once in case of multicast mode. */ + void (*send)(esp_ble_mesh_blob_cli_t *cli, uint16_t dst); + /** Called after every @ref blob_cli_broadcast_ctx::send callback. */ + void (*send_complete)(esp_ble_mesh_blob_cli_t *cli, uint16_t dst); + /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes + * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called + * after transmission has been completed. + */ + void (*next)(esp_ble_mesh_blob_cli_t *cli); + /** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before + * @ref blob_cli_broadcast_ctx::next is called. + */ + bool acked; + /** If true, the message is always sent in a unicast way. */ + bool force_unicast; + /** If true, non-responsive Target nodes won't be dropped after transfer has timed out. */ + bool optional; + /** Set to true by the BLOB Transfer Client between blob_cli_broadcast + * and broadcast_complete calls. + */ + bool is_inited; + /* Defines a time in ms by which the broadcast API postpones sending the message to a next + * target or completing the broadcast. + */ + uint32_t post_send_delay_ms; +} esp_blob_cli_broadcast_ctx_t; +/** INTERNAL_HIDDEN @endcond */ + +/** + * @brief BLOB Transfer Client model instance. + * @note Preview version, the contents of this struct may change in the future. + */ +struct esp_ble_mesh_blob_cli { + /** Event handler callbacks */ + const esp_ble_mesh_blob_cli_cb_t *cb; + + /** Runtime state */ + const esp_ble_mesh_model_t *mod; + + /** Firmware transfer information */ + struct { + esp_ble_mesh_blob_target_t *target; + esp_blob_cli_broadcast_ctx_t ctx; + struct k_delayed_work retry; + /* Represents Client Timeout timer in a timestamp. Used in Pull mode only. */ + int64_t cli_timestamp; + struct k_work complete; + uint16_t pending; + uint8_t retries; + uint8_t sending : 1, + cancelled : 1; + } tx; + + /** Firmware IO operation callbacks */ + const esp_ble_mesh_blob_io_t *io; + + /** BLOB Transfer Client transfer inputs. */ + const esp_ble_mesh_blob_cli_inputs_t *inputs; + + /** BLOB transfer. */ + const esp_ble_mesh_blob_xfer_t *xfer; + + /** Interval between chunk transmissions, in milliseconds. */ + uint32_t chunk_interval_ms; + + /** BLOCK count */ + uint16_t block_count; + + /** CHUNK index */ + uint16_t chunk_idx; + + /** Max Transfer Unit Size of BLOB Transfer */ + uint16_t mtu_size; + + /** State of blob client mode transfer */ + esp_ble_mesh_blob_cli_state_t state; + + /** BLOB transfer data block. */ + esp_ble_mesh_blob_block_t block; + + /** Transfer capabilities of a Target node. */ + esp_ble_mesh_blob_cli_caps_t caps; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_BLOB_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h new file mode 100644 index 0000000000..bf91d9e06f --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h @@ -0,0 +1,999 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_DFU_MODEL_API_H_ +#define _ESP_BLE_MESH_DFU_MODEL_API_H_ + +#include "esp_ble_mesh_defs.h" +#include "esp_ble_mesh_blob_model_api.h" +#include "esp_ble_mesh_dfu_slot_api.h" + +#if CONFIG_BLE_MESH_DFU_CLI || CONFIG_BLE_MESH_DFU_SRV +#ifndef _BLE_MESH_BLOB_DEPRECATE_WARN +#define _BLE_MESH_BLOB_DEPRECATE_WARN +#warning Please note: All APIs published in this document are in Preview version and may undergo significant changes in the future. +#endif +#endif /* CONFIG_BLE_MESH_DFU_CLI || CONFIG_BLE_MESH_DFU_SRV */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x08) +#define ESP_BLE_MESH_DFU_OP_UPDATE_INFO_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x09) + +#define ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0a) +#define ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0b) + +#define ESP_BLE_MESH_DFU_OP_UPDATE_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0c) +#define ESP_BLE_MESH_DFU_OP_UPDATE_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0d) +#define ESP_BLE_MESH_DFU_OP_UPDATE_CANCEL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0e) +#define ESP_BLE_MESH_DFU_OP_UPDATE_APPLY ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0f) +#define ESP_BLE_MESH_DFU_OP_UPDATE_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x10) + +#if CONFIG_BLE_MESH_DFU_CLI +/** @def ESP_BLE_MESH_MODEL_DFU_CLI + * + * @brief Define a new DFU Client model. + * + * @note This API needs to be called for each element on which + * the application needs to have a DFU Client model. + * + * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * + * @return New DFU Client model instance. + */ +#define ESP_BLE_MESH_MODEL_DFU_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_MODEL_BLOB_CLI(NULL, &(cli_data)->blob), \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DFU_CLI, \ + NULL, cli_pub, cli_data) + + +/** @def ESP_BLE_MESH_DFU_CLI_INIT + * + * @brief Initialize a DFU Client model instance. + * + * @note This macro is used to initialize the DFU Client model. + * It sets the callback handlers for the DFU Client. + * + * @param _handlers Pointer to the callback handler structure (esp_ble_mesh_dfu_cli_cb_t). + * + * @return An initialized DFU Client model instance. + */ +#define ESP_BLE_MESH_DFU_CLI_INIT(_handlers) \ +{ \ + .cb = _handlers, \ +} +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV +/** @def ESP_BLE_MESH_MODEL_DFU_SRV + * + * @brief Define a new DFU Server model. + * + * @note This API needs to be called for each element on which + * the application needs to have a DFU Server model. + * + * @param srv_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param srv_data Pointer to the unique struct esp_ble_mesh_dfu_trans_srv_t. + * + * @return New DFU Server model instance. + */ +#define ESP_BLE_MESH_MODEL_DFU_SRV(srv_pub, srv_data) \ + ESP_BLE_MESH_MODEL_BLOB_SRV(NULL, &(srv_data)->blob), \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DFU_SRV, \ + NULL, srv_pub, srv_data) + + +/** @def ESP_BLE_MESH_DFU_SRV_INIT + * + * @brief Initialize a DFU Server model instance. + * + * @note This macro is used to initialize the DFU Server model. + * It sets the callback handlers and image information for the DFU Server. + * + * @param _handlers Pointer to the callback handler structure (esp_ble_mesh_dfu_srv_cb_t). + * @param _imgs Pointer to the array of DFU images (esp_ble_mesh_dfu_img_t). + * @param _img_count Number of DFU images in the array. + * + * @return An initialized DFU Server model instance. + */ +#define ESP_BLE_MESH_DFU_SRV_INIT(_handlers, _imgs, _img_count) \ + { \ + .cb = _handlers, \ + .imgs = _imgs, .img_count = _img_count, \ + } +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +/** @brief DFU image structure. **/ +typedef struct esp_ble_mesh_dfu_img esp_ble_mesh_dfu_img_t; + +#if CONFIG_BLE_MESH_DFU_CLI +/** @brief DFU Client model instance structure. + * + * This structure represents a DFU (Device Firmware Update) Client model instance. + * It contains the necessary fields for managing DFU operations as a client. + * Should be initialized with ESP_BLE_MESH_DFU_CLI_INIT. + * + * @note Preview version, the contents of this struct may change in the future. + */ +typedef struct esp_ble_mesh_dfu_cli esp_ble_mesh_dfu_cli_t; + +/** @brief DFU iteration action enumeration. + * + * This enumeration defines the possible actions that can be taken + * during DFU iteration callbacks. It controls whether to continue + * or stop iterating through DFU images. + */ +typedef enum esp_ble_mesh_dfu_iter esp_ble_mesh_dfu_iter_t; + +/** @brief DFU image callback. + * + * The image callback is called for every DFU image on the Target node when + * calling bt_mesh_dfu_cli_imgs_get. + * + * @param cli Firmware Update Client model instance. + * @param ctx Message context of the received message. + * @param idx Image index. + * @param total Total number of images on the Target node. + * @param img Image information for the given image index. + * @param cb_data Callback data. + * + * @retval ESP_BLE_MESH_DFU_ITER_STOP Stop iterating through the image list and + * return from bt_mesh_dfu_cli_imgs_get. + * @retval ESP_BLE_MESH_DFU_ITER_CONTINUE Continue iterating through the image list + * if any images remain. + */ +typedef esp_ble_mesh_dfu_iter_t (*esp_ble_mesh_dfu_img_cb_t)(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_msg_ctx_t *ctx, uint8_t idx, + uint8_t total, const esp_ble_mesh_dfu_img_t *img, + void *cb_data); +/** @brief DFU image slot structure. + * + * This structure represents a DFU image slot used for DFU distribution. + * It contains information about the firmware image including size, + * firmware ID, metadata, and their respective lengths. + */ +typedef struct esp_ble_mesh_dfu_slot esp_ble_mesh_dfu_slot_t; + +/** @brief DFU Target node structure. + * + * This structure represents a DFU Target node in the mesh network. + * It contains information about the target's BLOB transfer status, + * image index, expected DFU effect, current status, and phase. + */ +typedef struct esp_ble_mesh_dfu_target esp_ble_mesh_dfu_target_t; + +/** @brief DFU Client callback structure. + * + * This structure contains callback function pointers for DFU Client events + * such as transfer suspension, completion, application, confirmation, + * and target node loss. + */ +typedef struct esp_ble_mesh_dfu_cli_cb esp_ble_mesh_dfu_cli_cb_t; + +/** @brief DFU Client model instance structure. + * + * This structure represents a DFU (Device Firmware Update) Client model instance. + * It contains the necessary fields for managing DFU operations as a client. + * Should be initialized with ESP_BLE_MESH_DFU_CLI_INIT. + * + * @note Preview version, the contents of this struct may change in the future. + */ +typedef struct esp_ble_mesh_dfu_cli esp_ble_mesh_dfu_cli_t; + +/** @brief DFU Client BLOB transfer parameters structure. + * + * This structure contains parameters for BLOB transfer during DFU operations, + * including block size logarithmic representation and base chunk size. + */ +typedef struct esp_ble_mesh_dfu_cli_xfer_blob_params esp_ble_mesh_dfu_cli_xfer_blob_params_t; + +/** @brief DFU Client transfer parameters structure. + * + * This structure contains parameters for DFU transfer operations, + * including BLOB ID, image slot, transfer mode, and BLOB parameters. + */ +typedef struct esp_ble_mesh_dfu_cli_xfer esp_ble_mesh_dfu_cli_xfer_t; + +/** @brief Device Firmware Update Info Get parameters structure. + * + * This structure contains parameters for the Firmware Update Information Get message, + * including the first index and entries limit for requesting firmware information. + */ +typedef struct esp_ble_mesh_device_firmware_update_info_get esp_ble_mesh_device_firmware_update_info_get_t; + +/** @brief Device Firmware Update Metadata Check parameters structure. + * + * This structure contains parameters for the Firmware Update Metadata Check message, + * including the update firmware index and vendor-specific metadata. + */ +typedef struct esp_ble_mesh_device_firmware_update_metadata_check esp_ble_mesh_device_firmware_update_metadata_check_t; + +/** @brief DFU Client get message union. + * + * This union contains different parameter structures for various DFU Client + * get messages, allowing type-safe access to message-specific parameters. + */ +typedef union esp_ble_mesh_dfu_client_get esp_ble_mesh_dfu_client_get_t; + +/** @brief DFU Client send arguments structure. + * + * This structure contains arguments for sending firmware via DFU Client, + * including the client instance, transfer inputs, BLOB stream, and transfer parameters. + */ +typedef struct esp_ble_mesh_dfu_cli_send_arg esp_ble_mesh_dfu_cli_send_arg_t; + +/** @brief Firmware information structure. + * + * This structure contains information about firmware including firmware ID + * and update URI for retrieving new firmware. + */ +typedef struct esp_ble_mesh_firmware_info esp_ble_mesh_firmware_info_t; + +/** @brief Device Firmware Update Info Status response structure. + * + * This structure contains the response parameters for Firmware Update Information + * Status message, including firmware information list count and details. + */ +typedef struct esp_ble_mesh_device_firmware_update_info_status esp_ble_mesh_device_firmware_update_info_status_t; + +/** @brief Device Firmware Update Metadata Check Status response structure. + * + * This structure contains the response parameters for Firmware Update Metadata + * Check Status message, including status code and additional information. + */ +typedef struct esp_ble_mesh_device_firmware_metadata_check_status esp_ble_mesh_device_firmware_metadata_check_status_t; + +/** @brief Device Firmware Update Status response structure. + * + * This structure contains the response parameters for various Firmware Update + * Status messages (Get, Start, Cancel, Apply), including status, phase, + * TTL, timeout base, BLOB ID, and firmware image index. + */ +typedef struct esp_ble_mesh_device_firmware_update_status esp_ble_mesh_device_firmware_update_status_t; + +/** @brief DFU Client send callback structure. + * + * This structure contains the result of sending DFU Client messages, + * including error code indicating success or failure. + */ +typedef struct esp_ble_mesh_dfu_client_send_cb esp_ble_mesh_dfu_client_send_cb_t; + +/** @brief DFU Client receive callback union. + * + * This union contains different response structures for various DFU Client + * received status messages, allowing type-safe access to message-specific responses. + */ +typedef union esp_ble_mesh_dfu_client_recv_cb esp_ble_mesh_dfu_client_recv_cb_t; + +/** @brief DFU Client callback parameters structure. + * + * This structure contains parameters for DFU Client callbacks, including + * common client parameters and a union of send/receive callback data. + */ +typedef struct esp_ble_mesh_dfu_client_cb_param esp_ble_mesh_dfu_client_cb_param_t; +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV +/** @brief Firmware Update Server instance structure. + * + * This structure represents a DFU (Device Firmware Update) Server model instance. + * It contains the necessary fields for managing DFU operations as a server. + * Should be initialized with ESP_BLE_MESH_DFU_SRV_INIT. + * + * @note Preview version, the contents of this struct may change in the future. + */ +typedef struct esp_ble_mesh_dfu_srv esp_ble_mesh_dfu_srv_t; + +/** @brief Firmware Update Server callback structure. + * + * This structure contains callback function pointers for DFU Server events + * such as transfer check, start, end, recovery, and apply. + */ +typedef struct esp_ble_mesh_dfu_srv_cb esp_ble_mesh_dfu_srv_cb_t; +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +/** DFU transfer phase. */ +typedef enum esp_ble_mesh_dfu_phase { + /** Ready to start a Receive Firmware procedure. */ + ESP_BLE_MESH_DFU_PHASE_IDLE, + + /** The Transfer BLOB procedure failed. */ + ESP_BLE_MESH_DFU_PHASE_TRANSFER_ERR, + + /** The Receive Firmware procedure is being executed. */ + ESP_BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE, + + /** The Verify Firmware procedure is being executed. */ + ESP_BLE_MESH_DFU_PHASE_VERIFY, + + /** The Verify Firmware procedure completed successfully. */ + ESP_BLE_MESH_DFU_PHASE_VERIFY_OK, + + /** The Verify Firmware procedure failed. */ + ESP_BLE_MESH_DFU_PHASE_VERIFY_FAIL, + + /** The Apply New Firmware procedure is being executed. */ + ESP_BLE_MESH_DFU_PHASE_APPLYING, + + /** Firmware transfer has been canceled. */ + ESP_BLE_MESH_DFU_PHASE_TRANSFER_CANCELED, + + /** Firmware applying succeeded. */ + ESP_BLE_MESH_DFU_PHASE_APPLY_SUCCESS, + + /** Firmware applying failed. */ + ESP_BLE_MESH_DFU_PHASE_APPLY_FAIL, + + /** Phase of a node was not yet retrieved. */ + ESP_BLE_MESH_DFU_PHASE_UNKNOWN, +} esp_ble_mesh_dfu_phase_t; + +/** Expected effect of a DFU transfer. */ +typedef enum esp_ble_mesh_dfu_effect { + /** No changes to node Composition Data. */ + ESP_BLE_MESH_DFU_EFFECT_NONE, + + /** Node Composition Data changed and the node does not support remote + * provisioning. + */ + ESP_BLE_MESH_DFU_EFFECT_COMP_CHANGE_NO_RPR, + + /** Node Composition Data changed, and remote provisioning is supported. + * The node supports remote provisioning and Composition Data Page + * 0x80. Page 0x80 contains different Composition Data than Page 0x0. + */ + ESP_BLE_MESH_DFU_EFFECT_COMP_CHANGE, + + /** Node will be unprovisioned after the update. */ + ESP_BLE_MESH_DFU_EFFECT_UNPROV, +} esp_ble_mesh_dfu_effect_t; + +/** DFU status. */ +typedef enum esp_ble_mesh_dfu_status { + /** The message was processed successfully. */ + ESP_BLE_MESH_DFU_SUCCESS, + + /** Insufficient resources on the node */ + ESP_BLE_MESH_DFU_ERR_RESOURCES, + + /** The operation cannot be performed while the Server is in the current + * phase. + */ + ESP_BLE_MESH_DFU_ERR_WRONG_PHASE, + + /** An internal error occurred on the node. */ + ESP_BLE_MESH_DFU_ERR_INTERNAL, + + /** The message contains a firmware index value that is not expected. */ + ESP_BLE_MESH_DFU_ERR_FW_IDX, + + /** The metadata check failed. */ + ESP_BLE_MESH_DFU_ERR_METADATA, + + /** The Server cannot start a firmware update. */ + ESP_BLE_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE, + + /** Another BLOB transfer is in progress. */ + ESP_BLE_MESH_DFU_ERR_BLOB_XFER_BUSY, +} esp_ble_mesh_dfu_status_t; + +#if CONFIG_BLE_MESH_DFU_CLI +/** Action for DFU iteration callbacks. */ +enum esp_ble_mesh_dfu_iter { + /** Stop iterating. */ + ESP_BLE_MESH_DFU_ITER_STOP, + + /** Continue iterating. */ + ESP_BLE_MESH_DFU_ITER_CONTINUE, +}; + +/** @brief DFU transfer states + * + * This enumeration defines the various states of a DFU (Device Firmware Update) transfer. + * These states track the progress of firmware distribution from idle state through + * transfer, verification, application, and confirmation phases. + */ +typedef enum esp_ble_mesh_dfu_xfer_state { + /** Idle state - No DFU transfer is in progress. */ + ESP_BLE_MESH_DFU_XFER_IDLE, + + /** Transfer state - Firmware data is being transferred to target nodes. */ + ESP_BLE_MESH_DFU_XFER_TRANSFER, + + /** Refresh state - Transfer is paused or being refreshed. */ + ESP_BLE_MESH_DFU_XFER_REFRESH, + + /** Verified state - Firmware has been successfully verified on target nodes. */ + ESP_BLE_MESH_DFU_XFER_VERIFIED, + + /** Apply state - Firmware is being applied on target nodes. */ + ESP_BLE_MESH_DFU_XFER_APPLY, + + /** Applied state - Firmware has been successfully applied on target nodes. */ + ESP_BLE_MESH_DFU_XFER_APPLIED, + + /** Confirm state - Waiting for confirmation from target nodes. */ + ESP_BLE_MESH_DFU_XFER_CONFIRM, + + /** Cancel state - DFU transfer has been cancelled. */ + ESP_BLE_MESH_DFU_XFER_CANCEL, + + /** Suspended state - DFU transfer has been suspended. */ + ESP_BLE_MESH_DFU_XFER_SUSPENDED, +} esp_ble_mesh_dfu_xfer_state_t; + +/** @brief Callback events of Device Firmware Update Client Model + * + * This enumeration defines the various callback events that can be generated + * by the DFU (Device Firmware Update) Client model. These events are used + * to notify the application about different stages and states of the DFU process, + * including message sending, timeouts, response reception, and image transfer completion. + */ +typedef enum { + /** DFU Client message sending completed event. + * This event is triggered when a DFU Client message has been successfully sent. + */ + ESP_BLE_MESH_DFU_CLIENT_SEND_COMP_EVT, + + /** DFU Client timeout event. + * This event is triggered when a DFU Client operation times out waiting for a response. + */ + ESP_BLE_MESH_DFU_CLIENT_TIMEOUT_EVT, + + /** DFU Client received Get response event. + * This event is triggered when the DFU Client receives a response to a Get message. + */ + ESP_BLE_MESH_DFU_CLIENT_RECV_GET_RSP_EVT, + + /** DFU Client image send completed event. + * This event is triggered when the DFU Client has completed sending a firmware image. + */ + ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT, + + /** Maximum DFU Client event value (used for bounds checking). */ + ESP_BLE_MESH_DFU_CLIENT_EVT_MAX, +} esp_ble_mesh_dfu_client_cb_event_t; + +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +/** DFU image instance. + * + * Each DFU image represents a single updatable firmware image. + */ +struct esp_ble_mesh_dfu_img { + /** Firmware ID. */ + const void *fwid; + + /** Length of the firmware ID. */ + size_t fwid_len; + + /** Update URI, or NULL. */ + const char *uri; +}; + +#if CONFIG_BLE_MESH_DFU_CLI +/** DFU image slot for DFU distribution. */ +struct esp_ble_mesh_dfu_slot { + /** Size of the firmware in bytes. */ + size_t size; + /** Length of the firmware ID. */ + size_t fwid_len; + /** Length of the metadata. */ + size_t metadata_len; + /** Firmware ID. */ + uint8_t fwid[CONFIG_BLE_MESH_DFU_FWID_MAXLEN]; + /** Metadata. */ + uint8_t metadata[CONFIG_BLE_MESH_DFU_METADATA_MAXLEN]; +}; + +/** DFU Target node. */ +struct esp_ble_mesh_dfu_target { + /** BLOB Target node */ + esp_ble_mesh_blob_target_t blob; + /** Image index on the Target node */ + uint8_t img_idx; + /** Expected DFU effect, see bt_mesh_dfu_effect. */ + uint8_t effect; + /** Current DFU status, see bt_mesh_dfu_status. */ + uint8_t status; + /** Current DFU phase, see bt_mesh_dfu_phase. */ + uint8_t phase; +}; + +/** Firmware Update Client event callbacks. */ +struct esp_ble_mesh_dfu_cli_cb { + /** @brief BLOB transfer is suspended. + * + * Called when the BLOB transfer is suspended due to response timeout from all Target nodes. + * + * @param cli Firmware Update Client model instance. + */ + void (*suspended)(esp_ble_mesh_dfu_cli_t *cli); + + /** @brief DFU ended. + * + * Called when the DFU transfer ends, either because all Target nodes were + * lost or because the transfer was completed successfully. + * + * @param cli Firmware Update Client model instance. + * @param reason Reason for ending. + */ + void (*ended)(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_dfu_status_t reason); + + /** @brief DFU transfer applied on all active Target nodes. + * + * Called at the end of the apply procedure. + * + * @param cli Firmware Update Client model instance. + */ + void (*applied)(esp_ble_mesh_dfu_cli_t *cli); + + /** @brief DFU transfer confirmed on all active Target nodes. + * + * Called at the end of the apply procedure. + * + * @param cli Firmware Update Client model instance. + */ + void (*confirmed)(esp_ble_mesh_dfu_cli_t *cli); + + /** @brief DFU Target node was lost. + * + * A DFU Target node was dropped from the receivers list. The Target node's + * @c status is set to reflect the reason for the failure. + * + * @param cli Firmware Update Client model instance. + * @param target DFU Target node that was lost. + */ + void (*lost_target)(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_dfu_target_t *target); +}; + +/** Firmware Update Client model instance. + * Should be initialized with ESP_BLE_MESH_DFU_CLI_INIT. + * + * @note Preview version, the contents of this struct may change in the future. + */ +struct esp_ble_mesh_dfu_cli { + /** Callback structure. */ + const esp_ble_mesh_dfu_cli_cb_t *cb; + /** Underlying BLOB Transfer Client. */ + esp_ble_mesh_blob_cli_t blob; + + /** runtime state */ + uint32_t op; + + /** ble mesh model instance. */ + esp_ble_mesh_model_t *mod; + + /** BLOB Transfer information */ + struct { + const esp_ble_mesh_dfu_slot_t *slot; + const esp_ble_mesh_blob_io_t *io; + esp_ble_mesh_blob_xfer_t blob; + uint8_t state; + uint8_t flags; + } xfer; + + /** Current request */ + void *req; +}; + +/** BLOB parameters for Firmware Update Client transfer */ +struct esp_ble_mesh_dfu_cli_xfer_blob_params { + /** Logarithmic representation of the block size. */ + uint8_t block_size_log; + /** Base chunk size. May be smaller for the last chunk. */ + uint16_t chunk_size; +}; + +/** Firmware Update Client transfer parameters */ +struct esp_ble_mesh_dfu_cli_xfer { + /** BLOB ID to use for this transfer, or 0 to set it randomly. */ + uint64_t blob_id; + /** DFU image slot to transfer. */ + const esp_ble_mesh_dfu_slot_t *slot; + /** Transfer mode (Push (Push BLOB Transfer Mode) or Pull (Pull BLOB Transfer Mode)) */ + enum esp_ble_mesh_blob_xfer_mode mode; + /** BLOB parameters to be used for the transfer, or NULL to retrieve Target nodes' + * capabilities before sending a firmware. + */ + const esp_ble_mesh_dfu_cli_xfer_blob_params_t *blob_params; +}; + +/** + * @brief Parameters of Device Firmware Update Info Get. + */ +struct esp_ble_mesh_device_firmware_update_info_get { + uint8_t first_index; /*!< Index of the first requested entry from the Firmware Information List state */ + uint8_t entries_limit; /*!< Maximum number of entries that the server includes in a Firmware Update Information Status message */ + esp_ble_mesh_dfu_img_cb_t img_cb; /*!< Added by Espressif, callback function used to walkthrough recceived images */ +}; + +/** + * @brief Parameters of Device Firmware Update Firmware Metadata Check. + */ +struct esp_ble_mesh_device_firmware_update_metadata_check { + uint8_t update_firmware_index; /*!< Index of the firmware image in the Firmware Information List state to check */ + struct net_buf_simple *metadata; /*!< Vendor-specific metadata */ +}; + +/** + * @brief Device Firmware Update Client model get message union. + * For ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET + * ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK + * ESP_BLE_MESH_DFU_OP_UPDATE_START + * the get_state parameter in the `esp_ble_mesh_dfu_client_get_state` function should not be set to NULL. + */ +union esp_ble_mesh_dfu_client_get { + esp_ble_mesh_device_firmware_update_info_get_t dfu_update_info_get; /*!< For ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET */ + esp_ble_mesh_device_firmware_update_metadata_check_t dfu_metadata_check; /*!< For ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK */ +}; + +/** + * @brief Parameters of Device Firmware Update Client + * model to send Firmware. + */ +struct esp_ble_mesh_dfu_cli_send_arg { + esp_ble_mesh_dfu_cli_t *cli; /*!< Device Firmware Update Client model instance */ + esp_ble_mesh_blob_cli_inputs_t *inputs; /*!< BLOB Transfer Client transfer inputs. */ + esp_ble_mesh_blob_io_t *io; /*!< BLOB stream. */ + esp_ble_mesh_dfu_cli_xfer_t *xfer; /*!< Firmware Update Client transfer parameters */ +}; + +/** + * @brief Struct of firmware information. + */ +struct esp_ble_mesh_firmware_info { + struct net_buf_simple *fw_id; /*!< Firmware ID */ + struct net_buf_simple *update_uri; /*!< URI used to retrieve a new firmware */ +}; + +/** + * @brief Response of Firmware Update Information Get Message + */ +struct esp_ble_mesh_device_firmware_update_info_status { + uint8_t fw_info_list_cnt; /*!< The number of entries in the Firmware Information List */ + uint8_t first_index; /*!< Index of the first requested entry from the Firmware Information List */ + esp_ble_mesh_firmware_info_t *fw_info_list; /*!< List of firmware information entries */ +}; + +/** + * @brief Response of Firmware Update Firmware Metadata Check Message + */ +struct esp_ble_mesh_device_firmware_metadata_check_status { + uint8_t status : 3; /*!< Status Code from the firmware metadata check */ + uint8_t additional_info : 5; /*!< The Firmware Update Additional Information state from the Firmware Update Server (see Section 4.1.3)*/ + uint8_t update_firmware_image_index; /*!< Index of the firmware image in the Firmware Information List state that was checked*/ +}; + +/** + * @brief Response of Firmware Update Get Message, + * Firmware Update Start Message, + * Firmware Update Cancel Message, + * Firmware Update Apply Message. + */ +struct esp_ble_mesh_device_firmware_update_status { + uint8_t status : 3; /*!< Status Code for the requesting message */ + uint8_t update_phase : 3; /*!< The Update Phase state of the Firmware Update Server */ + uint8_t update_ttl; /*!< TTL value to use during firmware image transfer */ + uint8_t additional_info : 5; /*!< The Firmware Update Additional Information state from the Firmware Update Server (see Section 4.1.3)*/ + uint16_t update_timeout_base; /*!< Used to compute the timeout of the firmware image transfer */ + uint64_t update_blob_id; /*!< BLOB identifier for the firmware image */ + uint8_t update_fw_img_idx; /*!< The index of the firmware image in the Firmware Information List state being updated*/ +}; + +/** Result of sending Device Firmware Update Client messages */ +struct esp_ble_mesh_dfu_client_send_cb { + int err_code; /*!< Result of sending a message */ +}; + +/** + * @brief Device Firmware Update Client model received message union + */ +union esp_ble_mesh_dfu_client_recv_cb { + esp_ble_mesh_device_firmware_update_info_status_t dfu_update_info_status; /*!< ESP_BLE_MESH_MODEL_OP_DIRECTED_CONTROL_STATUS */ + esp_ble_mesh_device_firmware_metadata_check_status_t dfu_metadata_check_status; /*!< ESP_BLE_MESH_MODEL_OP_PATH_METRIC_STATUS */ + esp_ble_mesh_device_firmware_update_status_t dfu_firmware_update_status; /*!< ESP_BLE_MESH_MODEL_OP_DISCOVERY_TABLE_CAPS_STATUS */ +}; + +/** Device Firmware Update Client model callback parameters */ +struct esp_ble_mesh_dfu_client_cb_param { + esp_ble_mesh_client_common_param_t *params; /*!< Client common parameters, used by all events. */ + /** Union of DF Client callback */ + union { + esp_ble_mesh_dfu_client_send_cb_t send; /*!< Result of sending a message */ + esp_ble_mesh_dfu_client_recv_cb_t recv; /*!< Parameters of received status message */ + }; +}; + +/** + * @brief Bluetooth Mesh Device Firmware Update client and server model functions. + */ + +/** + * @brief Device Firmware Update Client model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_dfu_client_cb_t)(esp_ble_mesh_dfu_client_cb_event_t event, + esp_ble_mesh_dfu_client_cb_param_t *param); + +/** + * @brief Device Firmware Update Server model callback function type + * @param event: Event type + * @param param: Pointer to callback parameter + */ +typedef void (* esp_ble_mesh_dfu_server_cb_t)(esp_ble_mesh_dfu_client_cb_event_t event, + esp_ble_mesh_dfu_client_cb_param_t *param); + +/** + * @brief Register BLE Mesh Device Firmware Update Client model callback. + * + * @param callback: Pointer to the callback function. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_register_dfu_client_callback(esp_ble_mesh_dfu_client_cb_t callback); + +/** + * @brief Get the value of Device Firmware Server model state with the corresponding get message. + * + * @param params: Pointer to BLE Mesh common client parameters. + * @param get: Pointer to a union, each kind of opcode corresponds to one structure inside. + * + * @return ESP_OK on success or error code otherwise. + * + */ +esp_err_t esp_ble_mesh_dfu_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfu_client_get_t *get); + +/** @brief Start distributing a DFU. + * + * Starts distribution of the firmware in the given slot to the list of DFU + * Target nodes in @c ctx. The transfer runs in the background, and its end is + * signalled through the bt_mesh_dfu_cli_cb::ended callback. + * + * @note The BLOB Transfer Client transfer inputs @c targets list must point to a list of + * bt_mesh_dfu_target nodes. The contents of `inputs`, `io`, `xfer` must not be changed or + * released from the beginning to the end of the transmission. + * + * @param cli Firmware Update Client model instance. + * @param inputs BLOB Transfer Client transfer inputs. + * @param io BLOB stream to read BLOB from. + * @param xfer Firmware Update Client transfer parameters. + * + * @return 0 on success, or (negative) error code otherwise. + */ +esp_err_t esp_ble_mesh_dfu_cli_img_send(esp_ble_mesh_dfu_cli_t *cli, + esp_ble_mesh_blob_cli_inputs_t *inputs, + esp_ble_mesh_blob_io_t *io, + esp_ble_mesh_dfu_cli_xfer_t *xfer); + +/** @brief Get progress as a percentage of completion. + * + * @param cli Firmware Update Client model instance. + * + * @return The progress of the current transfer in percent, or 0 if no + * transfer is active. + */ +uint8_t esp_ble_mesh_dfu_cli_progress(esp_ble_mesh_dfu_cli_t *cli); +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV +/** @brief Firmware Update Server event callbacks. */ +struct esp_ble_mesh_dfu_srv_cb { + /** @brief Transfer check callback. + * + * The transfer check can be used to validate the incoming transfer + * before it starts. The contents of the metadata is implementation + * specific, and should contain all the information the application + * needs to determine whether this image should be accepted, and what + * the effect of the transfer would be. + * + * If applying the image will have an effect on the provisioning state + * of the mesh stack, this can be communicated through the @c effect + * return parameter. + * + * The metadata check can be performed both as part of starting a new + * transfer and as a separate procedure. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image the metadata check is performed on. + * @param metadata Image metadata. + * @param effect Return parameter for the image effect on the + * provisioning state of the mesh stack. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*check)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img, + struct net_buf_simple *metadata, + esp_ble_mesh_dfu_effect_t *effect); + + /** @brief Transfer start callback. + * + * Called when the Firmware Update Server is ready to start a new DFU transfer. + * The application must provide an initialized BLOB stream to be used + * during the DFU transfer. + * + * The following error codes are treated specially, and should be used + * to communicate these issues: + * - @c -ENOMEM: The device cannot fit this image. + * - @c -EBUSY: The application is temporarily unable to accept the + * transfer. + * - @c -EALREADY: The device has already received and verified this + * image, and there's no need to transfer it again. The Firmware Update model + * will skip the transfer phase, and mark the image as verified. + * + * This handler is mandatory. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param metadata Image metadata. + * @param io BLOB stream return parameter. Must be set to a + * valid BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code otherwise. Return + * codes @c -ENOMEM, @c -EBUSY @c -EALREADY will be passed to + * the updater, other error codes are reported as internal + * errors. + */ + int (*start)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img, + struct net_buf_simple *metadata, + const esp_ble_mesh_blob_io_t **io); + + /** @brief Transfer end callback. + * + * This handler is optional. + * + * If the transfer is successful, the application should verify the + * firmware image, and call either bt_mesh_dfu_srv_verified or + * bt_mesh_dfu_srv_rejected depending on the outcome. + * + * If the transfer fails, the Firmware Update Server will be available for new + * transfers immediately after this function returns. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that failed the update. + * @param success Whether the DFU transfer was successful. + */ + void (*end)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img, bool success); + + /** @brief Transfer recovery callback. + * + * If the device reboots in the middle of a transfer, the Firmware Update Server + * calls this function when the Bluetooth mesh subsystem is started. + * + * This callback is optional, but transfers will not be recovered after + * a reboot without it. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param io BLOB stream return parameter. Must be set to a valid BLOB + * stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img, + const esp_ble_mesh_blob_io_t **io); + + /** @brief Transfer apply callback. + * + * Called after a transfer has been validated, and the updater sends an + * apply message to the Target nodes. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that should be applied. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*apply)(esp_ble_mesh_dfu_srv_t *srv, + const esp_ble_mesh_dfu_img_t *img); +}; + +/** @brief Firmware Update Server instance. + * + * Should be initialized with ESP_BLE_MESH_DFU_SRV_INIT. + * @note Preview version, the contents of this struct may change in the future. + */ +struct esp_ble_mesh_dfu_srv { + /** Underlying BLOB Transfer Server. */ + esp_ble_mesh_blob_srv_t blob; + /** Callback structure. */ + const esp_ble_mesh_dfu_srv_cb_t *cb; + /** List of updatable images. */ + const esp_ble_mesh_dfu_img_t *imgs; + /** Number of updatable images. */ + size_t img_count; + + /** Runtime state */ + esp_ble_mesh_model_t *mod; + /** Update information */ + struct { + /* Effect of transfer, @see bt_mesh_dfu_effect. */ + uint8_t effect; + /* Current phase, @see bt_mesh_dfu_phase. */ + uint8_t phase; + uint8_t ttl; + uint8_t idx; + uint16_t timeout_base; + uint16_t meta; + } update; +}; + +/** @brief Accept the received DFU transfer. + * + * Should be called at the end of a successful DFU transfer. + * + * If the DFU transfer completes successfully, the application should verify + * the image validity (including any image authentication or integrity checks), + * and call this function if the image is ready to be applied. + * + * @param srv Firmware Update Server instance. + */ +void esp_ble_mesh_dfu_srv_verified(esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Reject the received DFU transfer. + * + * Should be called at the end of a successful DFU transfer. + * + * If the DFU transfer completes successfully, the application should verify + * the image validity (including any image authentication or integrity checks), + * and call this function if one of the checks fail. + * + * @param srv Firmware Update Server instance. + */ +void esp_ble_mesh_dfu_srv_rejected(esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Cancel the ongoing DFU transfer. + * + * @param srv Firmware Update Server instance. + */ +void esp_ble_mesh_dfu_srv_cancel(esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Confirm that the received DFU transfer was applied. + * + * Should be called as a result of the `bt_mesh_dfu_srv_cb.apply` callback. + * + * @param srv Firmware Update Server instance. + */ +void esp_ble_mesh_dfu_srv_applied(esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Check if the Firmware Update Server is busy processing a transfer. + * + * @param srv Firmware Update Server instance. + * + * @return true if a DFU procedure is in progress, false otherwise. + */ +bool esp_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv); + +/** @brief Get the progress of the current DFU procedure, in percent. + * + * @param srv Firmware Update Server instance. + * + * @return The current transfer progress in percent. + */ +uint8_t esp_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv); +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ESP_BLE_MESH_DFU_MODEL_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_slot_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_slot_api.h new file mode 100644 index 0000000000..0332e0a0b5 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_slot_api.h @@ -0,0 +1,148 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _ESP_BLE_MESH_DFU_SLOT_API_H_ +#define _ESP_BLE_MESH_DFU_SLOT_API_H_ + +#include "esp_ble_mesh_dfu_model_api.h" + +#if CONFIG_BLE_MESH_DFU_SLOTS +#ifndef _BLE_MESH_BLOB_DEPRECATE_WARN +#define _BLE_MESH_BLOB_DEPRECATE_WARN +#warning Please note: All APIs published in this document are in Preview version and may undergo significant changes in the future. +#endif +#endif /* CONFIG_BLE_MESH_DFU_SLOTS */ + +typedef struct esp_ble_mesh_dfu_slot esp_ble_mesh_dfu_slot_t; + +typedef enum esp_ble_mesh_dfu_iter + (*esp_ble_mesh_dfu_slot_cb_t) (const esp_ble_mesh_dfu_slot_t *slot, void *user_data); + +/** @brief Get the number of slots committed to the firmware list. + * + * @return Number of committed slots. + */ +int esp_ble_mesh_dfu_slot_count(void); + +/** @brief Reserve a new DFU image slot for a distributable image. + * + * A DFU image slot represents a single distributable DFU image with all its + * metadata. The slot data must be set using esp_ble_mesh_dfu_slot_info_set and + * esp_ble_mesh_dfu_slot_fwid_set, and the slot committed using + * esp_ble_mesh_dfu_slot_commit for the slot to be considered part of the slot + * list. + * + * @return + * - slot : A pointer to the reserved slot + * - @c NULL : Slot allocation failed + */ +esp_ble_mesh_dfu_slot_t *esp_ble_mesh_dfu_slot_reserve(void); + +/** @brief Set the size and metadata for a reserved slot. + * + * @param dfu_slot Pointer to the reserved slot for which to set the + * metadata. + * @param size The size of the image. + * @param metadata Metadata or NULL. + * @param metadata_len Length of the metadata, at most @c + * CONFIG_BLE_MESH_DFU_METADATA_MAXLEN. + * + * @return + * - 0 : success + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter or invalid metadata parameter + * - @c ESP_ERR_INVALID_SIZE : metadata length is zero or exceeds @c CONFIG_BLE_MESH_DFU_METADATA_MAXLEN + */ +int esp_ble_mesh_dfu_slot_info_set(esp_ble_mesh_dfu_slot_t *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len); + +/** @brief Set the new fwid for the incoming image for a reserved slot. + * + * @param dfu_slot Pointer to the reserved slot for which to set the fwid. + * @param fwid Fwid to set. + * @param fwid_len Length of the fwid, at most @c + * CONFIG_BLE_MESH_DFU_FWID_MAXLEN. + * + * @return + * - 0 : success + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter or invalid fwid parameter + * - @c ESP_ERR_INVALID_SIZE : fwid length is zero or exceeds @c CONFIG_BLE_MESH_DFU_FWID_MAXLEN + */ +int esp_ble_mesh_dfu_slot_fwid_set(esp_ble_mesh_dfu_slot_t *dfu_slot, + const uint8_t *fwid, size_t fwid_len); + +/** @brief Commit the reserved slot to the list of slots, and store it + * persistently. + * + * If the commit fails for any reason, the slot will still be in the reserved + * state after this call. + * + * @param dfu_slot Pointer to the reserved slot. + * + * @return + * - 0 : success + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter or slot has been committed + * - @c ESP_ERR_INVALID_SIZE : slot size is zero + */ +int esp_ble_mesh_dfu_slot_commit(esp_ble_mesh_dfu_slot_t *dfu_slot); + +/** @brief Release a reserved slot so that it can be reserved again. + * + * @param dfu_slot Pointer to the reserved slot. + */ +void esp_ble_mesh_dfu_slot_release(const esp_ble_mesh_dfu_slot_t *dfu_slot); + +/** @brief Delete a committed DFU image slot. + * + * @param slot Slot to delete. Must be a valid pointer acquired from this + * module. + * + * @return + * - 0 : success + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter + */ +int esp_ble_mesh_dfu_slot_del(const esp_ble_mesh_dfu_slot_t *slot); + +/** @brief Delete all DFU image slots. + */ +void esp_ble_mesh_dfu_slot_del_all(void); + +/** @brief Get the DFU image slot at the given firmware image list index. + * + * @param img_idx DFU image slot index. + * + * @return + * - slot : A pointer to the reserved slot + * - @c NULL : No slot exists with the given index + */ +const esp_ble_mesh_dfu_slot_t *esp_ble_mesh_dfu_slot_at(uint16_t img_idx); + +/** @brief Get the committed DFU image slot for the image with the given + * firmware ID. + * + * @param fwid Firmware ID. + * @param fwid_len Firmware ID length. + * @param slot Slot pointer to fill. + * + * @return + * - index : Slot index + * - @c ESP_ERR_INVALID_ARG : invalid fwid parameter or invalid slot parameter + * - @c ESP_ERR_INVALID_SIZE : fwid length is zero + * - @c ESP_ERR_NOT_FOUND : no slot exists with the given firmware id + */ +int esp_ble_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, esp_ble_mesh_dfu_slot_t **slot); + +/** @brief Get the index in the firmware image list for the given slot. + * + * @param slot Slot to find. + * + * @return + * - index : Slot index + * - @c ESP_ERR_INVALID_ARG : invalid slot parameter + * - @c ESP_ERR_NOT_FOUND : The slot does not exist + */ +int esp_ble_mesh_dfu_slot_img_idx_get(const esp_ble_mesh_dfu_slot_t *slot); + +#endif /* _ESP_BLE_MESH_FW_SLOT_API_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h index 90e948b7d9..54b4f20aa8 100644 --- a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_mbt_model_api.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,51 +9,86 @@ #include "esp_ble_mesh_defs.h" +#if CONFIG_BLE_MESH_MBT_SRV || CONFIG_BLE_MESH_MBT_CLI +#ifndef _BLE_MESH_MBT_DEPRECATE_WARN +#define _BLE_MESH_MBT_DEPRECATE_WARN +#warning "warning: 'All content in this document, including data structures and APIs, will be deprecated." +#endif +#endif /* CONFIG_BLE_MESH_MBT_SRV || CONFIG_BLE_MESH_MBT_CLI */ + #ifdef __cplusplus extern "C" { #endif +#if CONFIG_IDF_CI_BUILD +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +/** @cond */ +#if (CONFIG_BLE_MESH_MBT_SRV && CONFIG_BLE_MESH_BLOB_SRV) || \ + (CONFIG_BLE_MESH_MBT_CLI && CONFIG_BLE_MESH_BLOB_CLI) +#error "BLOB Transfer Model and BLOB Model cannot be enabled at the same time" +#endif +/** @endcond */ + +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x00) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x01) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_CANCEL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x02) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_TRANSFER_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x03) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_BLOCK_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x05) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_BLOCK_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x04) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_PARTIAL_BLOCK_REPORT ESP_BLE_MESH_MODEL_OP_1(0x65) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_BLOCK_STATUS ESP_BLE_MESH_MODEL_OP_1(0x67) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_CHUNK_TRANSFER ESP_BLE_MESH_MODEL_OP_1(0x66) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_INFORMATION_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x06) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_MODEL_OP_BLOB_INFORMATION_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x07) +/** @deprecated This macro will be deprecated in future versions. */ #define ESP_BLE_MESH_BLOB_ID_SIZE 8 -/** @def ESP_BLE_MESH_MODEL_MBT_CLI +/** @def ESP_BLE_MESH_MODEL_MBT_CLI * - * @brief Define a new BLOB Transfer Client model. + * @brief Define a new BLOB Transfer Client model. * - * @note This API needs to be called for each element on which - * the application needs to have a BLOB Transfer Client model. + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Client model. * - * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. - * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. + * @deprecated This macro will be deprecated in future versions. * - * @return New BLOB Transfer Client model instance. + * @param cli_pub Pointer to unique struct esp_ble_mesh_model_pub_t. + * @param cli_data Pointer to unique struct esp_ble_mesh_client_t. + * + * @return New BLOB Transfer Client model instance. */ #define ESP_BLE_MESH_MODEL_MBT_CLI(cli_pub, cli_data) \ ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_MBT_CLI, \ NULL, cli_pub, cli_data) -/** @def ESP_BLE_MESH_MODEL_MBT_SRV +/** @def ESP_BLE_MESH_MODEL_MBT_SRV * - * @brief Define a new BLOB Transfer Server model. + * @brief Define a new BLOB Transfer Server model. * - * @note This API needs to be called for each element on which - * the application needs to have a BLOB Transfer Server model. + * @note This API needs to be called for each element on which + * the application needs to have a BLOB Transfer Server model. * - * @param srv_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. - * @param srv_data Pointer to the unique struct esp_ble_mesh_blob_trans_srv_t. + * @deprecated This macro will be deprecated in future versions. * - * @return New BLOB Transfer Server model instance. + * @param srv_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. + * @param srv_data Pointer to the unique struct esp_ble_mesh_blob_trans_srv_t. + * + * @return New BLOB Transfer Server model instance. */ #define ESP_BLE_MESH_MODEL_MBT_SRV(srv_pub, srv_data) \ ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_MBT_SRV, \ @@ -61,125 +96,125 @@ extern "C" { /** BLOB Transfer Server model context */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ -} esp_ble_mesh_mbt_srv_t; + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ +} esp_ble_mesh_mbt_srv_t __attribute__((deprecated)); /** Parameters of BLOB receiver */ typedef struct { - uint16_t unicast_addr; /*!< Unicast address of the server */ - uint8_t retrieved_transfer_phase; /*!< Retrieved transfer phase of the server */ - uint8_t status:4; /*!< Status of the last operation */ - uint16_t blocks_not_received_len; /*!< Indicates the length which blocks were not received by the server. */ - uint8_t *blocks_not_received; /*!< Indicates which blocks were not received by the server. */ - uint16_t missing_chunks_len; /*!< Indicates which chunks were not received in the current block */ - uint8_t *missing_chunks; /*!< Indicates which chunks were not received by the server in the current block */ -/* The followings are the additional information contained in status messages. */ - uint8_t transfer_mode:2; /*!< BLOB transfer mode */ - uint8_t expected_blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< Expected BLOB identifier list */ - uint32_t blob_size; /*!< BLOB size in octets */ - uint8_t block_size_log; /*!< Indicates the block size */ - uint16_t transfer_mtu_size; /*!< MTU size in octets */ - bool block_status_recv; /*!< Indicate if Blob Block Status is received as a response. */ -} esp_ble_mesh_blob_receiver_t; /*!< Structure of BLOB receiver */ + uint16_t unicast_addr; /*!< Unicast address of the server */ + uint8_t retrieved_transfer_phase; /*!< Retrieved transfer phase of the server */ + uint8_t status: 4; /*!< Status of the last operation */ + uint16_t blocks_not_received_len; /*!< Indicates the length which blocks were not received by the server. */ + uint8_t *blocks_not_received; /*!< Indicates which blocks were not received by the server. */ + uint16_t missing_chunks_len; /*!< Indicates which chunks were not received in the current block */ + uint8_t *missing_chunks; /*!< Indicates which chunks were not received by the server in the current block */ + /* The following are the additional information contained in status messages. */ + uint8_t transfer_mode: 2; /*!< BLOB transfer mode */ + uint8_t expected_blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< Expected BLOB identifier list */ + uint32_t blob_size; /*!< BLOB size in octets */ + uint8_t block_size_log; /*!< Indicates the block size */ + uint16_t transfer_mtu_size; /*!< MTU size in octets */ + bool block_status_recv; /*!< Indicate if Blob Block Status is received as a response. */ +} esp_ble_mesh_blob_receiver_t __attribute__((deprecated)); /*!< Structure of BLOB receiver */ /** Parameters of BLOB Information Status */ typedef struct { - uint8_t min_block_size_log; /*!< Min Block Size Log */ - uint8_t max_block_size_log; /*!< Max Block Size Log */ - uint16_t max_total_chunks; /*!< Max Total Chunks */ - uint16_t max_chunk_size; /*!< Max Chunk Size */ - uint32_t max_blob_size; /*!< Max BLOB Size */ - uint16_t server_mtu_size; /*!< Server MTU size */ - uint8_t supported_transfer_mode; /*!< Supported Transfer Mode */ -} esp_ble_mesh_blob_capabilities_t; /*!< Parameters of BLOB Information Status */ + uint8_t min_block_size_log; /*!< Min Block Size Log */ + uint8_t max_block_size_log; /*!< Max Block Size Log */ + uint16_t max_total_chunks; /*!< Max Total Chunks */ + uint16_t max_chunk_size; /*!< Max Chunk Size */ + uint32_t max_blob_size; /*!< Max BLOB Size */ + uint16_t server_mtu_size; /*!< Server MTU size */ + uint8_t supported_transfer_mode; /*!< Supported Transfer Mode */ +} esp_ble_mesh_blob_capabilities_t __attribute__((deprecated)); /*!< Parameters of BLOB Information Status */ /** Parameters of BLOB retrieve capabilities */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint8_t unicast_addr_count; /*!< The count of unicast address */ - uint16_t *unicast_addr; /*!< Unicast address list */ -} esp_ble_mesh_retrieve_capabilities_t; /*!< Parameters of BLOB retrieve capabilities */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unicast address list */ +} esp_ble_mesh_retrieve_capabilities_t __attribute__((deprecated)); /*!< Parameters of BLOB retrieve capabilities */ /** Parameters of BLOB transfer */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint8_t unicast_addr_count; /*!< The count of unicast address */ - uint16_t *unicast_addr; /*!< Unicast address list */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ - uint32_t blob_size; /*!< BLOB size in octets */ - uint8_t *blob_data; /*!< BLOB data */ - uint8_t transfer_mode; /*!< BLOB transfer mode */ - uint16_t client_timeout_base; /*!< Time wait for messages from the serve */ -} esp_ble_mesh_transfer_blob_t; /*!< Parameters of BLOB transfer */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unicast address list */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ + uint32_t blob_size; /*!< BLOB size in octets */ + uint8_t *blob_data; /*!< BLOB data */ + uint8_t transfer_mode; /*!< BLOB transfer mode */ + uint16_t client_timeout_base; /*!< Time wait for messages from the serve */ +} esp_ble_mesh_transfer_blob_t __attribute__((deprecated)); /*!< Parameters of BLOB transfer */ /** Parameters of BLOB Block Status message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint16_t block_number; /*!< Block number of the current block */ - uint16_t chunk_size; /*!< Chunk Size (in octets) for the current block */ -} esp_ble_mesh_send_block_t; /*!< BLOB Block Status message structure */ + uint16_t block_number; /*!< Block number of the current block */ + uint16_t chunk_size; /*!< Chunk Size (in octets) for the current block */ +} esp_ble_mesh_send_block_t __attribute__((deprecated)); /*!< BLOB Block Status message structure */ /** Parameters of BLOB send message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ -} esp_ble_mesh_send_data_t; /*!< Parameters of BLOB send message */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ +} esp_ble_mesh_send_data_t __attribute__((deprecated)); /*!< Parameters of BLOB send message */ /** Parameters of determine Block Status message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ -} esp_ble_mesh_determine_block_status_t; /*!< Parameters of determine Block Status message */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ +} esp_ble_mesh_determine_block_status_t __attribute__((deprecated)); /*!< Parameters of determine Block Status message */ /** Parameters of determine Block Status message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint8_t unicast_addr_count; /*!< The count of unicast address */ - uint16_t *unicast_addr; /*!< Unicast address list */ -} esp_ble_mesh_determine_transfer_status_t; /*!< Parameters of determine Block Status message */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unicast address list */ +} esp_ble_mesh_determine_transfer_status_t __attribute__((deprecated)); /*!< Parameters of determine Block Status message */ /** Parameters of cancel transfer message */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ - uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ + esp_ble_mesh_model_t *model; /*!< Pointer to BLOB Transfer Server model */ + uint8_t msg_role; /*!< Role of the device - Node/Provisioner */ - uint16_t multicast_addr; /*!< Multicast Address state */ - uint16_t app_idx; /*!< AppKey Index state */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - uint8_t unicast_addr_count; /*!< The count of unicast address */ - uint16_t *unicast_addr; /*!< Unicast address list */ + uint16_t multicast_addr; /*!< Multicast Address state */ + uint16_t app_idx; /*!< AppKey Index state */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + uint8_t unicast_addr_count; /*!< The count of unicast address */ + uint16_t *unicast_addr; /*!< Unicast address list */ - uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ -} esp_ble_mesh_cancel_transfer_t; /*!< Parameters of cancel transfer message */ + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ +} esp_ble_mesh_cancel_transfer_t __attribute__((deprecated)); /*!< Parameters of cancel transfer message */ /** * @brief BLOB Transfer Client model procedure result @@ -193,113 +228,113 @@ typedef struct { typedef union { /** Retrieve capabilities status */ struct { - int error_code; /*!< Result of starting Retrieve Capabilities procedure */ - esp_ble_mesh_retrieve_capabilities_t input; /*!< Input of starting Retrieve Capabilities procedure */ - } retrieve_capabilities_status; /*!< Retrieve capabilities status */ + int error_code; /*!< Result of starting Retrieve Capabilities procedure */ + esp_ble_mesh_retrieve_capabilities_t input; /*!< Input of starting Retrieve Capabilities procedure */ + } retrieve_capabilities_status; /*!< Retrieve capabilities status */ /** Transfer BLOB status */ struct { - int error_code; /*!< Result of starting Transfer BLOB procedure */ - esp_ble_mesh_transfer_blob_t input; /*!< Input of starting Transfer BLOB procedure */ - } transfer_blob_status; /*!< Transfer BLOB status */ + int error_code; /*!< Result of starting Transfer BLOB procedure */ + esp_ble_mesh_transfer_blob_t input; /*!< Input of starting Transfer BLOB procedure */ + } transfer_blob_status; /*!< Transfer BLOB status */ /** Send block status */ struct { - int error_code; /*!< Result of starting Send Block sub-procedure */ - esp_ble_mesh_send_block_t input; /*!< Input of starting Send Block sub-procedure */ - } send_block_status; /*!< Send block status */ + int error_code; /*!< Result of starting Send Block sub-procedure */ + esp_ble_mesh_send_block_t input; /*!< Input of starting Send Block sub-procedure */ + } send_block_status; /*!< Send block status */ /** Send data status */ struct { - int error_code; /*!< Result of starting Send Data sub-procedure */ - esp_ble_mesh_send_data_t input; /*!< Input of starting Send Data sub-procedure */ - } send_data_status; /*!< Send data status */ + int error_code; /*!< Result of starting Send Data sub-procedure */ + esp_ble_mesh_send_data_t input; /*!< Input of starting Send Data sub-procedure */ + } send_data_status; /*!< Send data status */ /** Determine block status */ struct { - int error_code; /*!< Result of starting Determine Block Status sub-procedure */ - esp_ble_mesh_determine_block_status_t input; /*!< Input of starting Determine Block Status sub-procedure */ - } determine_block_status_status; /*!< Determine block status */ + int error_code; /*!< Result of starting Determine Block Status sub-procedure */ + esp_ble_mesh_determine_block_status_t input; /*!< Input of starting Determine Block Status sub-procedure */ + } determine_block_status_status; /*!< Determine block status */ /** Determine transfer status */ struct { - int error_code; /*!< Result of starting Determine Transfer Status procedure */ - esp_ble_mesh_determine_transfer_status_t input; /*!< Input of starting Determine Transfer Status procedure */ - } determine_transfer_status_status; /*!< Determine transfer status */ + int error_code; /*!< Result of starting Determine Transfer Status procedure */ + esp_ble_mesh_determine_transfer_status_t input; /*!< Input of starting Determine Transfer Status procedure */ + } determine_transfer_status_status; /*!< Determine transfer status */ /** Cancel transfer status */ struct { - int error_code; /*!< Result of starting Cancel Transfer procedure */ - esp_ble_mesh_cancel_transfer_t input; /*!< Input of starting Cancel Transfer procedure */ - } cancel_transfer_status; /*!< Cancel transfer status */ + int error_code; /*!< Result of starting Cancel Transfer procedure */ + esp_ble_mesh_cancel_transfer_t input; /*!< Input of starting Cancel Transfer procedure */ + } cancel_transfer_status; /*!< Cancel transfer status */ /** Retrieve capabilities complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Retrieve Capabilities procedure */ - } retrieve_capabilities_comp; /*!< Retrieve capabilities complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Retrieve Capabilities procedure */ + } retrieve_capabilities_comp; /*!< Retrieve capabilities complete */ /** Transfer BLOB complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Transfer BLOB procedure */ - } transfer_blob_comp; /*!< Transfer BLOB complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Transfer BLOB procedure */ + } transfer_blob_comp; /*!< Transfer BLOB complete */ /** Send block complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Send Block sub-procedure */ - } send_block_comp; /*!< Send block complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Send Block sub-procedure */ + } send_block_comp; /*!< Send block complete */ /** Send data complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Send Data sub-procedure */ - } send_data_comp; /*!< Send data complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Send Data sub-procedure */ + } send_data_comp; /*!< Send data complete */ /** Determine block status complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Determine Block Status sub-procedure */ - } determine_block_status_comp; /*!< Determine block status complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Determine Block Status sub-procedure */ + } determine_block_status_comp; /*!< Determine block status complete */ /** Determine transfer status complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Determine Transfer Status procedure */ - } determine_transfer_status_comp; /*!< Determine transfer status complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Determine Transfer Status procedure */ + } determine_transfer_status_comp; /*!< Determine transfer status complete */ /** Cancel transfer complete */ struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t result; /*!< Result of Cancel Transfer procedure */ - } cancel_transfer_comp; /*!< Cancel transfer complete */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t result; /*!< Result of Cancel Transfer procedure */ + } cancel_transfer_comp; /*!< Cancel transfer complete */ /** Set transfer TTL */ struct { - int error_code; /*!< Result of setting Transfer TTL state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ - } set_transfer_ttl; /*!< Set transfer TTL */ + int error_code; /*!< Result of setting Transfer TTL state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ + } set_transfer_ttl; /*!< Set transfer TTL */ /** Clear transfer TTL */ struct { - int error_code; /*!< Result of clearing Transfer TTL state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - } clear_transfer_ttl; /*!< Clear transfer TTL */ + int error_code; /*!< Result of clearing Transfer TTL state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + } clear_transfer_ttl; /*!< Clear transfer TTL */ /** Set application index */ struct { - int error_code; /*!< Result of setting AppKey Index state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint16_t app_idx; /*!< AppKey Index state */ - } set_app_idx; /*!< Set application index */ + int error_code; /*!< Result of setting AppKey Index state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint16_t app_idx; /*!< AppKey Index state */ + } set_app_idx; /*!< Set application index */ /** Clear application index */ struct { - int error_code; /*!< Result of clearing AppKey Index state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - } clear_app_idx; /*!< Clear application index */ + int error_code; /*!< Result of clearing AppKey Index state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + } clear_app_idx; /*!< Clear application index */ /** Set multicast address */ struct { - int error_code; /*!< Result of setting Multicast Address state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint16_t multicast_addr; /*!< Multicast Address state */ - } set_multicast_addr; /*!< Set multicast address */ + int error_code; /*!< Result of setting Multicast Address state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + uint16_t multicast_addr; /*!< Multicast Address state */ + } set_multicast_addr; /*!< Set multicast address */ /** Clear multicast address */ struct { - int error_code; /*!< Result of clearing Multicast Address state */ - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - } clear_multicast_addr; /*!< Clear multicast address */ -} esp_ble_mesh_mbt_client_cb_value_t; /*!< BLOB Transfer Client model callback values union */ + int error_code; /*!< Result of clearing Multicast Address state */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + } clear_multicast_addr; /*!< Clear multicast address */ +} esp_ble_mesh_mbt_client_cb_value_t; /*!< BLOB Transfer Client model callback values union */ /** BLOB Transfer Client model callback parameters */ typedef struct { - esp_ble_mesh_mbt_client_cb_value_t value; /*!< BLOB Transfer Client model callback values */ -} esp_ble_mesh_mbt_client_cb_param_t; /*!< BLOB Transfer Client model callback parameters */ + esp_ble_mesh_mbt_client_cb_value_t value; /*!< BLOB Transfer Client model callback values */ +} esp_ble_mesh_mbt_client_cb_param_t __attribute__((deprecated)); /*!< BLOB Transfer Client model callback parameters */ /** * This enum value is the event of BLOB Transfer Client model. @@ -327,30 +362,30 @@ typedef enum { ESP_BLE_MESH_MBT_CLIENT_SET_MULTICAST_ADDR_COMP_EVT, ESP_BLE_MESH_MBT_CLIENT_CLEAR_MULTICAST_ADDR_COMP_EVT, ESP_BLE_MESH_MBT_CLIENT_EVT_MAX, -} esp_ble_mesh_mbt_client_cb_event_t; +} esp_ble_mesh_mbt_client_cb_event_t __attribute__((deprecated)); /** Parameters of initialize BLOB receive */ typedef struct { - esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ + esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ - uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ - uint16_t timeout; /*!< Timeout */ - uint8_t transfer_ttl; /*!< Transfer TTL state */ -} esp_ble_mesh_initialize_blob_receive_t; /*!< Structure of initialize BLOB receive */ + uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ + uint16_t timeout; /*!< Timeout */ + uint8_t transfer_ttl; /*!< Transfer TTL state */ +} esp_ble_mesh_initialize_blob_receive_t __attribute__((deprecated)); /*!< Structure of initialize BLOB receive */ /** Parameters of cancel BLOB receive */ typedef struct { esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ uint8_t blob_id[ESP_BLE_MESH_BLOB_ID_SIZE]; /*!< BLOB identifier list */ -} esp_ble_mesh_cancel_blob_receive_t;/*!< */ +} esp_ble_mesh_cancel_blob_receive_t __attribute__((deprecated));/*!< */ /** Parameters of cancel BLOB receive */ typedef struct { esp_ble_mesh_model_t *model; /*!< Pointer to the BLOB Transfer Client model */ esp_ble_mesh_blob_capabilities_t caps; /*!< Parameters of BLOB Information Status */ -} esp_ble_mesh_set_blob_capabilities_t;/*!< */ +} esp_ble_mesh_set_blob_capabilities_t __attribute__((deprecated)); /** * @brief BLOB Transfer Server model callback value union @@ -358,61 +393,61 @@ typedef struct { typedef union { /** Initialize BLOB receive complete */ struct { - int error_code; /*!< Result of initializing BLOB receive */ - esp_ble_mesh_initialize_blob_receive_t input; /*!< Input of initializing BLOB receive */ - } initialize_blob_receive_comp; /*!< Initialize BLOB receive complete */ + int error_code; /*!< Result of initializing BLOB receive */ + esp_ble_mesh_initialize_blob_receive_t input; /*!< Input of initializing BLOB receive */ + } initialize_blob_receive_comp; /*!< Initialize BLOB receive complete */ /** Cancel BLOB receive complete */ struct { - int error_code; /*!< Result of canceling BLOB receive */ - esp_ble_mesh_cancel_blob_receive_t input; /*!< Input of canceling BLOB receive */ - } cancel_blob_receive_comp; /*!< Cancel BLOB receive complete */ + int error_code; /*!< Result of canceling BLOB receive */ + esp_ble_mesh_cancel_blob_receive_t input; /*!< Input of canceling BLOB receive */ + } cancel_blob_receive_comp; /*!< Cancel BLOB receive complete */ /** Set BLOB capabilities complete */ struct { - int error_code; /*!< Result of setting BLOB capabilities */ - esp_ble_mesh_set_blob_capabilities_t input; /*!< Input of setting BLOB capabilities */ - } set_blob_capabilities_comp; /*!< Set BLOB capabilities complete */ + int error_code; /*!< Result of setting BLOB capabilities */ + esp_ble_mesh_set_blob_capabilities_t input; /*!< Input of setting BLOB capabilities */ + } set_blob_capabilities_comp; /*!< Set BLOB capabilities complete */ /** BLOB transfer get */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Get message context */ - } blob_transfer_get; /*!< BLOB transfer get */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Get message context */ + } blob_transfer_get; /*!< BLOB transfer get */ /** BLOB transfer start */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Start message context */ - } blob_transfer_start; /*!< BLOB transfer start */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Start message context */ + } blob_transfer_start; /*!< BLOB transfer start */ /** BLOB transfer cancel */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Cancel message context */ - } blob_transfer_cancel; /*!< BLOB transfer cancel */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Transfer Cancel message context */ + } blob_transfer_cancel; /*!< BLOB transfer cancel */ /** BLOB block get */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Get message context */ - } blob_block_get; /*!< BLOB block get */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Get message context */ + } blob_block_get; /*!< BLOB block get */ /** BLOB block start */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Start message context */ - } blob_block_start; /*!< BLOB block start */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Block Start message context */ + } blob_block_start; /*!< BLOB block start */ /** BLOB chunk transfer */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Chunk Transfer message context */ - } blob_chunk_transfer; /*!< BLOB chunk transfer */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Chunk Transfer message context */ + } blob_chunk_transfer; /*!< BLOB chunk transfer */ /** BLOB information get */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Information Get message context */ - } blob_information_get; /*!< BLOB information get */ + esp_ble_mesh_msg_ctx_t ctx; /*!< BLOB Information Get message context */ + } blob_information_get; /*!< BLOB information get */ /** Block receive complete */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB block completely */ - } block_receive_comp; /*!< Block receive complete */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB block completely */ + } block_receive_comp; /*!< Block receive complete */ /** BLOB receive complete */ struct { - esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB completely */ - } blob_receive_comp; /*!< BLOB receive complete */ -} esp_ble_mesh_mbt_server_cb_value_t; /*!< BLOB Transfer Server model callback value union */ + esp_ble_mesh_msg_ctx_t ctx; /*!< Information of receiving BLOB completely */ + } blob_receive_comp; /*!< BLOB receive complete */ +} esp_ble_mesh_mbt_server_cb_value_t __attribute__((deprecated)); /*!< BLOB Transfer Server model callback value union */ /** BLOB Transfer Server model callback parameters */ typedef struct { - esp_ble_mesh_mbt_server_cb_value_t value; /*!< Value of the received blob transfer messages */ -} esp_ble_mesh_mbt_server_cb_param_t; /*!< BLOB Transfer Server model callback parameters */ + esp_ble_mesh_mbt_server_cb_value_t value; /*!< Value of the received blob transfer messages */ +} esp_ble_mesh_mbt_server_cb_param_t __attribute__((deprecated)); /*!< BLOB Transfer Server model callback parameters */ /** This enum value is the event of BLOB Transfer Server model */ typedef enum { @@ -430,7 +465,7 @@ typedef enum { ESP_BLE_MESH_MBT_SERVER_BLOB_RECEIVE_COMP_EVT, ESP_BLE_MESH_MBT_SERVER_BLOB_RECEIVE_TIMEOUT_EVT, ESP_BLE_MESH_MBT_SERVER_EVT_MAX, -} esp_ble_mesh_mbt_server_cb_event_t; +} esp_ble_mesh_mbt_server_cb_event_t __attribute__((deprecated)); /** * @brief BLOB Transfer Client model callback function type @@ -453,96 +488,116 @@ typedef void (* esp_ble_mesh_mbt_server_cb_t)(esp_ble_mesh_mbt_server_cb_event_t /** * @brief Register BLE Mesh BLOB Transfer Client model callback. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] callback: Pointer to the callback function. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_register_mbt_client_callback(esp_ble_mesh_mbt_client_cb_t callback); +esp_err_t esp_ble_mesh_register_mbt_client_callback(esp_ble_mesh_mbt_client_cb_t callback) __attribute__((deprecated)); /** * @brief Register BLE Mesh BLOB Transfer Server model callback. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] callback: Pointer to the callback function. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback); +esp_err_t esp_ble_mesh_register_mbt_server_callback(esp_ble_mesh_mbt_server_cb_t callback) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Retrieve Capabilities procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Retrieve Capabilities procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input); +esp_err_t esp_ble_mesh_mbt_client_retrieve_capabilities(esp_ble_mesh_retrieve_capabilities_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Transfer BLOB procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Transfer BLOB procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input); +esp_err_t esp_ble_mesh_mbt_client_transfer_blob(esp_ble_mesh_transfer_blob_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Send Block sub-procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Send Block sub-procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input); +esp_err_t esp_ble_mesh_mbt_client_send_block(esp_ble_mesh_send_block_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Send Data sub-procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Send Data sub-procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input); +esp_err_t esp_ble_mesh_mbt_client_send_data(esp_ble_mesh_send_data_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Determine Block Status sub-procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Determine Block Status sub-procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input); +esp_err_t esp_ble_mesh_mbt_client_determine_block_status(esp_ble_mesh_determine_block_status_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Determine Transfer Status procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Determine Transfer Status procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input); +esp_err_t esp_ble_mesh_mbt_client_determine_transfer_status(esp_ble_mesh_determine_transfer_status_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client starts Cancel Transfer procedure. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of Cancel Transfer procedure. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input); +esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Client gets BLOB receiver. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] unicast_addr: Unicast address of the BLOB receiver. * @@ -550,21 +605,25 @@ esp_err_t esp_ble_mesh_mbt_client_cancel_transfer(esp_ble_mesh_cancel_transfer_t * */ const esp_ble_mesh_blob_receiver_t *esp_ble_mesh_mbt_client_get_blob_receiver(esp_ble_mesh_model_t *model, - uint16_t unicast_addr); + uint16_t unicast_addr) __attribute__((deprecated)); /** * @brief BLOB Transfer Client gets active BLOB receiver list. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * * @return Active BLOB receiver list on success or NULL on failure. * */ -const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model); +const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_receiver(esp_ble_mesh_model_t *model) __attribute__((deprecated)); /** * @brief BLOB Transfer Client gets BLOB transfer progress. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] unicast_addr: Unicast address of the BLOB receiver. * @param[in] block_percent: Block reception percent to be updated. @@ -576,11 +635,13 @@ const esp_ble_mesh_blob_receiver_t **esp_ble_mesh_mbt_client_get_active_blob_rec esp_err_t esp_ble_mesh_mbt_client_get_transfer_progress(esp_ble_mesh_model_t *model, uint16_t unicast_addr, uint8_t *block_percent, - uint8_t *chunk_percent); + uint8_t *chunk_percent) __attribute__((deprecated)); /** * @brief BLOB Transfer Client sets Transfer TTL state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] transfer_ttl: Transfer TTL state value. * @@ -588,21 +649,25 @@ esp_err_t esp_ble_mesh_mbt_client_get_transfer_progress(esp_ble_mesh_model_t *mo * */ esp_err_t esp_ble_mesh_mbt_client_set_transfer_ttl(esp_ble_mesh_model_t *model, - uint8_t transfer_ttl); + uint8_t transfer_ttl) __attribute__((deprecated)); /** * @brief BLOB Transfer Client clear Transfer TTL state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model); +esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model) __attribute__((deprecated)); /** * @brief BLOB Transfer Client sets AppKey Index state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] app_idx: AppKey Index state value. * @@ -610,21 +675,25 @@ esp_err_t esp_ble_mesh_mbt_client_clear_transfer_ttl(esp_ble_mesh_model_t *model * */ esp_err_t esp_ble_mesh_mbt_client_set_app_idx(esp_ble_mesh_model_t *model, - uint16_t app_idx); + uint16_t app_idx) __attribute__((deprecated)); /** * @brief BLOB Transfer Client clear AppKey Index state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model); +esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model) __attribute__((deprecated)); /** * @brief BLOB Transfer Client sets Multicast Address state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * @param[in] multicast_addr: Multicast Address state value. * @@ -632,51 +701,61 @@ esp_err_t esp_ble_mesh_mbt_client_clear_app_idx(esp_ble_mesh_model_t *model); * */ esp_err_t esp_ble_mesh_mbt_client_set_multicast_addr(esp_ble_mesh_model_t *model, - uint16_t multicast_addr); + uint16_t multicast_addr) __attribute__((deprecated)); /** * @brief BLOB Transfer Client clear Multicast Address state. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Client model. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model); +esp_err_t esp_ble_mesh_mbt_client_clear_multicast_addr(esp_ble_mesh_model_t *model) __attribute__((deprecated)); /** * @brief BLOB Transfer Server initializes BLOB receive. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of initializing BLOB receive. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input); +esp_err_t esp_ble_mesh_mbt_server_initialize_blob_receive(esp_ble_mesh_initialize_blob_receive_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Server cancels BLOB receive. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of cancelling BLOB receive. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input); +esp_err_t esp_ble_mesh_mbt_server_cancel_blob_receive(esp_ble_mesh_cancel_blob_receive_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Server sets BLOB capabilities. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] input: The input of setting BLOB capabilities. * * @return ESP_OK on success or error code otherwise. * */ -esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input); +esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_capabilities_t *input) __attribute__((deprecated)); /** * @brief BLOB Transfer Server gets current BLOB reception progress. * + * @deprecated This function will be deprecated in future versions. + * * @param[in] model: BLOB Transfer Server model. * @param[in] reception_progress: Reception progress to be updated. * @@ -684,7 +763,11 @@ esp_err_t esp_ble_mesh_mbt_server_set_blob_capabilities(esp_ble_mesh_set_blob_ca * */ esp_err_t esp_ble_mesh_mbt_server_get_blob_reception_progress(esp_ble_mesh_model_t *model, - uint8_t *reception_progress); + uint8_t *reception_progress) __attribute__((deprecated)); + +#if CONFIG_IDF_CI_BUILD +#pragma GCC diagnostic pop +#endif #ifdef __cplusplus } diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c new file mode 100644 index 0000000000..91f0ab9d83 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c @@ -0,0 +1,414 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "btc_ble_mesh_model_common.h" +#include "btc_ble_mesh_dfu_model.h" +#include "esp_ble_mesh_dfu_model_api.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/dfu/dfu_srv.h" + +#if CONFIG_BLE_MESH_DFU_CLI +/* Device Firmware Update Client model related functions */ + +static inline void btc_ble_mesh_dfu_client_cb_to_app(btc_ble_mesh_dfu_client_cb_evt_t event, + esp_ble_mesh_dfu_client_cb_param_t *param) +{ + esp_ble_mesh_dfu_client_cb_t btc_ble_mesh_cb = + btc_profile_cb_get(BTC_PID_DFU_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +void btc_ble_mesh_dfu_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_dfu_client_args_t *dst = p_dest; + btc_ble_mesh_dfu_client_args_t *src = p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE: { + dst->dfu_get.params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->dfu_get.params) { + memcpy(dst->dfu_get.params, src->dfu_get.params, + sizeof(esp_ble_mesh_client_common_param_t)); + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + break; + } + if (src->dfu_get.get) { + dst->dfu_get.get = bt_mesh_calloc(sizeof(esp_ble_mesh_dfu_client_get_t)); + if (dst->dfu_get.get) { + memcpy(dst->dfu_get.get, src->dfu_get.get, + sizeof(esp_ble_mesh_dfu_client_get_t)); + if (src->dfu_get.params->opcode == ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK) { + if (src->dfu_get.get->dfu_metadata_check.metadata) { + dst->dfu_get.get->dfu_metadata_check.metadata = bt_mesh_alloc_buf(src->dfu_get.get->dfu_metadata_check.metadata->len); + if (dst->dfu_get.get->dfu_metadata_check.metadata) { + net_buf_simple_add_mem(dst->dfu_get.get->dfu_metadata_check.metadata, + src->dfu_get.get->dfu_metadata_check.metadata->data, + src->dfu_get.get->dfu_metadata_check.metadata->len); + } else { + BT_ERR("Out of memory for metadata"); + return; + } + } else { + BT_ERR("Metadata should be exists"); + return; + } + } + } else { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + } + } + break; + } + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_dfu_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_dfu_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_dfu_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE: + if (arg->dfu_get.params) { + bt_mesh_free(arg->dfu_get.params); + } + if (arg->dfu_get.get) { + bt_mesh_free(arg->dfu_get.get); + } + break; + default: + break; + } +} + +static void btc_ble_mesh_dfu_client_copy_req_data(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_dfu_client_cb_param_t *p_dest_data = p_dest; + esp_ble_mesh_dfu_client_cb_param_t *p_src_data = p_src; + uint16_t length = 0; + + if (!msg || !p_src_data || !p_dest_data) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (p_src_data->params) { + p_dest_data->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (!p_dest_data->params) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + + memcpy(p_dest_data->params, p_src_data->params, sizeof(esp_ble_mesh_client_common_param_t)); + } + + switch (msg->act) { + case ESP_BLE_MESH_DFU_CLIENT_RECV_GET_RSP_EVT: + if (p_src_data->params) { + switch (p_src_data->params->opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + if (p_src_data->recv.dfu_update_info_status.fw_info_list_cnt) { + length = p_src_data->recv.dfu_update_info_status.fw_info_list_cnt * sizeof(esp_ble_mesh_firmware_info_t); + p_dest_data->recv.dfu_update_info_status.fw_info_list = bt_mesh_calloc(length); + if (!p_dest_data->recv.dfu_update_info_status.fw_info_list) { + BT_ERR("%s, Out of memory, act %d", __func__, msg->act); + return; + } + memcpy(p_dest_data->recv.dfu_update_info_status.fw_info_list, + p_src_data->recv.dfu_update_info_status.fw_info_list, + length); + } + break; + default: + break; + } + } + case ESP_BLE_MESH_DFU_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_DFU_CLIENT_TIMEOUT_EVT: + case ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT: + break; + default: + break; + } +} + +static void btc_ble_mesh_dfu_client_free_req_data(btc_msg_t *msg) +{ + esp_ble_mesh_dfu_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (msg->act >= ESP_BLE_MESH_DFU_CLIENT_EVT_MAX) { + BT_ERR("%s, Invalid event %d", msg->act); + return; + } + + arg = (esp_ble_mesh_dfu_client_cb_param_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_DFU_CLIENT_RECV_GET_RSP_EVT: + if (arg->params) { + switch (arg->params->opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + bt_mesh_free(arg->recv.dfu_update_info_status.fw_info_list); + break; + default: + break; + } + } + case ESP_BLE_MESH_DFU_CLIENT_SEND_COMP_EVT: + case ESP_BLE_MESH_DFU_CLIENT_TIMEOUT_EVT: + case ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT: + break; + default: + BT_WARN("Unprocessed event %d", msg->act); + break; + } + + if (arg->params) { + bt_mesh_free(arg->params); + } + + return; +} + +static void btc_ble_mesh_dfu_client_cb(esp_ble_mesh_dfu_client_cb_param_t *cb_params, uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_DFU_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_DFU_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, sizeof(esp_ble_mesh_dfu_client_cb_param_t), + btc_ble_mesh_dfu_client_copy_req_data, + btc_ble_mesh_dfu_client_free_req_data); +} + +void bt_mesh_dfu_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_dfu_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0; + + if (!model || !ctx || len > sizeof(cb_params.recv)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_DFU_CLIENT_TIMEOUT: + act = ESP_BLE_MESH_DFU_CLIENT_TIMEOUT_EVT; + break; + case BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP: + act = ESP_BLE_MESH_DFU_CLIENT_RECV_GET_RSP_EVT; + break; + case BTC_BLE_MESH_EVT_DFU_CLIENT_IMG_SEND_CMP: + act = ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT; + break; + default: + BT_ERR("Unknown Device Firmware Update client event type %d", event); + return; + } + + params.opcode = opcode; + params.model = (esp_ble_mesh_model_t *)model; + params.ctx.net_idx = ctx->net_idx; + params.ctx.app_idx = ctx->app_idx; + params.ctx.addr = ctx->addr; + params.ctx.recv_ttl = ctx->recv_ttl; + params.ctx.recv_op = ctx->recv_op; + params.ctx.recv_dst = ctx->recv_dst; + params.ctx.recv_rssi = ctx->recv_rssi; + params.ctx.send_ttl = ctx->send_ttl; + + cb_params.params = ¶ms; + + if (val && len) { + memcpy(&cb_params.recv, val, len); + } + + btc_ble_mesh_dfu_client_cb(&cb_params, act); +} + +static int btc_ble_mesh_dfu_client_get_state(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfu_client_get_t *get) +{ + bt_mesh_client_common_param_t param = {0}; + struct bt_mesh_dfu_cli *dfu_cli = NULL; + + if (params == NULL || + params->model == NULL || + params->model->user_data == NULL) { + BT_ERR("%s, Invalid parameter %d %p %p", __func__, params == NULL, params->model, params->model->user_data); + return -EINVAL; + } + + dfu_cli = (struct bt_mesh_dfu_cli *)params->model->user_data; + + switch (params->opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + case ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK: + case ESP_BLE_MESH_DFU_OP_UPDATE_START: + if (get == NULL) { + BT_ERR("Invalid Device Firmware Update Get"); + return -EINVAL; + } + break; + default: + break; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, false); + + switch (param.opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_INFO_GET: + return bt_mesh_dfu_cli_imgs_get(dfu_cli, ¶m.ctx, (bt_mesh_dfu_img_cb_t) get->dfu_update_info_get.img_cb, + NULL, get->dfu_update_info_get.first_index, + get->dfu_update_info_get.entries_limit); + case ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK: + return bt_mesh_dfu_cli_metadata_check(dfu_cli, ¶m.ctx, get->dfu_metadata_check.update_firmware_index, + get->dfu_metadata_check.metadata); + case ESP_BLE_MESH_DFU_OP_UPDATE_GET: + return bt_mesh_dfu_cli_status_get(dfu_cli, ¶m.ctx); + case ESP_BLE_MESH_DFU_OP_UPDATE_START: + // automatic start + return 0; + case ESP_BLE_MESH_DFU_OP_UPDATE_CANCEL: + return bt_mesh_dfu_cli_cancel(dfu_cli, ¶m.ctx); + case ESP_BLE_MESH_DFU_OP_UPDATE_APPLY: + return bt_mesh_dfu_cli_apply(dfu_cli); + default: + BT_ERR("Invalid Device firmware Get opcode 0x%04x", param.opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_dfu_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_dfu_client_cb_param_t cb = {0}; + btc_ble_mesh_dfu_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (btc_ble_mesh_dfu_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE: + cb.params = arg->dfu_get.params; + cb.send.err_code = btc_ble_mesh_dfu_client_get_state(arg->dfu_get.params, + arg->dfu_get.get); + btc_ble_mesh_dfu_client_cb(&cb, + ESP_BLE_MESH_DFU_CLIENT_SEND_COMP_EVT); + break; + case BTC_BLE_MESH_ACT_DFU_CLIENT_IMG_SEND: + cb.send.err_code = bt_mesh_dfu_cli_send((struct bt_mesh_dfu_cli *)arg->send_arg.cli, + (struct bt_mesh_blob_cli_inputs *)arg->send_arg.inputs, + (struct bt_mesh_blob_io *)arg->send_arg.io, + (struct bt_mesh_dfu_cli_xfer *)arg->send_arg.xfer); + btc_ble_mesh_dfu_client_cb(&cb, + ESP_BLE_MESH_DFU_CLIENT_IMG_SEND_CMP_EVT); + break; + default: + break; + } + + btc_ble_mesh_dfu_client_arg_deep_free(msg); +} + +void btc_ble_mesh_dfu_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_dfu_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_dfu_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_DFU_CLIENT_EVT_MAX) { + btc_ble_mesh_dfu_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_dfu_client_free_req_data(msg); +} + +uint8_t btc_ble_mesh_dfu_cli_progress(struct esp_ble_mesh_dfu_cli *cli) +{ + return bt_mesh_dfu_cli_progress((struct bt_mesh_dfu_cli *)cli); +} + +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV + +void btc_ble_mesh_dfu_srv_verified(esp_ble_mesh_dfu_srv_t *srv) +{ + bt_mesh_dfu_srv_verified((struct bt_mesh_dfu_srv *)srv); +} + +void btc_ble_mesh_dfu_srv_rejected(esp_ble_mesh_dfu_srv_t *srv) +{ + bt_mesh_dfu_srv_rejected((struct bt_mesh_dfu_srv *)srv); +} + +void btc_ble_mesh_dfu_srv_cancel(esp_ble_mesh_dfu_srv_t *srv) +{ + bt_mesh_dfu_srv_cancel((struct bt_mesh_dfu_srv *)srv); +} + +void btc_ble_mesh_dfu_srv_applied(esp_ble_mesh_dfu_srv_t *srv) +{ + bt_mesh_dfu_srv_applied((struct bt_mesh_dfu_srv *)srv); +} + +bool btc_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv) +{ + return bt_mesh_dfu_srv_is_busy((struct bt_mesh_dfu_srv *)srv); +} + +uint8_t btc_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv) +{ + return bt_mesh_dfu_srv_progress((struct bt_mesh_dfu_srv *)srv); +} +#endif /* CONFIG_BLE_MESH_DFU_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_slot.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_slot.c new file mode 100644 index 0000000000..1c92a05567 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_slot.c @@ -0,0 +1,79 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "dfu_slot.h" +#include "esp_ble_mesh_dfu_model_api.h" +#include "esp_ble_mesh_dfu_slot_api.h" +#include "btc_ble_mesh_dfu_slot.h" + +#if CONFIG_BLE_MESH_DFU_SLOTS +int btc_ble_mesh_dfu_slot_count(void) +{ + return bt_mesh_dfu_slot_count(); +} + +struct esp_ble_mesh_dfu_slot *btc_ble_mesh_dfu_slot_reserve(void) +{ + return (struct esp_ble_mesh_dfu_slot *)bt_mesh_dfu_slot_reserve(); +} + +int btc_ble_mesh_dfu_slot_info_set(struct esp_ble_mesh_dfu_slot *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len) +{ + return bt_mesh_dfu_slot_info_set((struct bt_mesh_dfu_slot *) dfu_slot, size, + metadata, metadata_len); +} + +int btc_ble_mesh_dfu_slot_fwid_set(struct esp_ble_mesh_dfu_slot *dfu_slot, + const uint8_t *fwid, size_t fwid_len) +{ + return bt_mesh_dfu_slot_fwid_set((struct bt_mesh_dfu_slot *) dfu_slot, fwid, + fwid_len); +} + +int btc_ble_mesh_dfu_slot_commit(struct esp_ble_mesh_dfu_slot *dfu_slot) +{ + return bt_mesh_dfu_slot_commit((struct bt_mesh_dfu_slot *) dfu_slot); +} + +void btc_ble_mesh_dfu_slot_release(const struct esp_ble_mesh_dfu_slot *dfu_slot) +{ + bt_mesh_dfu_slot_release((const struct bt_mesh_dfu_slot *)dfu_slot); +} + +int btc_ble_mesh_dfu_slot_del(const struct esp_ble_mesh_dfu_slot *slot) +{ + return bt_mesh_dfu_slot_del((const struct bt_mesh_dfu_slot *)slot); +} + +void btc_ble_mesh_dfu_slot_del_all(void) +{ + bt_mesh_dfu_slot_del_all(); +} + +const struct esp_ble_mesh_dfu_slot *btc_ble_mesh_dfu_slot_at(uint16_t img_idx) +{ + return (const struct esp_ble_mesh_dfu_slot *)bt_mesh_dfu_slot_at(img_idx); +} + +int btc_ble_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, struct esp_ble_mesh_dfu_slot **slot) +{ + return bt_mesh_dfu_slot_get(fwid, fwid_len, (struct bt_mesh_dfu_slot **)slot); +} + +int btc_ble_mesh_dfu_slot_img_idx_get(const struct esp_ble_mesh_dfu_slot *slot) +{ + return bt_mesh_dfu_slot_img_idx_get((const struct bt_mesh_dfu_slot *)slot); +} + +size_t btc_ble_mesh_dfu_slot_foreach(esp_ble_mesh_dfu_slot_cb_t cb, void *user_data) +{ + return bt_mesh_dfu_slot_foreach((bt_mesh_dfu_slot_cb_t)cb, user_data); +} +#endif /* CONFIG_BLE_MESH_DFU_SLOTS */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h new file mode 100644 index 0000000000..a74aeb5453 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h @@ -0,0 +1,74 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_DFU_MODEL_H_ +#define _BTC_BLE_MESH_DFU_MODEL_H_ + +#include "btc/btc_manage.h" +#include "esp_ble_mesh_dfu_model_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if CONFIG_BLE_MESH_DFU_CLI +typedef enum { + BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE, + BTC_BLE_MESH_ACT_DFU_CLIENT_IMG_SEND, + BTC_BLE_MESH_ACT_DFU_CLIENT_MAX, +} btc_ble_mesh_dfu_client_act_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_dfu_client_get_t *get; + } dfu_get; + struct { + struct esp_ble_mesh_dfu_cli *cli; + struct esp_ble_mesh_blob_cli_inputs *inputs; + struct esp_ble_mesh_blob_io *io; + struct esp_ble_mesh_dfu_cli_xfer *xfer; + } send_arg; +} btc_ble_mesh_dfu_client_args_t; + +typedef enum { + BTC_BLE_MESH_EVT_DFU_CLIENT_TIMEOUT, + BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP, + BTC_BLE_MESH_EVT_DFU_CLIENT_IMG_SEND_CMP, + BTC_BLE_MESH_EVT_DFU_CLIENT_MAX, +} btc_ble_mesh_dfu_client_cb_evt_t; + +void btc_ble_mesh_dfu_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); +void btc_ble_mesh_dfu_client_arg_deep_free(btc_msg_t *msg); +void bt_mesh_dfu_client_cb_evt_to_btc(uint32_t opcode, uint8_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); +void btc_ble_mesh_dfu_client_call_handler(btc_msg_t *msg); +void btc_ble_mesh_dfu_client_cb_handler(btc_msg_t *msg); +uint8_t btc_ble_mesh_dfu_cli_progress(struct esp_ble_mesh_dfu_cli *cli); +#endif /* CONFIG_BLE_MESH_DFU_CLI */ + +#if CONFIG_BLE_MESH_DFU_SRV + +void btc_ble_mesh_dfu_srv_verified(esp_ble_mesh_dfu_srv_t *srv); + +void btc_ble_mesh_dfu_srv_rejected(esp_ble_mesh_dfu_srv_t *srv); + +void btc_ble_mesh_dfu_srv_cancel(esp_ble_mesh_dfu_srv_t *srv); + +void btc_ble_mesh_dfu_srv_applied(esp_ble_mesh_dfu_srv_t *srv); + +bool btc_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv); + +uint8_t btc_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv); +#endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BTC_BLE_MESH_DFU_MODEL_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_slot.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_slot.h new file mode 100644 index 0000000000..90867586c9 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_slot.h @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BTC_BLE_MESH_DFU_SLOT_H_ +#define _BTC_BLE_MESH_DFU_SLOT_H_ + +int btc_ble_mesh_dfu_slot_count(void); + +struct esp_ble_mesh_dfu_slot *btc_ble_mesh_dfu_slot_reserve(void); + +int btc_ble_mesh_dfu_slot_info_set(struct esp_ble_mesh_dfu_slot *dfu_slot, size_t size, + const uint8_t *metadata, size_t metadata_len); + +int btc_ble_mesh_dfu_slot_fwid_set(struct esp_ble_mesh_dfu_slot *dfu_slot, + const uint8_t *fwid, size_t fwid_len); + +int btc_ble_mesh_dfu_slot_commit(struct esp_ble_mesh_dfu_slot *dfu_slot); + +void btc_ble_mesh_dfu_slot_release(const struct esp_ble_mesh_dfu_slot *dfu_slot); + +int btc_ble_mesh_dfu_slot_del(const struct esp_ble_mesh_dfu_slot *slot); + +void btc_ble_mesh_dfu_slot_del_all(void); + +const struct esp_ble_mesh_dfu_slot *btc_ble_mesh_dfu_slot_at(uint16_t img_idx); + +int btc_ble_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, struct esp_ble_mesh_dfu_slot **slot); + +int btc_ble_mesh_dfu_slot_img_idx_get(const struct esp_ble_mesh_dfu_slot *slot); + +size_t btc_ble_mesh_dfu_slot_foreach(esp_ble_mesh_dfu_slot_cb_t cb, void *user_data); + +#endif /* _BTC_BLE_MESH_DFU_SLOT_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h index 070888ca55..4bb82ed1a3 100644 --- a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_mbt_model.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +14,11 @@ extern "C" { #endif +#if CONFIG_IDF_CI_BUILD +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + typedef enum { BTC_BLE_MESH_ACT_MBT_CLIENT_RETRIEVE_CAPABILITIES, BTC_BLE_MESH_ACT_MBT_CLIENT_TRANSFER_BLOB, @@ -136,6 +141,10 @@ void bt_mesh_mbt_server_cb_evt_to_btc(uint8_t event, struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx); +#if CONFIG_IDF_CI_BUILD +#pragma GCC diagnostic pop +#endif + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h index 3af9af7214..ee94be24e6 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h @@ -1,29 +1,35 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#define BT_MESH_DFD_OP_RECEIVERS_ADD BT_MESH_MODEL_OP_2(0x83, 0x11) -#define BT_MESH_DFD_OP_RECEIVERS_DELETE_ALL BT_MESH_MODEL_OP_2(0x83, 0x12) -#define BT_MESH_DFD_OP_RECEIVERS_STATUS BT_MESH_MODEL_OP_2(0x83, 0x13) -#define BT_MESH_DFD_OP_RECEIVERS_GET BT_MESH_MODEL_OP_2(0x83, 0x14) -#define BT_MESH_DFD_OP_RECEIVERS_LIST BT_MESH_MODEL_OP_2(0x83, 0x15) -#define BT_MESH_DFD_OP_CAPABILITIES_GET BT_MESH_MODEL_OP_2(0x83, 0x16) -#define BT_MESH_DFD_OP_CAPABILITIES_STATUS BT_MESH_MODEL_OP_2(0x83, 0x17) -#define BT_MESH_DFD_OP_GET BT_MESH_MODEL_OP_2(0x83, 0x18) -#define BT_MESH_DFD_OP_START BT_MESH_MODEL_OP_2(0x83, 0x19) -#define BT_MESH_DFD_OP_SUSPEND BT_MESH_MODEL_OP_2(0x83, 0x1a) -#define BT_MESH_DFD_OP_CANCEL BT_MESH_MODEL_OP_2(0x83, 0x1b) -#define BT_MESH_DFD_OP_APPLY BT_MESH_MODEL_OP_2(0x83, 0x1c) -#define BT_MESH_DFD_OP_STATUS BT_MESH_MODEL_OP_2(0x83, 0x1d) -#define BT_MESH_DFD_OP_UPLOAD_GET BT_MESH_MODEL_OP_2(0x83, 0x1e) -#define BT_MESH_DFD_OP_UPLOAD_START BT_MESH_MODEL_OP_2(0x83, 0x1f) -#define BT_MESH_DFD_OP_UPLOAD_START_OOB BT_MESH_MODEL_OP_2(0x83, 0x20) -#define BT_MESH_DFD_OP_UPLOAD_CANCEL BT_MESH_MODEL_OP_2(0x83, 0x21) -#define BT_MESH_DFD_OP_UPLOAD_STATUS BT_MESH_MODEL_OP_2(0x83, 0x22) -#define BT_MESH_DFD_OP_FW_GET BT_MESH_MODEL_OP_2(0x83, 0x23) -#define BT_MESH_DFD_OP_FW_GET_BY_INDEX BT_MESH_MODEL_OP_2(0x83, 0x24) -#define BT_MESH_DFD_OP_FW_DELETE BT_MESH_MODEL_OP_2(0x83, 0x25) -#define BT_MESH_DFD_OP_FW_DELETE_ALL BT_MESH_MODEL_OP_2(0x83, 0x26) -#define BT_MESH_DFD_OP_FW_STATUS BT_MESH_MODEL_OP_2(0x83, 0x27) +#include "access.h" + +/* @todo: adapt to dfd client */ +#if CONFIG_BLE_MESH_DFD_SRV +#define BT_MESH_DFD_OP_RECEIVERS_ADD BLE_MESH_MODEL_OP_2(0x83, 0x11) +#define BT_MESH_DFD_OP_RECEIVERS_DELETE_ALL BLE_MESH_MODEL_OP_2(0x83, 0x12) +#define BT_MESH_DFD_OP_RECEIVERS_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x13) +#define BT_MESH_DFD_OP_RECEIVERS_GET BLE_MESH_MODEL_OP_2(0x83, 0x14) +#define BT_MESH_DFD_OP_RECEIVERS_LIST BLE_MESH_MODEL_OP_2(0x83, 0x15) +#define BT_MESH_DFD_OP_CAPABILITIES_GET BLE_MESH_MODEL_OP_2(0x83, 0x16) +#define BT_MESH_DFD_OP_CAPABILITIES_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x17) +#define BT_MESH_DFD_OP_GET BLE_MESH_MODEL_OP_2(0x83, 0x18) +#define BT_MESH_DFD_OP_START BLE_MESH_MODEL_OP_2(0x83, 0x19) +#define BT_MESH_DFD_OP_SUSPEND BLE_MESH_MODEL_OP_2(0x83, 0x1a) +#define BT_MESH_DFD_OP_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x1b) +#define BT_MESH_DFD_OP_APPLY BLE_MESH_MODEL_OP_2(0x83, 0x1c) +#define BT_MESH_DFD_OP_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x1d) +#define BT_MESH_DFD_OP_UPLOAD_GET BLE_MESH_MODEL_OP_2(0x83, 0x1e) +#define BT_MESH_DFD_OP_UPLOAD_START BLE_MESH_MODEL_OP_2(0x83, 0x1f) +#define BT_MESH_DFD_OP_UPLOAD_START_OOB BLE_MESH_MODEL_OP_2(0x83, 0x20) +#define BT_MESH_DFD_OP_UPLOAD_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x21) +#define BT_MESH_DFD_OP_UPLOAD_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x22) +#define BT_MESH_DFD_OP_FW_GET BLE_MESH_MODEL_OP_2(0x83, 0x23) +#define BT_MESH_DFD_OP_FW_GET_BY_INDEX BLE_MESH_MODEL_OP_2(0x83, 0x24) +#define BT_MESH_DFD_OP_FW_DELETE BLE_MESH_MODEL_OP_2(0x83, 0x25) +#define BT_MESH_DFD_OP_FW_DELETE_ALL BLE_MESH_MODEL_OP_2(0x83, 0x26) +#define BT_MESH_DFD_OP_FW_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x27) +#endif diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c index 4a395a175b..7821b21b88 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c @@ -1,1306 +1,1311 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ - #include -#include -#include #include "dfu_slot.h" #include "dfd.h" #include "dfu.h" #include "dfd_srv_internal.h" #include "net.h" #include "transport.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/dfu/dfd_srv.h" +#include "mesh_v1.1/mbt/blob_srv.h" -#define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL -#include -LOG_MODULE_REGISTER(bt_mesh_dfd_srv); +#if CONFIG_BLE_MESH_DFD_SRV +#define DFD_UPLOAD_STATUS_MSG_MAXLEN (5 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN) -#define ERASE_BLOCK_SIZE DT_PROP(DT_CHOSEN(zephyr_flash), erase_block_size) +_Static_assert((DFD_UPLOAD_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_UPLOAD_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The Firmware Distribution Upload Status message does not fit into the maximum " + "outgoing SDU size."); -#define DFD_UPLOAD_STATUS_MSG_MAXLEN (5 + CONFIG_BT_MESH_DFU_FWID_MAXLEN) +#define DFD_UPLOAD_START_MSG_MAXLEN (16 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN + \ + CONFIG_BLE_MESH_DFU_METADATA_MAXLEN) -BUILD_ASSERT((DFD_UPLOAD_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_UPLOAD_STATUS) + - BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, - "The Firmware Distribution Upload Status message does not fit into the maximum " - "outgoing SDU size."); +_Static_assert((DFD_UPLOAD_START_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_UPLOAD_START) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The Firmware Distribution Upload Start message does not fit into the maximum " + "incoming SDU size."); -#define DFD_UPLOAD_START_MSG_MAXLEN (16 + CONFIG_BT_MESH_DFU_FWID_MAXLEN + \ - CONFIG_BT_MESH_DFU_METADATA_MAXLEN) +#define DFD_RECEIVERS_LIST_MSG_MAXLEN (4 + CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX * 5) -BUILD_ASSERT((DFD_UPLOAD_START_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_UPLOAD_START) + - BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, - "The Firmware Distribution Upload Start message does not fit into the maximum " - "incoming SDU size."); +_Static_assert((DFD_RECEIVERS_LIST_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_RECEIVERS_LIST) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The Firmware Distribution Receivers List message does not fit into the maximum " + "outgoing SDU size."); -#define DFD_RECEIVERS_LIST_MSG_MAXLEN (4 + CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX * 5) +#define DFD_RECEIVERS_ADD_MSG_MAXLEN (CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX * 3) -BUILD_ASSERT((DFD_RECEIVERS_LIST_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_RECEIVERS_LIST) + - BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, - "The Firmware Distribution Receivers List message does not fit into the maximum " - "outgoing SDU size."); - -#define DFD_RECEIVERS_ADD_MSG_MAXLEN (CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX * 3) - -BUILD_ASSERT((DFD_RECEIVERS_ADD_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_RECEIVERS_ADD) + - BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, - "The Firmware Distribution Receivers Add message does not fit into the maximum " - "incoming SDU size."); +_Static_assert((DFD_RECEIVERS_ADD_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_RECEIVERS_ADD) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The Firmware Distribution Receivers Add message does not fit into the maximum " + "incoming SDU size."); struct slot_search_ctx { - off_t offset; - size_t size; - bool failed; + off_t offset; + size_t size; + bool failed; }; static void dfd_phase_set(struct bt_mesh_dfd_srv *srv, - enum bt_mesh_dfd_phase new_phase) + enum bt_mesh_dfd_phase new_phase) { - srv->phase = new_phase; + srv->phase = new_phase; - if (srv->cb && srv->cb->phase) { - srv->cb->phase(srv, srv->phase); - } + if (srv->cb && srv->cb->phase) { + srv->cb->phase(srv, srv->phase); + } } static struct bt_mesh_dfu_target *target_get(struct bt_mesh_dfd_srv *srv, - uint16_t addr) + uint16_t addr) { - for (int i = 0; i < srv->target_cnt; ++i) { - if (addr == srv->targets[i].blob.addr) { - return &srv->targets[i]; - } - } + for (int i = 0; i < srv->target_cnt; ++i) { + if (addr == srv->targets[i].blob.addr) { + return &srv->targets[i]; + } + } - return NULL; + return NULL; } static bool is_busy(const struct bt_mesh_dfd_srv *srv) { - return srv->phase == BT_MESH_DFD_PHASE_TRANSFER_ACTIVE || - srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUCCESS || - srv->phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE; + return srv->phase == BT_MESH_DFD_PHASE_TRANSFER_ACTIVE || + srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUCCESS || + srv->phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE; } static bool upload_is_busy(const struct bt_mesh_dfd_srv *srv) { - return bt_mesh_blob_srv_is_busy(&srv->upload.blob) || - srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + return bt_mesh_blob_srv_is_busy(&srv->upload.blob) || + srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; } static int slot_del(struct bt_mesh_dfd_srv *srv, const struct bt_mesh_dfu_slot *slot) { - if (srv->cb && srv->cb->del) { - srv->cb->del(srv, slot); - } + if (srv->cb && srv->cb->del) { + srv->cb->del(srv, slot); + } - return bt_mesh_dfu_slot_del(slot); + return bt_mesh_dfu_slot_del(slot); } static void receivers_status_rsp(struct bt_mesh_dfd_srv *srv, - struct bt_mesh_msg_ctx *ctx, - enum bt_mesh_dfd_status status) + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFD_OP_RECEIVERS_STATUS, 3); - bt_mesh_model_msg_init(&buf, BT_MESH_DFD_OP_RECEIVERS_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFD_OP_RECEIVERS_STATUS, 3); + bt_mesh_model_msg_init(&buf, BT_MESH_DFD_OP_RECEIVERS_STATUS); - net_buf_simple_add_u8(&buf, status); - net_buf_simple_add_le16(&buf, srv->target_cnt); + net_buf_simple_add_u8(&buf, status); + net_buf_simple_add_le16(&buf, srv->target_cnt); - bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); + bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); } static int handle_receivers_add(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - enum bt_mesh_dfd_status status = BT_MESH_DFD_SUCCESS; - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + enum bt_mesh_dfd_status status = BT_MESH_DFD_SUCCESS; + struct bt_mesh_dfd_srv *srv = mod->user_data; - if (buf->len % 3) { - return -EINVAL; - } + if (buf->len % 3) { + return -EINVAL; + } - if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { - receivers_status_rsp(srv, ctx, - BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION); - return 0; - } + if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { + receivers_status_rsp(srv, ctx, + BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION); + return 0; + } - while (buf->len >= 3 && status == BT_MESH_DFD_SUCCESS) { - uint8_t img_idx; - uint16_t addr; + while (buf->len >= 3 && status == BT_MESH_DFD_SUCCESS) { + uint8_t img_idx; + uint16_t addr; - addr = net_buf_simple_pull_le16(buf); - img_idx = net_buf_simple_pull_u8(buf); + addr = net_buf_simple_pull_le16(buf); + img_idx = net_buf_simple_pull_u8(buf); - status = bt_mesh_dfd_srv_receiver_add(srv, addr, img_idx); - } + status = bt_mesh_dfd_srv_receiver_add(srv, addr, img_idx); + } - receivers_status_rsp(srv, ctx, status); + receivers_status_rsp(srv, ctx, status); - return 0; + return 0; } static int handle_receivers_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - receivers_status_rsp(srv, ctx, bt_mesh_dfd_srv_receivers_delete_all(srv)); + receivers_status_rsp(srv, ctx, bt_mesh_dfd_srv_receivers_delete_all(srv)); - return 0; + return 0; } static int handle_receivers_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; - uint16_t first, cnt; - uint8_t progress; - int i; + struct bt_mesh_dfd_srv *srv = mod->user_data; + uint16_t first, cnt; + uint8_t progress; + int i; - first = net_buf_simple_pull_le16(buf); - cnt = net_buf_simple_pull_le16(buf); - if (cnt == 0) { - return -EINVAL; - } + first = net_buf_simple_pull_le16(buf); + cnt = net_buf_simple_pull_le16(buf); + if (cnt == 0) { + return -EINVAL; + } - /* Create a buffer that can fit the full target list, maxing out at TX_SDU_MAX: */ - NET_BUF_SIMPLE_DEFINE( - rsp, BT_MESH_MODEL_BUF_LEN(BT_MESH_DFD_OP_RECEIVERS_LIST, - DFD_RECEIVERS_LIST_MSG_MAXLEN)); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_RECEIVERS_LIST); + /* Create a buffer that can fit the full target list, maxing out at TX_SDU_MAX: */ + NET_BUF_SIMPLE_DEFINE( + rsp, BLE_MESH_MODEL_BUF_LEN(BT_MESH_DFD_OP_RECEIVERS_LIST, + DFD_RECEIVERS_LIST_MSG_MAXLEN)); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_RECEIVERS_LIST); - net_buf_simple_add_le16(&rsp, srv->target_cnt); - net_buf_simple_add_le16(&rsp, first); + net_buf_simple_add_le16(&rsp, srv->target_cnt); + net_buf_simple_add_le16(&rsp, first); - cnt = MIN(cnt, srv->target_cnt - first); - progress = bt_mesh_dfu_cli_progress(&srv->dfu) / 2; + cnt = MIN(cnt, srv->target_cnt - first); + progress = bt_mesh_dfu_cli_progress(&srv->dfu) / 2; - for (i = 0; i < cnt && net_buf_simple_tailroom(&rsp) >= 5 + BT_MESH_MIC_SHORT; i++) { - const struct bt_mesh_dfu_target *t = &srv->targets[i + first]; + for (i = 0; i < cnt && net_buf_simple_tailroom(&rsp) >= 5 + BLE_MESH_MIC_SHORT; i++) { + const struct bt_mesh_dfu_target *t = &srv->targets[i + first]; - net_buf_simple_add_le32( - &rsp, ((t->blob.addr & BIT_MASK(15)) | - ((t->phase & BIT_MASK(4)) << 15U) | - ((t->status & BIT_MASK(3)) << 19U) | - ((t->blob.status & BIT_MASK(4)) << 22U) | - ((progress & BIT_MASK(6)) << 26U))); - net_buf_simple_add_u8(&rsp, t->img_idx); - } + net_buf_simple_add_le32( + &rsp, ((t->blob.addr & BIT_MASK(15)) | + ((t->phase & BIT_MASK(4)) << 15U) | + ((t->status & BIT_MASK(3)) << 19U) | + ((t->blob.status & BIT_MASK(4)) << 22U) | + ((progress & BIT_MASK(6)) << 26U))); + net_buf_simple_add_u8(&rsp, t->img_idx); + } - bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); - return 0; + return 0; } static enum bt_mesh_dfu_iter slot_space_cb(const struct bt_mesh_dfu_slot *slot, - void *user_data) + void *user_data) { - size_t *total = user_data; + size_t *total = user_data; - *total += slot->size; + *total += slot->size; - return BT_MESH_DFU_ITER_CONTINUE; + return BLE_MESH_DFU_ITER_CONTINUE; } static int handle_capabilities_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - size_t size = 0; + size_t size = 0; - BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_CAPABILITIES_STATUS, 17); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_CAPABILITIES_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_CAPABILITIES_STATUS, 17); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_CAPABILITIES_STATUS); - net_buf_simple_add_le16(&rsp, CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX); - net_buf_simple_add_le16(&rsp, CONFIG_BT_MESH_DFU_SLOT_CNT); - net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE); - net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE); + net_buf_simple_add_le16(&rsp, CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX); + net_buf_simple_add_le16(&rsp, CONFIG_BLE_MESH_DFU_SLOT_CNT); + net_buf_simple_add_le32(&rsp, CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE); + net_buf_simple_add_le32(&rsp, CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE); - /* Remaining size */ - (void)bt_mesh_dfu_slot_foreach(slot_space_cb, &size); - size = MIN(size, CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE); + /* Remaining size */ + (void)bt_mesh_dfu_slot_foreach(slot_space_cb, &size); + size = MIN(size, CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE); - net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE - size); + net_buf_simple_add_le32(&rsp, CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE - size); -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + struct bt_mesh_dfd_srv *srv = mod->user_data; - if (srv->oob_schemes.count > 0) { - net_buf_simple_add_u8(&rsp, 1); - net_buf_simple_add_mem(&rsp, srv->oob_schemes.schemes, - srv->oob_schemes.count); - } else + if (srv->oob_schemes.count > 0) { + net_buf_simple_add_u8(&rsp, 1); + net_buf_simple_add_mem(&rsp, srv->oob_schemes.schemes, + srv->oob_schemes.count); + } else #endif - { - net_buf_simple_add_u8(&rsp, 0); - } + { + net_buf_simple_add_u8(&rsp, 0); + } - bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); + bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); - return 0; + return 0; } static void status_rsp(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, - enum bt_mesh_dfd_status status) + enum bt_mesh_dfd_status status) { - BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_STATUS, 12); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_STATUS, 12); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_STATUS); - net_buf_simple_add_u8(&rsp, status); - net_buf_simple_add_u8(&rsp, srv->phase); + net_buf_simple_add_u8(&rsp, status); + net_buf_simple_add_u8(&rsp, srv->phase); - if (srv->phase == BT_MESH_DFD_PHASE_IDLE || !srv->dfu.xfer.slot) { - bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); - return; - } + if (srv->phase == BT_MESH_DFD_PHASE_IDLE || !srv->dfu.xfer.slot) { + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + return; + } - net_buf_simple_add_le16(&rsp, srv->inputs.group); - net_buf_simple_add_le16(&rsp, srv->inputs.app_idx); - net_buf_simple_add_u8(&rsp, srv->inputs.ttl); - net_buf_simple_add_le16(&rsp, srv->inputs.timeout_base); - net_buf_simple_add_u8(&rsp, ((srv->dfu.xfer.blob.mode & BIT_MASK(2)) | - ((srv->apply & BIT_MASK(1)) << 2))); - net_buf_simple_add_le16(&rsp, srv->slot_idx); + net_buf_simple_add_le16(&rsp, srv->inputs.group); + net_buf_simple_add_le16(&rsp, srv->inputs.app_idx); + net_buf_simple_add_u8(&rsp, srv->inputs.ttl); + net_buf_simple_add_le16(&rsp, srv->inputs.timeout_base); + net_buf_simple_add_u8(&rsp, ((srv->dfu.xfer.blob.mode & BIT_MASK(2)) | + ((srv->apply & BIT_MASK(1)) << 2))); + net_buf_simple_add_le16(&rsp, srv->slot_idx); - bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); } static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - return 0; + return 0; } static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; - struct bt_mesh_dfd_start_params params; - uint8_t byte; + struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfd_start_params params; + uint8_t byte; - params.app_idx = net_buf_simple_pull_le16(buf); - params.ttl = net_buf_simple_pull_u8(buf); - params.timeout_base = net_buf_simple_pull_le16(buf); - byte = net_buf_simple_pull_u8(buf); - params.xfer_mode = byte & BIT_MASK(2); - params.apply = (byte >> 2U) & BIT_MASK(1); - params.slot_idx = net_buf_simple_pull_le16(buf); + params.app_idx = net_buf_simple_pull_le16(buf); + params.ttl = net_buf_simple_pull_u8(buf); + params.timeout_base = net_buf_simple_pull_le16(buf); + byte = net_buf_simple_pull_u8(buf); + params.xfer_mode = byte & BIT_MASK(2); + params.apply = (byte >> 2U) & BIT_MASK(1); + params.slot_idx = net_buf_simple_pull_le16(buf); - if (buf->len == 16) { - /* TODO: Virtual addresses not supported. */ - status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); - return 0; - } + if (buf->len == 16) { + /* TODO: Virtual addresses not supported. */ + status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } - if (buf->len != 2) { - return -EINVAL; - } + if (buf->len != 2) { + return -EINVAL; + } - params.group = net_buf_simple_pull_le16(buf); + params.group = net_buf_simple_pull_le16(buf); - status_rsp(srv, ctx, bt_mesh_dfd_srv_start(srv, ¶ms)); + status_rsp(srv, ctx, bt_mesh_dfd_srv_start(srv, ¶ms)); - return 0; + return 0; } static int handle_suspend(const struct bt_mesh_model *mod, - struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - status_rsp(srv, ctx, bt_mesh_dfd_srv_suspend(srv)); + status_rsp(srv, ctx, bt_mesh_dfd_srv_suspend(srv)); - return 0; + return 0; } static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - bt_mesh_dfd_srv_cancel(srv, ctx); + bt_mesh_dfd_srv_cancel(srv, ctx); - return 0; + return 0; } static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - status_rsp(srv, ctx, bt_mesh_dfd_srv_apply(srv)); + status_rsp(srv, ctx, bt_mesh_dfd_srv_apply(srv)); - return 0; + return 0; } static void upload_status_rsp_with_progress(struct bt_mesh_dfd_srv *srv, - struct bt_mesh_msg_ctx *ctx, - enum bt_mesh_dfd_status status, - uint8_t progress) + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status, + uint8_t progress) { - BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_UPLOAD_STATUS, - DFD_UPLOAD_STATUS_MSG_MAXLEN); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_UPLOAD_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_UPLOAD_STATUS, + DFD_UPLOAD_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_UPLOAD_STATUS); - net_buf_simple_add_u8(&rsp, status); - net_buf_simple_add_u8(&rsp, srv->upload.phase); + net_buf_simple_add_u8(&rsp, status); + net_buf_simple_add_u8(&rsp, srv->upload.phase); - if (srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_IDLE || - !srv->upload.slot) { - bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); - return; - } + if (srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_IDLE || + !srv->upload.slot) { + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + return; + } -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - if (srv->upload.is_oob) { - net_buf_simple_add_u8(&rsp, progress | BIT(7)); - net_buf_simple_add_mem(&rsp, srv->upload.oob.current_fwid, - srv->upload.oob.current_fwid_len); - } else +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob) { + net_buf_simple_add_u8(&rsp, progress | BIT(7)); + net_buf_simple_add_mem(&rsp, srv->upload.oob.current_fwid, + srv->upload.oob.current_fwid_len); + } else #endif - { - net_buf_simple_add_u8(&rsp, progress); - net_buf_simple_add_mem(&rsp, srv->upload.slot->fwid, - srv->upload.slot->fwid_len); - } + { + net_buf_simple_add_u8(&rsp, progress); + net_buf_simple_add_mem(&rsp, srv->upload.slot->fwid, + srv->upload.slot->fwid_len); + } - bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); } static void upload_status_rsp(struct bt_mesh_dfd_srv *srv, - struct bt_mesh_msg_ctx *ctx, - enum bt_mesh_dfd_status status) + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status) { - uint8_t progress; + uint8_t progress; -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - if (srv->upload.is_oob) { - progress = srv->cb->oob_progress_get(srv, srv->upload.slot); - } else +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob) { + progress = srv->cb->oob_progress_get(srv, srv->upload.slot); + } else #endif - { - progress = bt_mesh_blob_srv_progress(&srv->upload.blob); - } + { + progress = bt_mesh_blob_srv_progress(&srv->upload.blob); + } - upload_status_rsp_with_progress(srv, ctx, status, progress); + upload_status_rsp_with_progress(srv, ctx, status, progress); } static int handle_upload_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - return 0; + return 0; } static inline int set_upload_fwid(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, - const uint8_t *fwid, size_t fwid_len) + const uint8_t *fwid, size_t fwid_len) { - int err = bt_mesh_dfu_slot_fwid_set(srv->upload.slot, fwid, fwid_len); + int err = bt_mesh_dfu_slot_fwid_set(srv->upload.slot, fwid, fwid_len); - switch (err) { - case -EFBIG: /* Fwid too long */ - case -EALREADY: /* Other server is in progress with this fwid */ - bt_mesh_dfu_slot_release(srv->upload.slot); - srv->upload.slot = NULL; - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); - break; - case -EEXIST: /* Img with this fwid already is in list */ - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; - bt_mesh_dfu_slot_release(srv->upload.slot); + switch (err) { + case -EFBIG: /* Fwid too long */ + case -EALREADY: /* Other server is in progress with this fwid */ + bt_mesh_dfu_slot_release(srv->upload.slot); + srv->upload.slot = NULL; + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + break; + case -EEXIST: /* Img with this fwid already is in list */ + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + bt_mesh_dfu_slot_release(srv->upload.slot); - err = bt_mesh_dfu_slot_get(fwid, fwid_len, &srv->upload.slot); - if (!err) { - upload_status_rsp_with_progress(srv, ctx, BT_MESH_DFD_SUCCESS, 100); - } else { - srv->upload.slot = NULL; - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); - } - break; - case 0: - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; - break; - case -EINVAL: /* Slot in wrong state. */ - default: - break; - } + err = bt_mesh_dfu_slot_get(fwid, fwid_len, &srv->upload.slot); + if (!err) { + upload_status_rsp_with_progress(srv, ctx, BT_MESH_DFD_SUCCESS, 100); + } else { + srv->upload.slot = NULL; + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + } + break; + case 0: + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + break; + case -EINVAL: /* Slot in wrong state. */ + default: + break; + } - return err; + return err; } static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; - size_t meta_len, fwid_len, size; - const uint8_t *meta, *fwid; - uint16_t timeout_base; - uint64_t blob_id; - int err; - uint8_t ttl; + struct bt_mesh_dfd_srv *srv = mod->user_data; + size_t meta_len, fwid_len, size; + const uint8_t *meta, *fwid; + uint16_t timeout_base; + uint64_t blob_id; + int err; + uint8_t ttl; - ttl = net_buf_simple_pull_u8(buf); - timeout_base = net_buf_simple_pull_le16(buf); - blob_id = net_buf_simple_pull_le64(buf); - size = net_buf_simple_pull_le32(buf); - meta_len = net_buf_simple_pull_u8(buf); - if (buf->len < meta_len) { - return -EINVAL; - } + ttl = net_buf_simple_pull_u8(buf); + timeout_base = net_buf_simple_pull_le16(buf); + blob_id = net_buf_simple_pull_le64(buf); + size = net_buf_simple_pull_le32(buf); + meta_len = net_buf_simple_pull_u8(buf); + if (buf->len < meta_len) { + return -EINVAL; + } - meta = net_buf_simple_pull_mem(buf, meta_len); - fwid_len = buf->len; - fwid = net_buf_simple_pull_mem(buf, fwid_len); + meta = net_buf_simple_pull_mem(buf, meta_len); + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); - LOG_DBG("Upload Start: size: %d, fwid: %s, metadata: %s", size, bt_hex(fwid, fwid_len), - bt_hex(meta, meta_len)); + BT_DBG("Upload Start: size: %d, fwid: %s, metadata: %s", size, bt_hex(fwid, fwid_len), + bt_hex(meta, meta_len)); - if (size > CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE) { - upload_status_rsp(srv, ctx, - BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); - return 0; - } + if (size > CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE) { + upload_status_rsp(srv, ctx, + BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + return 0; + } - if (upload_is_busy(srv)) { - if (!srv->upload.slot) { - LOG_WRN("Busy with no upload slot"); - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); - return 0; - } + if (upload_is_busy(srv)) { + if (!srv->upload.slot) { + BT_WARN("Busy with no upload slot"); + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } - if (srv->upload.slot->fwid_len == fwid_len && - !memcmp(srv->upload.slot->fwid, fwid, fwid_len) && - srv->upload.slot->metadata_len == meta_len && - !memcmp(srv->upload.slot->metadata, meta, meta_len) && - srv->upload.blob.state.xfer.id == blob_id && - srv->upload.blob.state.ttl == ttl && - srv->upload.blob.state.timeout_base == timeout_base -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - && !srv->upload.is_oob + if (srv->upload.slot->fwid_len == fwid_len && + !memcmp(srv->upload.slot->fwid, fwid, fwid_len) && + srv->upload.slot->metadata_len == meta_len && + !memcmp(srv->upload.slot->metadata, meta, meta_len) && + srv->upload.blob.state.xfer.id == blob_id && + srv->upload.blob.state.ttl == ttl && + srv->upload.blob.state.timeout_base == timeout_base +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + && !srv->upload.is_oob #endif - ) { - LOG_DBG("Duplicate upload start"); - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - return 0; - } + ) { + BT_DBG("Duplicate upload start"); + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + return 0; + } - LOG_WRN("Upload already in progress"); - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD); - return 0; - } + BT_WARN("Upload already in progress"); + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD); + return 0; + } - /* This will be a no-op if the slot state isn't RESERVED, which is - * what we want. - */ - if (srv->upload.slot) { - bt_mesh_dfu_slot_release(srv->upload.slot); - } + /* This will be a no-op if the slot state isn't RESERVED, which is + * what we want. + */ + if (srv->upload.slot) { + bt_mesh_dfu_slot_release(srv->upload.slot); + } -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - srv->upload.is_oob = false; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + srv->upload.is_oob = false; #endif - srv->upload.slot = bt_mesh_dfu_slot_reserve(); + srv->upload.slot = bt_mesh_dfu_slot_reserve(); - if (!srv->upload.slot) { - LOG_WRN("No space for slot"); - upload_status_rsp(srv, ctx, - BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); - return 0; - } + if (!srv->upload.slot) { + BT_WARN("No space for slot"); + upload_status_rsp(srv, ctx, + BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + return 0; + } - err = set_upload_fwid(srv, ctx, fwid, fwid_len); - if (err) { - return err; - } + err = set_upload_fwid(srv, ctx, fwid, fwid_len); + if (err) { + return err; + } - err = bt_mesh_dfu_slot_info_set(srv->upload.slot, size, meta, meta_len); - switch (err) { - case -EFBIG: - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); - break; - case 0: - break; - default: - return err; - } + err = bt_mesh_dfu_slot_info_set(srv->upload.slot, size, meta, meta_len); + switch (err) { + case -EFBIG: + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + break; + case 0: + break; + default: + return err; + } - srv->io = NULL; - err = srv->cb->recv(srv, srv->upload.slot, &srv->io); - if (err || !srv->io) { - LOG_ERR("App rejected upload. err: %d io: %p", err, srv->io); - bt_mesh_dfu_slot_release(srv->upload.slot); - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); - return 0; - } + srv->io = NULL; + err = srv->cb->recv(srv, srv->upload.slot, &srv->io); + if (err || !srv->io) { + BT_ERR("App rejected upload. err: %d io: %p", err, srv->io); + bt_mesh_dfu_slot_release(srv->upload.slot); + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } - err = bt_mesh_blob_srv_recv(&srv->upload.blob, blob_id, srv->io, ttl, - timeout_base); - if (err) { - LOG_ERR("BLOB Server rejected upload (err: %d)", err); - bt_mesh_dfu_slot_release(srv->upload.slot); - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); - return 0; - } + err = bt_mesh_blob_srv_recv(&srv->upload.blob, blob_id, srv->io, ttl, + timeout_base); + if (err) { + BT_ERR("BLOB Server rejected upload (err: %d)", err); + bt_mesh_dfu_slot_release(srv->upload.slot); + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } - LOG_DBG("%s", bt_hex(fwid, fwid_len)); + BT_DBG("%s", bt_hex(fwid, fwid_len)); - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - return 0; + return 0; } static int handle_upload_start_oob(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; - uint8_t uri_len; - uint8_t *uri; - uint16_t fwid_len; - uint8_t *fwid; + struct bt_mesh_dfd_srv *srv = mod->user_data; + uint8_t uri_len; + uint8_t *uri; + uint16_t fwid_len; + uint8_t *fwid; - uri_len = net_buf_simple_pull_u8(buf); + uri_len = net_buf_simple_pull_u8(buf); - if (uri_len > buf->len) { - return -EINVAL; - } + if (uri_len > buf->len) { + return -EINVAL; + } - uri = net_buf_simple_pull_mem(buf, uri_len); - fwid_len = buf->len; - fwid = net_buf_simple_pull_mem(buf, fwid_len); + uri = net_buf_simple_pull_mem(buf, uri_len); + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); - LOG_DBG("Upload OOB Start"); - LOG_HEXDUMP_DBG(uri, uri_len, "URI"); - LOG_HEXDUMP_DBG(fwid, fwid_len, "FWID"); + BT_DBG("Upload OOB Start"); + BT_INFO("URI %s", bt_hex(uri, uri_len)); + BT_INFO("FWID %s", bt_hex(fwid, fwid_len)); - if (upload_is_busy(srv)) { -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - if (srv->upload.is_oob && - uri_len == srv->upload.oob.uri_len && - fwid_len == srv->upload.oob.current_fwid_len && - !memcmp(uri, srv->upload.oob.uri, uri_len) && - !memcmp(fwid, srv->upload.oob.current_fwid, fwid_len)) { - /* Same image, return SUCCESS for idempotency */ - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - return 0; - } + if (upload_is_busy(srv)) { +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob && + uri_len == srv->upload.oob.uri_len && + fwid_len == srv->upload.oob.current_fwid_len && + !memcmp(uri, srv->upload.oob.uri, uri_len) && + !memcmp(fwid, srv->upload.oob.current_fwid, fwid_len)) { + /* Same image, return SUCCESS for idempotency */ + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + return 0; + } #endif - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD); - return 0; -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - } else if (srv->upload.is_oob && srv->upload.is_pending_oob_check) { - /* Ignore the request if we didn't confirm the previous one. */ - return 0; + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD); + return 0; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + } else if (srv->upload.is_oob && srv->upload.is_pending_oob_check) { + /* Ignore the request if we didn't confirm the previous one. */ + return 0; #endif - } + } -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - if (uri_len > CONFIG_BT_MESH_DFU_URI_MAXLEN || - fwid_len > CONFIG_BT_MESH_DFU_FWID_MAXLEN) { - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); - return 0; - } +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (uri_len > CONFIG_BLE_MESH_DFU_URI_MAXLEN || + fwid_len > CONFIG_BLE_MESH_DFU_FWID_MAXLEN) { + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + return 0; + } - struct bt_mesh_dfu_slot *slot = bt_mesh_dfu_slot_reserve(); + struct bt_mesh_dfu_slot *slot = bt_mesh_dfu_slot_reserve(); - if (slot == NULL) { - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); - return 0; - } + if (slot == NULL) { + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + return 0; + } - /* This will be a no-op if the slot state isn't RESERVED, which is - * what we want. - */ - if (srv->upload.slot) { - bt_mesh_dfu_slot_release(srv->upload.slot); - } + /* This will be a no-op if the slot state isn't RESERVED, which is + * what we want. + */ + if (srv->upload.slot) { + bt_mesh_dfu_slot_release(srv->upload.slot); + } - srv->upload.is_oob = true; - srv->upload.slot = slot; - memcpy(srv->upload.oob.uri, uri, uri_len); - srv->upload.oob.uri_len = uri_len; - memcpy(srv->upload.oob.current_fwid, fwid, fwid_len); - srv->upload.oob.current_fwid_len = fwid_len; - memcpy(&srv->upload.oob.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + srv->upload.is_oob = true; + srv->upload.slot = slot; + memcpy(srv->upload.oob.uri, uri, uri_len); + srv->upload.oob.uri_len = uri_len; + memcpy(srv->upload.oob.current_fwid, fwid, fwid_len); + srv->upload.oob.current_fwid_len = fwid_len; + memcpy(&srv->upload.oob.ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); - int status = srv->cb->start_oob_upload(srv, srv->upload.slot, srv->upload.oob.uri, - srv->upload.oob.uri_len, - srv->upload.oob.current_fwid, - srv->upload.oob.current_fwid_len); + int status = srv->cb->start_oob_upload(srv, srv->upload.slot, srv->upload.oob.uri, + srv->upload.oob.uri_len, + srv->upload.oob.current_fwid, + srv->upload.oob.current_fwid_len); - if (status != BT_MESH_DFD_SUCCESS) { - upload_status_rsp(srv, ctx, status); - bt_mesh_dfu_slot_release(srv->upload.slot); - } else { - srv->upload.is_pending_oob_check = true; - } + if (status != BT_MESH_DFD_SUCCESS) { + upload_status_rsp(srv, ctx, status); + bt_mesh_dfu_slot_release(srv->upload.slot); + } else { + srv->upload.is_pending_oob_check = true; + } #else - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_URI_NOT_SUPPORTED); -#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ + upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_URI_NOT_SUPPORTED); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ - return 0; + return 0; } static int handle_upload_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - if (srv->upload.is_oob) { - srv->cb->cancel_oob_upload(srv, srv->upload.slot); - } else + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + if (srv->upload.is_oob) { + srv->cb->cancel_oob_upload(srv, srv->upload.slot); + } else #endif - { - (void)bt_mesh_blob_srv_cancel(&srv->upload.blob); - } - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + { + (void)bt_mesh_blob_srv_cancel(&srv->upload.blob); + } + upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - return 0; + return 0; } static void fw_status_rsp(struct bt_mesh_dfd_srv *srv, - struct bt_mesh_msg_ctx *ctx, - enum bt_mesh_dfd_status status, uint16_t idx, - const uint8_t *fwid, size_t fwid_len) + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfd_status status, uint16_t idx, + const uint8_t *fwid, size_t fwid_len) { - BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_FW_STATUS, - 7 + CONFIG_BT_MESH_DFU_FWID_MAXLEN); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_FW_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_FW_STATUS, + 7 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN); + bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_FW_STATUS); - net_buf_simple_add_u8(&rsp, status); - net_buf_simple_add_le16(&rsp, bt_mesh_dfu_slot_count()); + net_buf_simple_add_u8(&rsp, status); + net_buf_simple_add_le16(&rsp, bt_mesh_dfu_slot_count()); - net_buf_simple_add_le16(&rsp, idx); - if (fwid) { - net_buf_simple_add_mem(&rsp, fwid, fwid_len); - } + net_buf_simple_add_le16(&rsp, idx); + if (fwid) { + net_buf_simple_add_mem(&rsp, fwid, fwid_len); + } - bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); } static int handle_fw_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; - struct bt_mesh_dfu_slot *slot; - const uint8_t *fwid; - size_t fwid_len; - int idx; + struct bt_mesh_dfd_srv *srv = mod->user_data; + struct bt_mesh_dfu_slot *slot; + const uint8_t *fwid; + size_t fwid_len; + int idx; - fwid_len = buf->len; - fwid = net_buf_simple_pull_mem(buf, fwid_len); + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); - idx = bt_mesh_dfu_slot_get(fwid, fwid_len, &slot); - if (idx >= 0) { - fw_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS, idx, fwid, - fwid_len); - } else { - fw_status_rsp(srv, ctx, BT_MESH_DFD_ERR_FW_NOT_FOUND, 0xffff, - fwid, fwid_len); - } + idx = bt_mesh_dfu_slot_get(fwid, fwid_len, &slot); + if (idx >= 0) { + fw_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS, idx, fwid, + fwid_len); + } else { + fw_status_rsp(srv, ctx, BT_MESH_DFD_ERR_FW_NOT_FOUND, 0xffff, + fwid, fwid_len); + } - return 0; + return 0; } static int handle_fw_get_by_index(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; - const struct bt_mesh_dfu_slot *slot; - uint16_t idx; + struct bt_mesh_dfd_srv *srv = mod->user_data; + const struct bt_mesh_dfu_slot *slot; + uint16_t idx; - idx = net_buf_simple_pull_le16(buf); + idx = net_buf_simple_pull_le16(buf); - slot = bt_mesh_dfu_slot_at(idx); - if (slot) { - fw_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS, idx, slot->fwid, - slot->fwid_len); - } else { - fw_status_rsp(srv, ctx, BT_MESH_DFD_ERR_FW_NOT_FOUND, idx, - NULL, 0); - } + slot = bt_mesh_dfu_slot_at(idx); + if (slot) { + fw_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS, idx, slot->fwid, + slot->fwid_len); + } else { + fw_status_rsp(srv, ctx, BT_MESH_DFD_ERR_FW_NOT_FOUND, idx, + NULL, 0); + } - return 0; + return 0; } static int handle_fw_delete(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; - const uint8_t *fwid; - size_t fwid_len; + struct bt_mesh_dfd_srv *srv = mod->user_data; + const uint8_t *fwid; + size_t fwid_len; - fwid_len = buf->len; - fwid = net_buf_simple_pull_mem(buf, fwid_len); + fwid_len = buf->len; + fwid = net_buf_simple_pull_mem(buf, fwid_len); - enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_fw_delete(srv, &fwid_len, &fwid); + enum bt_mesh_dfd_status status = bt_mesh_dfd_srv_fw_delete(srv, &fwid_len, &fwid); - fw_status_rsp(srv, ctx, status, 0xffff, fwid, fwid_len); + fw_status_rsp(srv, ctx, status, 0xffff, fwid, fwid_len); - return 0; + return 0; } static enum bt_mesh_dfu_iter slot_del_cb(const struct bt_mesh_dfu_slot *slot, - void *user_data) + void *user_data) { - struct bt_mesh_dfd_srv *srv = user_data; + struct bt_mesh_dfd_srv *srv = user_data; - if (srv->cb && srv->cb->del) { - srv->cb->del(srv, slot); - } + if (srv->cb && srv->cb->del) { + srv->cb->del(srv, slot); + } - return BT_MESH_DFU_ITER_CONTINUE; + return BLE_MESH_DFU_ITER_CONTINUE; } static int handle_fw_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - fw_status_rsp(srv, ctx, bt_mesh_dfd_srv_fw_delete_all(srv), 0xffff, NULL, 0); + fw_status_rsp(srv, ctx, bt_mesh_dfd_srv_fw_delete_all(srv), 0xffff, NULL, 0); - return 0; + return 0; } const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[] = { - { BT_MESH_DFD_OP_RECEIVERS_ADD, BT_MESH_LEN_MIN(3), handle_receivers_add }, - { BT_MESH_DFD_OP_RECEIVERS_DELETE_ALL, BT_MESH_LEN_EXACT(0), handle_receivers_delete_all }, - { BT_MESH_DFD_OP_RECEIVERS_GET, BT_MESH_LEN_EXACT(4), handle_receivers_get }, - { BT_MESH_DFD_OP_CAPABILITIES_GET, BT_MESH_LEN_EXACT(0), handle_capabilities_get }, - { BT_MESH_DFD_OP_GET, BT_MESH_LEN_EXACT(0), handle_get }, - { BT_MESH_DFD_OP_START, BT_MESH_LEN_MIN(10), handle_start }, - { BT_MESH_DFD_OP_SUSPEND, BT_MESH_LEN_EXACT(0), handle_suspend }, - { BT_MESH_DFD_OP_CANCEL, BT_MESH_LEN_EXACT(0), handle_cancel }, - { BT_MESH_DFD_OP_APPLY, BT_MESH_LEN_EXACT(0), handle_apply }, - { BT_MESH_DFD_OP_UPLOAD_GET, BT_MESH_LEN_EXACT(0), handle_upload_get }, - { BT_MESH_DFD_OP_UPLOAD_START, BT_MESH_LEN_MIN(16), handle_upload_start }, - { BT_MESH_DFD_OP_UPLOAD_START_OOB, BT_MESH_LEN_MIN(2), handle_upload_start_oob }, - { BT_MESH_DFD_OP_UPLOAD_CANCEL, BT_MESH_LEN_EXACT(0), handle_upload_cancel }, - { BT_MESH_DFD_OP_FW_GET, BT_MESH_LEN_MIN(0), handle_fw_get }, - { BT_MESH_DFD_OP_FW_GET_BY_INDEX, BT_MESH_LEN_EXACT(2), handle_fw_get_by_index }, - { BT_MESH_DFD_OP_FW_DELETE, BT_MESH_LEN_MIN(0), handle_fw_delete }, - { BT_MESH_DFD_OP_FW_DELETE_ALL, BT_MESH_LEN_EXACT(0), handle_fw_delete_all }, + { BT_MESH_DFD_OP_RECEIVERS_ADD, 3, (void *)handle_receivers_add }, + { BT_MESH_DFD_OP_RECEIVERS_DELETE_ALL, 0, (void *)handle_receivers_delete_all }, + { BT_MESH_DFD_OP_RECEIVERS_GET, 4, (void *)handle_receivers_get }, + { BT_MESH_DFD_OP_CAPABILITIES_GET, 0, (void *)handle_capabilities_get }, + { BT_MESH_DFD_OP_GET, 0, (void *)handle_get }, + { BT_MESH_DFD_OP_START, 10, (void *)handle_start }, + { BT_MESH_DFD_OP_SUSPEND, 0, (void *)handle_suspend }, + { BT_MESH_DFD_OP_CANCEL, 0, (void *)handle_cancel }, + { BT_MESH_DFD_OP_APPLY, 0, (void *)handle_apply }, + { BT_MESH_DFD_OP_UPLOAD_GET, 0, (void *)handle_upload_get }, + { BT_MESH_DFD_OP_UPLOAD_START, 16, (void *)handle_upload_start }, + { BT_MESH_DFD_OP_UPLOAD_START_OOB, 2, (void *)handle_upload_start_oob }, + { BT_MESH_DFD_OP_UPLOAD_CANCEL, 0, (void *)handle_upload_cancel }, + { BT_MESH_DFD_OP_FW_GET, 0, (void *)handle_fw_get }, + { BT_MESH_DFD_OP_FW_GET_BY_INDEX, 2, (void *)handle_fw_get_by_index }, + { BT_MESH_DFD_OP_FW_DELETE, 0, (void *)handle_fw_delete }, + { BT_MESH_DFD_OP_FW_DELETE_ALL, 0, (void *)handle_fw_delete_all }, - BT_MESH_MODEL_OP_END + BLE_MESH_MODEL_OP_END }; static void dfu_suspended(struct bt_mesh_dfu_cli *cli) { - struct bt_mesh_dfd_srv *srv = - CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); - dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED); + dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED); } static void dfu_ended(struct bt_mesh_dfu_cli *cli, - enum bt_mesh_dfu_status reason) + enum bt_mesh_dfu_status reason) { - struct bt_mesh_dfd_srv *srv = - CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); - int err; + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + int err; - LOG_DBG("reason: %u, phase: %u, apply: %u", reason, srv->phase, srv->apply); + BT_DBG("reason: %u, phase: %u, apply: %u", reason, srv->phase, srv->apply); - if (srv->phase == BT_MESH_DFD_PHASE_IDLE) { - return; - } + if (srv->phase == BT_MESH_DFD_PHASE_IDLE) { + return; + } - if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); - return; - } + if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + return; + } - if (reason != BT_MESH_DFU_SUCCESS) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); - return; - } + if (reason != BLE_MESH_DFU_SUCCESS) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + return; + } - if (!srv->apply) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_SUCCESS); - return; - } + if (!srv->apply) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_SUCCESS); + return; + } - dfd_phase_set(srv, BT_MESH_DFD_PHASE_APPLYING_UPDATE); + dfd_phase_set(srv, BT_MESH_DFD_PHASE_APPLYING_UPDATE); - err = bt_mesh_dfu_cli_apply(cli); - if (err) { - LOG_ERR("Apply failed: %d", err); - dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); - } + err = bt_mesh_dfu_cli_apply(cli); + if (err) { + BT_ERR("Apply failed: %d", err); + dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + } } static void dfu_applied(struct bt_mesh_dfu_cli *cli) { - struct bt_mesh_dfd_srv *srv = - CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); - int err; + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + int err; - if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); - return; - } + if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + return; + } - if (srv->phase != BT_MESH_DFD_PHASE_APPLYING_UPDATE) { - return; - } + if (srv->phase != BT_MESH_DFD_PHASE_APPLYING_UPDATE) { + return; + } - err = bt_mesh_dfu_cli_confirm(cli); - if (err) { - LOG_ERR("Confirm failed: %d", err); - dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); - } + err = bt_mesh_dfu_cli_confirm(cli); + if (err) { + BT_ERR("Confirm failed: %d", err); + dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + } } static void dfu_confirmed(struct bt_mesh_dfu_cli *cli) { - struct bt_mesh_dfd_srv *srv = - CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); - if (srv->phase != BT_MESH_DFD_PHASE_APPLYING_UPDATE && - srv->phase != BT_MESH_DFD_PHASE_CANCELING_UPDATE) { - return; - } + if (srv->phase != BT_MESH_DFD_PHASE_APPLYING_UPDATE && + srv->phase != BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + return; + } - dfd_phase_set(srv, BT_MESH_DFD_PHASE_COMPLETED); + dfd_phase_set(srv, BT_MESH_DFD_PHASE_COMPLETED); } const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb = { - .suspended = dfu_suspended, - .ended = dfu_ended, - .applied = dfu_applied, - .confirmed = dfu_confirmed, + .suspended = dfu_suspended, + .ended = dfu_ended, + .applied = dfu_applied, + .confirmed = dfu_confirmed, }; static int upload_start(struct bt_mesh_blob_srv *b, struct bt_mesh_msg_ctx *ctx, - struct bt_mesh_blob_xfer *xfer) + struct bt_mesh_blob_xfer *xfer) { - LOG_DBG(""); - return 0; + BT_DBG(""); + return 0; } static void upload_end(struct bt_mesh_blob_srv *b, uint64_t id, bool success) { - struct bt_mesh_dfd_srv *srv = - CONTAINER_OF(b, struct bt_mesh_dfd_srv, upload.blob); + struct bt_mesh_dfd_srv *srv = + CONTAINER_OF(b, struct bt_mesh_dfd_srv, upload.blob); - if (srv->upload.phase != BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE) { - return; - } + if (srv->upload.phase != BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE) { + return; + } - LOG_DBG("%u", success); + BT_DBG("%u", success); - if (success && (bt_mesh_dfu_slot_commit(srv->upload.slot) == 0)) { - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; - return; - } + if (success && (bt_mesh_dfu_slot_commit(srv->upload.slot) == 0)) { + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + return; + } - /* Will delete slot when we start a new upload */ - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; + /* Will delete slot when we start a new upload */ + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; } static void upload_timeout(struct bt_mesh_blob_srv *b) { - LOG_DBG(""); + BT_DBG(""); - upload_end(b, b->state.xfer.id, false); + upload_end(b, b->state.xfer.id, false); } const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb = { - .start = upload_start, - .end = upload_end, - .suspended = upload_timeout, + .start = upload_start, + .end = upload_end, + .suspended = upload_timeout, }; -static int dfd_srv_init(const struct bt_mesh_model *mod) +static int dfd_srv_init(struct bt_mesh_model *mod) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - srv->mod = mod; + srv->mod = mod; - if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) { - bt_mesh_model_extend(mod, srv->upload.blob.mod); - } - - return 0; + return 0; } -static void dfd_srv_reset(const struct bt_mesh_model *mod) +static void dfd_srv_reset(struct bt_mesh_model *mod) { - struct bt_mesh_dfd_srv *srv = mod->rt->user_data; + struct bt_mesh_dfd_srv *srv = mod->user_data; - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); - sys_slist_init(&srv->inputs.targets); - srv->target_cnt = 0; + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; - bt_mesh_dfu_slot_foreach(slot_del_cb, srv); - bt_mesh_dfu_slot_del_all(); + sys_slist_init(&srv->inputs.targets); + srv->target_cnt = 0; + + bt_mesh_dfu_slot_foreach(slot_del_cb, srv); + bt_mesh_dfu_slot_del_all(); } +static int dfd_srv_deinit(struct bt_mesh_model *mod) +{ + dfd_srv_reset(mod); + return 0; +} const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb = { - .init = dfd_srv_init, - .reset = dfd_srv_reset, + .init = dfd_srv_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = dfd_srv_deinit, +#endif }; enum bt_mesh_dfd_status bt_mesh_dfd_srv_receiver_add(struct bt_mesh_dfd_srv *srv, uint16_t addr, - uint8_t img_idx) + uint8_t img_idx) { - struct bt_mesh_dfu_target *t; - struct bt_mesh_blob_target_pull *p; + struct bt_mesh_dfu_target *t; + struct bt_mesh_blob_target_pull *p; - if (!BT_MESH_ADDR_IS_UNICAST(addr)) { - return BT_MESH_DFD_SUCCESS; - } + if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { + return BT_MESH_DFD_SUCCESS; + } - t = target_get(srv, addr); - if (t) { - t->img_idx = img_idx; - return BT_MESH_DFD_SUCCESS; - } + t = target_get(srv, addr); + if (t) { + t->img_idx = img_idx; + return BT_MESH_DFD_SUCCESS; + } - /* New target node, add it to the list */ + /* New target node, add it to the list */ - if (srv->target_cnt == ARRAY_SIZE(srv->targets)) { - return BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES; - } + if (srv->target_cnt == ARRAY_SIZE(srv->targets)) { + return BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES; + } - t = &srv->targets[srv->target_cnt]; - p = &srv->pull_ctxs[srv->target_cnt]; - srv->target_cnt++; + t = &srv->targets[srv->target_cnt]; + p = &srv->pull_ctxs[srv->target_cnt]; + srv->target_cnt++; - memset(t, 0, sizeof(*t)); - memset(p, 0, sizeof(*p)); - t->blob.addr = addr; - t->blob.pull = p; - t->img_idx = img_idx; + memset(t, 0, sizeof(*t)); + memset(p, 0, sizeof(*p)); + t->blob.addr = addr; + t->blob.pull = p; + t->img_idx = img_idx; - LOG_DBG("Added receiver 0x%04x img: %u", t->blob.addr, - t->img_idx); + BT_DBG("Added receiver 0x%04x img: %u", t->blob.addr, + t->img_idx); - return BT_MESH_DFD_SUCCESS; + return BT_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_receivers_delete_all(struct bt_mesh_dfd_srv *srv) { - if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; - } + if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } - sys_slist_init(&srv->inputs.targets); - srv->target_cnt = 0; + sys_slist_init(&srv->inputs.targets); + srv->target_cnt = 0; - return BT_MESH_DFD_SUCCESS; + return BT_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, - struct bt_mesh_dfd_start_params *params) + struct bt_mesh_dfd_start_params *params) { - int err, i; - struct bt_mesh_dfu_cli_xfer xfer = { 0 }; + int err, i; + struct bt_mesh_dfu_cli_xfer xfer = { 0 }; - if (!srv->target_cnt) { - return BT_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY; - } + if (!srv->target_cnt) { + return BT_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY; + } - if (!bt_mesh_app_key_exists(params->app_idx)) { - return BT_MESH_DFD_ERR_INVALID_APPKEY_INDEX; - } + if (!bt_mesh_app_key_get(params->app_idx)) { + return BT_MESH_DFD_ERR_INVALID_APPKEY_INDEX; + } - xfer.mode = params->xfer_mode; - xfer.slot = bt_mesh_dfu_slot_at(params->slot_idx); - if (!xfer.slot) { - return BT_MESH_DFD_ERR_FW_NOT_FOUND; - } + xfer.mode = params->xfer_mode; + xfer.slot = bt_mesh_dfu_slot_at(params->slot_idx); + if (!xfer.slot) { + return BT_MESH_DFD_ERR_FW_NOT_FOUND; + } - if (srv->inputs.app_idx == params->app_idx && - srv->inputs.timeout_base == params->timeout_base && - srv->inputs.group == params->group && srv->inputs.ttl == params->ttl && - srv->dfu.xfer.blob.mode == xfer.mode && srv->apply == params->apply && - srv->slot_idx == params->slot_idx) { - if (is_busy(srv) || - srv->phase == BT_MESH_DFD_PHASE_COMPLETED) { - LOG_WRN("Already completed or in progress"); - return BT_MESH_DFD_SUCCESS; - } else if (srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { - bt_mesh_dfu_cli_resume(&srv->dfu); - dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_ACTIVE); - return BT_MESH_DFD_SUCCESS; - } - } else if (is_busy(srv) || - srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { - LOG_WRN("Busy with distribution"); - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; - } + if (srv->inputs.app_idx == params->app_idx && + srv->inputs.timeout_base == params->timeout_base && + srv->inputs.group == params->group && srv->inputs.ttl == params->ttl && + srv->dfu.xfer.blob.mode == xfer.mode && srv->apply == params->apply && + srv->slot_idx == params->slot_idx) { + if (is_busy(srv) || + srv->phase == BT_MESH_DFD_PHASE_COMPLETED) { + BT_WARN("Already completed or in progress"); + return BT_MESH_DFD_SUCCESS; + } else if (srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + bt_mesh_dfu_cli_resume(&srv->dfu); + dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_ACTIVE); + return BT_MESH_DFD_SUCCESS; + } + } else if (is_busy(srv) || + srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + BT_WARN("Busy with distribution"); + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } - if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { - LOG_WRN("Canceling distribution"); - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; - } + if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + BT_WARN("Canceling distribution"); + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } - srv->io = NULL; - err = srv->cb->send(srv, xfer.slot, &srv->io); - if (err || !srv->io) { - return BT_MESH_DFD_ERR_INTERNAL; - } + srv->io = NULL; + err = srv->cb->send(srv, xfer.slot, &srv->io); + if (err || !srv->io) { + return BT_MESH_DFD_ERR_INTERNAL; + } - sys_slist_init(&srv->inputs.targets); - for (i = 0; i < srv->target_cnt; i++) { - uint16_t addr = srv->targets[i].blob.addr; + sys_slist_init(&srv->inputs.targets); + for (i = 0; i < srv->target_cnt; i++) { + uint16_t addr = srv->targets[i].blob.addr; - memset(&srv->targets[i].blob, 0, sizeof(struct bt_mesh_blob_target)); - memset(&srv->pull_ctxs[i], 0, sizeof(struct bt_mesh_blob_target_pull)); - srv->targets[i].blob.addr = addr; - srv->targets[i].blob.pull = &srv->pull_ctxs[i]; + memset(&srv->targets[i].blob, 0, sizeof(struct bt_mesh_blob_target)); + memset(&srv->pull_ctxs[i], 0, sizeof(struct bt_mesh_blob_target_pull)); + srv->targets[i].blob.addr = addr; + srv->targets[i].blob.pull = &srv->pull_ctxs[i]; - sys_slist_append(&srv->inputs.targets, &srv->targets[i].blob.n); - } + sys_slist_append(&srv->inputs.targets, &srv->targets[i].blob.n); + } - srv->slot_idx = params->slot_idx; - srv->inputs.app_idx = params->app_idx; - srv->inputs.timeout_base = params->timeout_base; - srv->inputs.group = params->group; - srv->inputs.ttl = params->ttl; - srv->apply = params->apply; + srv->slot_idx = params->slot_idx; + srv->inputs.app_idx = params->app_idx; + srv->inputs.timeout_base = params->timeout_base; + srv->inputs.group = params->group; + srv->inputs.ttl = params->ttl; + srv->apply = params->apply; - LOG_DBG("Distribution Start: slot: %d, appidx: %d, tb: %d, addr: %04X, ttl: %d, apply: %d", - params->slot_idx, params->app_idx, params->timeout_base, params->group, params->ttl, - params->apply); + BT_DBG("Distribution Start: slot: %d, appidx: %d, tb: %d, addr: %04X, ttl: %d, apply: %d", + params->slot_idx, params->app_idx, params->timeout_base, params->group, params->ttl, + params->apply); - /* DFD Server will always retrieve targets' capabilities before distributing a firmware.*/ - xfer.blob_params = NULL; + /* DFD Server will always retrieve targets' capabilities before distributing a firmware.*/ + xfer.blob_params = NULL; - dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_ACTIVE); - err = bt_mesh_dfu_cli_send(&srv->dfu, &srv->inputs, srv->io, &xfer); - if (err) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); - return BT_MESH_DFD_ERR_INTERNAL; - } + dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_ACTIVE); + err = bt_mesh_dfu_cli_send(&srv->dfu, &srv->inputs, srv->io, &xfer); + if (err) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + return BT_MESH_DFD_ERR_INTERNAL; + } - return BT_MESH_DFD_SUCCESS; + return BT_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_suspend(struct bt_mesh_dfd_srv *srv) { - int err; + int err; - if (srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { - return BT_MESH_DFD_SUCCESS; - } + if (srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + return BT_MESH_DFD_SUCCESS; + } - if (srv->phase != BT_MESH_DFD_PHASE_TRANSFER_ACTIVE) { - return BT_MESH_DFD_ERR_WRONG_PHASE; - } + if (srv->phase != BT_MESH_DFD_PHASE_TRANSFER_ACTIVE) { + return BT_MESH_DFD_ERR_WRONG_PHASE; + } - err = bt_mesh_dfu_cli_suspend(&srv->dfu); - if (err) { - return BT_MESH_DFD_ERR_SUSPEND_FAILED; - } + err = bt_mesh_dfu_cli_suspend(&srv->dfu); + if (err) { + return BT_MESH_DFD_ERR_SUSPEND_FAILED; + } - srv->phase = BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED; - return BT_MESH_DFD_SUCCESS; + srv->phase = BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED; + return BT_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_cancel(struct bt_mesh_dfd_srv *srv, - struct bt_mesh_msg_ctx *ctx) + struct bt_mesh_msg_ctx *ctx) { - enum bt_mesh_dfd_phase prev_phase; - int err; + enum bt_mesh_dfd_phase prev_phase; + int err; - if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE || - srv->phase == BT_MESH_DFD_PHASE_IDLE) { - if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - } - return BT_MESH_DFD_SUCCESS; - } + if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE || + srv->phase == BT_MESH_DFD_PHASE_IDLE) { + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + } + return BT_MESH_DFD_SUCCESS; + } - if (srv->phase == BT_MESH_DFD_PHASE_COMPLETED || - srv->phase == BT_MESH_DFD_PHASE_FAILED) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); - if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - } - return BT_MESH_DFD_SUCCESS; - } + if (srv->phase == BT_MESH_DFD_PHASE_COMPLETED || + srv->phase == BT_MESH_DFD_PHASE_FAILED) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + } + return BT_MESH_DFD_SUCCESS; + } - /* Phase TRANSFER_ACTIVE, TRANSFER_SUSPENDED, TRANSFER_SUCCESS, APPLYING_UPDATE: */ + /* Phase TRANSFER_ACTIVE, TRANSFER_SUSPENDED, TRANSFER_SUCCESS, APPLYING_UPDATE: */ - prev_phase = srv->phase; - dfd_phase_set(srv, BT_MESH_DFD_PHASE_CANCELING_UPDATE); - err = bt_mesh_dfu_cli_cancel(&srv->dfu, NULL); - if (err) { - if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); - } - return BT_MESH_DFD_ERR_INTERNAL; - } + prev_phase = srv->phase; + dfd_phase_set(srv, BT_MESH_DFD_PHASE_CANCELING_UPDATE); + err = bt_mesh_dfu_cli_cancel(&srv->dfu, NULL); + if (err) { + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + } + return BT_MESH_DFD_ERR_INTERNAL; + } - if (prev_phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE && ctx) { - /* Disable randomization for the Firmware Distribution State message to avoid - * reordering when Firmware Distribution Server sends 2 messages in a row when - * cancelling the update (see section 6.2.3.10 of MshDFUv1.0). - */ - ctx->rnd_delay = false; - } + if (prev_phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE && ctx) { + /* Disable randomization for the Firmware Distribution State message to avoid + * reordering when Firmware Distribution Server sends 2 messages in a row when + * cancelling the update (see section 6.2.3.10 of MshDFUv1.0). + */ + /* + * Changed by Espressif: Access Message random delay is not currently supported in IDF. + */ + // ctx->rnd_delay = false; + } - if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - } + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + } - if (prev_phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); - if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); - } - } + if (prev_phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE) { + dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + if (ctx != NULL) { + status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + } + } - return BT_MESH_DFD_SUCCESS; + return BT_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_apply(struct bt_mesh_dfd_srv *srv) { - int err; + int err; - if (srv->phase == BT_MESH_DFD_PHASE_IDLE || - srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE || - srv->phase == BT_MESH_DFD_PHASE_TRANSFER_ACTIVE || - srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED || - srv->phase == BT_MESH_DFD_PHASE_FAILED) { - return BT_MESH_DFD_ERR_WRONG_PHASE; - } + if (srv->phase == BT_MESH_DFD_PHASE_IDLE || + srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE || + srv->phase == BT_MESH_DFD_PHASE_TRANSFER_ACTIVE || + srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED || + srv->phase == BT_MESH_DFD_PHASE_FAILED) { + return BT_MESH_DFD_ERR_WRONG_PHASE; + } - if (srv->phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE || - srv->phase == BT_MESH_DFD_PHASE_COMPLETED) { - return BT_MESH_DFD_SUCCESS; - } + if (srv->phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE || + srv->phase == BT_MESH_DFD_PHASE_COMPLETED) { + return BT_MESH_DFD_SUCCESS; + } - err = bt_mesh_dfu_cli_apply(&srv->dfu); - if (err) { - return BT_MESH_DFD_ERR_INTERNAL; - } + err = bt_mesh_dfu_cli_apply(&srv->dfu); + if (err) { + return BT_MESH_DFD_ERR_INTERNAL; + } - dfd_phase_set(srv, BT_MESH_DFD_PHASE_APPLYING_UPDATE); - return BT_MESH_DFD_SUCCESS; + dfd_phase_set(srv, BT_MESH_DFD_PHASE_APPLYING_UPDATE); + return BT_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete(struct bt_mesh_dfd_srv *srv, size_t *fwid_len, - const uint8_t **fwid) + const uint8_t **fwid) { - struct bt_mesh_dfu_slot *slot; - int idx, err; + struct bt_mesh_dfu_slot *slot; + int idx, err; - if (srv->phase != BT_MESH_DFD_PHASE_IDLE) { - *fwid = NULL; - *fwid_len = 0; - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; - } + if (srv->phase != BT_MESH_DFD_PHASE_IDLE) { + *fwid = NULL; + *fwid_len = 0; + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } - idx = bt_mesh_dfu_slot_get(*fwid, *fwid_len, &slot); - if (idx < 0) { - return BT_MESH_DFD_SUCCESS; - } + idx = bt_mesh_dfu_slot_get(*fwid, *fwid_len, &slot); + if (idx < 0) { + return BT_MESH_DFD_SUCCESS; + } - err = slot_del(srv, slot); - if (err) { - *fwid = NULL; - *fwid_len = 0; - return BT_MESH_DFD_ERR_INTERNAL; - } else { - return BT_MESH_DFD_SUCCESS; - } + err = slot_del(srv, slot); + if (err) { + *fwid = NULL; + *fwid_len = 0; + return BT_MESH_DFD_ERR_INTERNAL; + } else { + return BT_MESH_DFD_SUCCESS; + } } enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete_all(struct bt_mesh_dfd_srv *srv) { - if (srv->phase != BT_MESH_DFD_PHASE_IDLE) { - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; - } + if (srv->phase != BT_MESH_DFD_PHASE_IDLE) { + return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + } - bt_mesh_dfu_slot_foreach(slot_del_cb, srv); + bt_mesh_dfu_slot_foreach(slot_del_cb, srv); - bt_mesh_dfu_slot_del_all(); + bt_mesh_dfu_slot_del_all(); - return BT_MESH_DFD_SUCCESS; + return BT_MESH_DFD_SUCCESS; } -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot, int status, - uint8_t *fwid, size_t fwid_len) + const struct bt_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len) { - int err; + int err; - if (slot != srv->upload.slot || !srv->upload.is_oob || - srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || - !srv->upload.is_pending_oob_check) { - /* This should not happen, unless the application calls the function with a - * "wrong" pointer or at a wrong time. - */ - return -EINVAL; - } + if (slot != srv->upload.slot || !srv->upload.is_oob || + srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || + !srv->upload.is_pending_oob_check) { + /* This should not happen, unless the application calls the function with a + * "wrong" pointer or at a wrong time. + */ + return -EINVAL; + } - srv->upload.is_pending_oob_check = false; + srv->upload.is_pending_oob_check = false; - if (status != BT_MESH_DFD_SUCCESS) { - bt_mesh_dfu_slot_release(srv->upload.slot); - upload_status_rsp(srv, &srv->upload.oob.ctx, status); - return -ECANCELED; - } + if (status != BT_MESH_DFD_SUCCESS) { + bt_mesh_dfu_slot_release(srv->upload.slot); + upload_status_rsp(srv, &srv->upload.oob.ctx, status); + return -ECANCELED; + } - err = set_upload_fwid(srv, &srv->upload.oob.ctx, fwid, fwid_len); + err = set_upload_fwid(srv, &srv->upload.oob.ctx, fwid, fwid_len); - if (err) { - return err; - } + if (err) { + return err; + } - upload_status_rsp(srv, &srv->upload.oob.ctx, BT_MESH_DFD_SUCCESS); - return 0; + upload_status_rsp(srv, &srv->upload.oob.ctx, BT_MESH_DFD_SUCCESS); + return 0; } int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot, bool success, - size_t size, const uint8_t *metadata, size_t metadata_len) + const struct bt_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len) { - int err = 0; + int err = 0; - if (srv->upload.phase != BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || - srv->upload.slot != slot || !srv->upload.is_oob) { - return -EINVAL; - } + if (srv->upload.phase != BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || + srv->upload.slot != slot || !srv->upload.is_oob) { + return -EINVAL; + } - if (!success) { - goto error; - } + if (!success) { + goto error; + } - err = bt_mesh_dfu_slot_info_set(srv->upload.slot, size, metadata, metadata_len); - if (err) { - goto error; - } + err = bt_mesh_dfu_slot_info_set(srv->upload.slot, size, metadata, metadata_len); + if (err) { + goto error; + } - err = bt_mesh_dfu_slot_commit(srv->upload.slot); - if (err) { - goto error; - } + err = bt_mesh_dfu_slot_commit(srv->upload.slot); + if (err) { + goto error; + } - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; - return 0; + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + return 0; error: - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; - bt_mesh_dfu_slot_release(srv->upload.slot); - return err; + srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; + bt_mesh_dfu_slot_release(srv->upload.slot); + return err; } -#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ +#endif /* CONFIG_BLE_MESH_DFD_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h index 12c7d943f6..403b8b3d17 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv_internal.h @@ -1,47 +1,49 @@ /* - * Copyright (c) 2022 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_INTERNAL_H__ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_INTERNAL_H__ +#ifndef _BLE_MESH_v11_DFD_SRV_INTERNAL_H__ +#define _BLE_MESH_v11_DFD_SRV_INTERNAL_H__ -#include +#include "mesh_v1.1/dfu/dfd_srv.h" +#if CONFIG_BLE_MESH_DFD_SRV #ifdef __cplusplus extern "C" { #endif struct bt_mesh_dfd_start_params { - uint16_t app_idx, timeout_base, slot_idx, group; - enum bt_mesh_blob_xfer_mode xfer_mode; - uint8_t ttl; - bool apply; + uint16_t app_idx, timeout_base, slot_idx, group; + enum bt_mesh_blob_xfer_mode xfer_mode; + uint8_t ttl; + bool apply; }; enum bt_mesh_dfd_status bt_mesh_dfd_srv_receiver_add(struct bt_mesh_dfd_srv *srv, uint16_t addr, - uint8_t img_idx); + uint8_t img_idx); enum bt_mesh_dfd_status bt_mesh_dfd_srv_receivers_delete_all(struct bt_mesh_dfd_srv *srv); enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, - struct bt_mesh_dfd_start_params *params); + struct bt_mesh_dfd_start_params *params); enum bt_mesh_dfd_status bt_mesh_dfd_srv_suspend(struct bt_mesh_dfd_srv *srv); enum bt_mesh_dfd_status bt_mesh_dfd_srv_cancel(struct bt_mesh_dfd_srv *srv, - struct bt_mesh_msg_ctx *ctx); + struct bt_mesh_msg_ctx *ctx); enum bt_mesh_dfd_status bt_mesh_dfd_srv_apply(struct bt_mesh_dfd_srv *srv); enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete(struct bt_mesh_dfd_srv *srv, size_t *fwid_len, - const uint8_t **fwid); + const uint8_t **fwid); enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete_all(struct bt_mesh_dfd_srv *srv); #ifdef __cplusplus } #endif - -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_INTERNAL_H__ */ +#endif +#endif /* _BLE_MESH_v11_DFD_SRV_INTERNAL_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h index c1c5aca46c..17a2059803 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu.h @@ -1,44 +1,47 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include "mesh/buf.h" -#define BT_MESH_DFU_OP_UPDATE_INFO_GET BT_MESH_MODEL_OP_2(0x83, 0x08) -#define BT_MESH_DFU_OP_UPDATE_INFO_STATUS BT_MESH_MODEL_OP_2(0x83, 0x09) +#if CONFIG_BLE_MESH_DFU_SRV || CONFIG_BLE_MESH_DFU_CLI +#define BLE_MESH_DFU_OP_UPDATE_INFO_GET BLE_MESH_MODEL_OP_2(0x83, 0x08) +#define BLE_MESH_DFU_OP_UPDATE_INFO_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x09) -#define BT_MESH_DFU_OP_UPDATE_METADATA_CHECK BT_MESH_MODEL_OP_2(0x83, 0x0a) -#define BT_MESH_DFU_OP_UPDATE_METADATA_STATUS BT_MESH_MODEL_OP_2(0x83, 0x0b) +#define BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK BLE_MESH_MODEL_OP_2(0x83, 0x0a) +#define BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x0b) -#define BT_MESH_DFU_OP_UPDATE_GET BT_MESH_MODEL_OP_2(0x83, 0x0c) -#define BT_MESH_DFU_OP_UPDATE_START BT_MESH_MODEL_OP_2(0x83, 0x0d) -#define BT_MESH_DFU_OP_UPDATE_CANCEL BT_MESH_MODEL_OP_2(0x83, 0x0e) -#define BT_MESH_DFU_OP_UPDATE_APPLY BT_MESH_MODEL_OP_2(0x83, 0x0f) -#define BT_MESH_DFU_OP_UPDATE_STATUS BT_MESH_MODEL_OP_2(0x83, 0x10) +#define BLE_MESH_DFU_OP_UPDATE_GET BLE_MESH_MODEL_OP_2(0x83, 0x0c) +#define BLE_MESH_DFU_OP_UPDATE_START BLE_MESH_MODEL_OP_2(0x83, 0x0d) +#define BLE_MESH_DFU_OP_UPDATE_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x0e) +#define BLE_MESH_DFU_OP_UPDATE_APPLY BLE_MESH_MODEL_OP_2(0x83, 0x0f) +#define BLE_MESH_DFU_OP_UPDATE_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x10) -#define DFU_UPDATE_INFO_STATUS_MSG_MINLEN (4 + CONFIG_BT_MESH_DFU_FWID_MAXLEN + \ - CONFIG_BT_MESH_DFU_URI_MAXLEN) -#define DFU_UPDATE_START_MSG_MAXLEN (12 + CONFIG_BT_MESH_DFU_METADATA_MAXLEN) +#define DFU_UPDATE_INFO_STATUS_MSG_MINLEN (4 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN + \ + CONFIG_BLE_MESH_DFU_URI_MAXLEN) +#define DFU_UPDATE_START_MSG_MAXLEN (12 + CONFIG_BLE_MESH_DFU_METADATA_MAXLEN) static inline uint16_t dfu_metadata_checksum(struct net_buf_simple *buf) { - /* Simple Fletcher-16 checksum to ensure duplicate start messages don't - * have different metadata. - */ - struct net_buf_simple_state state; - uint8_t sum[2] = {0, 0}; + /* Simple Fletcher-16 checksum to ensure duplicate start messages don't + * have different metadata. + */ + struct net_buf_simple_state state; + uint8_t sum[2] = {0, 0}; - net_buf_simple_save(buf, &state); + net_buf_simple_save(buf, &state); + while (buf->len) { + uint8_t byte = net_buf_simple_pull_u8(buf); - while (buf->len) { - uint8_t byte = net_buf_simple_pull_u8(buf); + sum[0] += byte; + sum[1] += sum[0]; + } - sum[0] += byte; - sum[1] += sum[0]; - } + net_buf_simple_restore(buf, &state); - net_buf_simple_restore(buf, &state); - - return (sum[0] << 8U) | sum[1]; + return (sum[0] << 8U) | sum[1]; } +#endif /* CONFIG_BLE_MESH_DFU_SRV || CONFIG_BLE_MESH_DFU_CLI */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c index f02b884d22..8ce345831d 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c @@ -1,174 +1,325 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include -#include -#include -#include #include "access.h" #include "dfu.h" +#include "btc_ble_mesh_dfu_model.h" #include "blob.h" -#include +#include "mesh/slist.h" +#include "mesh/mutex.h" +#include "mesh_v1.1/dfu/dfu.h" +#include "mesh_v1.1/dfu/dfu_cli.h" -#define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL -#include -LOG_MODULE_REGISTER(bt_mesh_dfu_cli); +#if CONFIG_BLE_MESH_DFU_CLI +#define TARGETS_FOR_EACH(cli, target) \ + SYS_SLIST_FOR_EACH_CONTAINER( \ + (sys_slist_t *)&((cli)->blob.inputs)->targets, target, blob.n) -#define TARGETS_FOR_EACH(cli, target) \ - SYS_SLIST_FOR_EACH_CONTAINER( \ - (sys_slist_t *)&((cli)->blob.inputs)->targets, target, blob.n) - -#define MSG_CTX(cli, dst) \ - { \ - .app_idx = (cli)->blob.inputs->app_idx, .addr = dst, \ - .send_ttl = (cli)->blob.inputs->ttl, \ - } +#define MSG_CTX(cli, dst) \ + { \ + .app_idx = (cli)->blob.inputs->app_idx, .addr = dst, \ + .send_ttl = (cli)->blob.inputs->ttl, \ + } #define DFU_CLI(blob_cli) CONTAINER_OF(blob_cli, struct bt_mesh_dfu_cli, blob) -BUILD_ASSERT((DFU_UPDATE_START_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_START) + - BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, - "The Firmware Update Start message does not fit into the maximum outgoing SDU size."); +_Static_assert((DFU_UPDATE_START_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFU_OP_UPDATE_START) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The Firmware Update Start message does not fit into the maximum outgoing SDU size."); -BUILD_ASSERT((DFU_UPDATE_INFO_STATUS_MSG_MINLEN + - BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_INFO_STATUS) + BT_MESH_MIC_SHORT) - <= BT_MESH_RX_SDU_MAX, - "The Firmware Update Info Status message does not fit into the maximum incoming SDU " - "size."); +_Static_assert((DFU_UPDATE_INFO_STATUS_MSG_MINLEN + + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFU_OP_UPDATE_INFO_STATUS) + BLE_MESH_MIC_SHORT) + <= BLE_MESH_RX_SDU_MAX, + "The Firmware Update Info Status message does not fit into the maximum incoming SDU " + "size."); enum req { - REQ_NONE, - REQ_METADATA, - REQ_IMG, - REQ_STATUS, + REQ_NONE, + REQ_METADATA, + REQ_IMG, + REQ_STATUS, + INTERNAL_REQ_IMG, }; enum { - FLAG_FAILED = BIT(0), - FLAG_CANCELLED = BIT(1), - FLAG_SKIP_CAPS_GET = BIT(2), - FLAG_RESUME = BIT(3), - FLAG_COMPLETED = BIT(4), + FLAG_FAILED = BIT(0), + FLAG_CANCELLED = BIT(1), + FLAG_SKIP_CAPS_GET = BIT(2), + FLAG_RESUME = BIT(3), + FLAG_COMPLETED = BIT(4), }; -enum { - STATE_IDLE, - STATE_TRANSFER, - STATE_REFRESH, - STATE_VERIFIED, - STATE_APPLY, - STATE_APPLIED, - STATE_CONFIRM, - STATE_CANCEL, - STATE_SUSPENDED, -}; +static void bt_mesh_dfu_cli_rm_req_from_list(bt_mesh_dfu_cli_req_t *req); +static int req_free(bt_mesh_dfu_cli_req_t *req); static int32_t dfu_cli_timeout = (10 * MSEC_PER_SEC); +static struct { + bt_mesh_mutex_t op_lock; + sys_slist_t list; +} dfu_req_list; + static struct bt_mesh_dfu_target *target_get(struct bt_mesh_dfu_cli *cli, - uint16_t addr) + uint16_t addr) { - struct bt_mesh_dfu_target *target; + struct bt_mesh_dfu_target *target; - TARGETS_FOR_EACH(cli, target) { - if (addr == target->blob.addr) { - return target; - } - } + TARGETS_FOR_EACH(cli, target) { + if (addr == target->blob.addr) { + return target; + } + } - return NULL; + return NULL; +} + +static void req_timeout_handler(struct k_work *work) +{ + struct k_delayed_work *timer = NULL; + bt_mesh_dfu_cli_req_t *req = NULL; + struct bt_mesh_msg_ctx ctx = {0}; + + BT_WARN("Receive dfu status message timeout"); + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + timer = CONTAINER_OF(work, struct k_delayed_work, work); + + if (timer && !k_delayed_work_free(timer)) { + req = CONTAINER_OF(work, bt_mesh_dfu_cli_req_t, timer.work); + memcpy(&ctx, &req->ctx, sizeof(struct bt_mesh_msg_ctx)); + if (req->type == REQ_NONE) { + assert(0); + } + if (req == NULL) { + assert(0); + } + + bt_mesh_dfu_client_cb_evt_to_btc(req->opcode, BTC_BLE_MESH_EVT_DFU_CLIENT_TIMEOUT, + req->dfu_cli->mod, &ctx, NULL, 0); + } + + bt_mesh_dfu_cli_rm_req_from_list(req); + req_free(req); + + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); +} + +static bt_mesh_dfu_cli_req_t* req_alloc(void) +{ + bt_mesh_dfu_cli_req_t *req = bt_mesh_calloc(sizeof(bt_mesh_dfu_cli_req_t)); + if (!req) { + BT_ERR("device firmware client allocl failed"); + return NULL; + } + + req->ctx.addr = BLE_MESH_ADDR_UNASSIGNED; + req->type = REQ_NONE; + k_delayed_work_init(&req->timer, req_timeout_handler); + return req; +} + +static int req_free(bt_mesh_dfu_cli_req_t *req) +{ + if (req->node.next) { + BT_ERR("req still in list"); + return -EINVAL; + } + + k_delayed_work_free(&req->timer); + bt_mesh_free(req); + return 0; +} + +static int is_valid_req(bt_mesh_dfu_cli_req_t *req) +{ + if (!req || + req->ctx.addr == BLE_MESH_ADDR_UNASSIGNED) { + return false; + } + + return true; +} + +static void bt_mesh_dfu_cli_req_list_init(void) +{ + sys_slist_init(&dfu_req_list.list); + bt_mesh_r_mutex_create(&dfu_req_list.op_lock); +} + +static void bt_mesh_dfu_cli_add_req_to_list(bt_mesh_dfu_cli_req_t *req) +{ + if (!is_valid_req(req)) { + return; + } + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + sys_slist_append(&dfu_req_list.list, &req->node); + + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); +} + +static void bt_mesh_dfu_cli_rm_req_from_list(bt_mesh_dfu_cli_req_t *req) +{ + if (!is_valid_req(req)) { + return; + } + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + sys_slist_find_and_remove(&dfu_req_list.list, &req->node); + + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); + + k_delayed_work_cancel(&req->timer); +} + +static bt_mesh_dfu_cli_req_t* bt_mesh_dfu_req_find_by_addr(uint16_t addr) +{ + bt_mesh_dfu_cli_req_t *req = NULL; + sys_snode_t *peek = NULL; + + if (addr == BLE_MESH_ADDR_UNASSIGNED) { + return NULL; + } + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + SYS_SLIST_FOR_EACH_NODE(&dfu_req_list.list, peek) { + req = (bt_mesh_dfu_cli_req_t*)peek; + if (req->ctx.addr == addr) { + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); + return req; + } + } + + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); + return NULL; +} + +static void bt_mesh_dfu_req_list_free(void) +{ + bt_mesh_dfu_cli_req_t *req = NULL; + sys_snode_t *peek = NULL; + sys_snode_t *nxt = NULL; + + bt_mesh_r_mutex_lock(&dfu_req_list.op_lock); + + SYS_SLIST_FOR_EACH_NODE_SAFE(&dfu_req_list.list, peek, nxt) { + req = (bt_mesh_dfu_cli_req_t*)peek; + if (req->params) { + bt_mesh_free(req->params); + } + bt_mesh_dfu_cli_rm_req_from_list(req); + k_delayed_work_cancel(&req->timer); + req_free(req); + } + + bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); + return; } static void target_failed(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_dfu_target *target, - enum bt_mesh_dfu_status status) + struct bt_mesh_dfu_target *target, + enum bt_mesh_dfu_status status) { - target->status = status; + target->status = status; - LOG_ERR("Target 0x%04x failed: %u", target->blob.addr, status); + BT_ERR("Target 0x%04x failed: %u", target->blob.addr, status); - /* Invalidate blob status to prevent the target from being included in - * future sending: - */ - if (target->blob.status == BT_MESH_BLOB_SUCCESS) { - target->blob.status = BT_MESH_BLOB_ERR_INTERNAL; - } + /* Invalidate blob status to prevent the target from being included in + * future sending: + */ + if (target->blob.status == BT_MESH_BLOB_SUCCESS) { + target->blob.status = BT_MESH_BLOB_ERR_INTERNAL; + } - if (cli->cb && cli->cb->lost_target) { - cli->cb->lost_target(cli, target); - } + if (cli->cb && cli->cb->lost_target) { + cli->cb->lost_target(cli, target); + } } static void dfu_complete(struct bt_mesh_dfu_cli *cli) { - LOG_DBG(""); + BT_DBG(""); - if (cli->cb && cli->cb->ended) { - cli->cb->ended(cli, BT_MESH_DFU_SUCCESS); - } + if (cli->cb && cli->cb->ended) { + cli->cb->ended(cli, BLE_MESH_DFU_SUCCESS); + } } static void dfu_applied(struct bt_mesh_dfu_cli *cli) { - LOG_DBG(""); + BT_DBG(""); - cli->xfer.state = STATE_APPLIED; + cli->xfer.state = STATE_APPLIED; - if (cli->cb && cli->cb->applied) { - cli->cb->applied(cli); - } + if (cli->cb && cli->cb->applied) { + cli->cb->applied(cli); + } } static void dfu_failed(struct bt_mesh_dfu_cli *cli, - enum bt_mesh_dfu_status reason) + enum bt_mesh_dfu_status reason) { - LOG_DBG("%u", reason); + BT_DBG("%u", reason); - cli->xfer.flags |= FLAG_FAILED; + cli->xfer.flags |= FLAG_FAILED; - if (cli->cb && cli->cb->ended) { - cli->cb->ended(cli, reason); - } + if (cli->cb && cli->cb->ended) { + cli->cb->ended(cli, reason); + } } -static int req_setup(struct bt_mesh_dfu_cli *cli, enum req type, uint16_t addr, - void *params) +static int req_setup(struct bt_mesh_dfu_cli *cli, enum req type, + uint32_t opcode, struct bt_mesh_msg_ctx *ctx, + void *params) { - if (cli->req.type != REQ_NONE) { - return -EBUSY; - } + if (!cli->req || + cli->req->type != REQ_NONE) { + return -EBUSY; + } - cli->req.addr = addr; - cli->req.params = params; - cli->req.type = type; + cli->req->params = params; + cli->req->type = type; + cli->req->dfu_cli = cli; + cli->req->opcode = opcode; - return 0; + if (ctx) { + memcpy(&cli->req->ctx, ctx, sizeof(struct bt_mesh_msg_ctx)); + } + + return 0; } static int req_wait(struct bt_mesh_dfu_cli *cli, k_timeout_t timeout) { - int err; + int err = ESP_OK; + bt_mesh_dfu_cli_req_t *req = cli->req; - err = k_sem_take(&cli->req.sem, timeout); - cli->req.type = REQ_NONE; - - return err; + req->timeout = timeout; + k_delayed_work_submit(&req->timer, timeout); + bt_mesh_dfu_cli_add_req_to_list(req); + return err; } static bool targets_active(struct bt_mesh_dfu_cli *cli) { - struct bt_mesh_dfu_target *target; + struct bt_mesh_dfu_target *target; - TARGETS_FOR_EACH(cli, target) { - if (target->status == BT_MESH_DFU_SUCCESS) { - return true; - } - } + TARGETS_FOR_EACH(cli, target) { + if (target->status == BLE_MESH_DFU_SUCCESS) { + return true; + } + } - return false; + return false; } /******************************************************************************* @@ -177,106 +328,112 @@ static bool targets_active(struct bt_mesh_dfu_cli *cli) static void refresh(struct bt_mesh_dfu_cli *cli); static void blob_caps(struct bt_mesh_blob_cli *b, - const struct bt_mesh_blob_cli_caps *caps) + const struct bt_mesh_blob_cli_caps *caps) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - int err; + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + int err; - if (!caps) { - dfu_failed(cli, BT_MESH_DFU_ERR_RESOURCES); - return; - } + if (!caps) { + dfu_failed(cli, BLE_MESH_DFU_ERR_RESOURCES); + return; + } - cli->xfer.blob.block_size_log = caps->max_block_size_log; - cli->xfer.blob.chunk_size = caps->max_chunk_size; + cli->xfer.blob.block_size_log = caps->max_block_size_log; + cli->xfer.blob.chunk_size = caps->max_chunk_size; - /* If mode is not already set and server reported it supports all modes - * default to PUSH, otherwise set value reported by server. If mode - * was set and server supports all modes, keep old value; set - * reported value otherwise. - */ - if (!(cli->xfer.blob.mode & BT_MESH_BLOB_XFER_MODE_ALL)) { - cli->xfer.blob.mode = - caps->modes == BT_MESH_BLOB_XFER_MODE_ALL ? - BT_MESH_BLOB_XFER_MODE_PUSH : caps->modes; - } else { - cli->xfer.blob.mode = - caps->modes == BT_MESH_BLOB_XFER_MODE_ALL ? - cli->xfer.blob.mode : caps->modes; - } + /* If mode is not already set and server reported it supports all modes + * default to PUSH, otherwise set value reported by server. If mode + * was set and server supports all modes, keep old value; set + * reported value otherwise. + */ + if (!(cli->xfer.blob.mode & BT_MESH_BLOB_XFER_MODE_ALL)) { + cli->xfer.blob.mode = + caps->modes == BT_MESH_BLOB_XFER_MODE_ALL ? + BT_MESH_BLOB_XFER_MODE_PUSH : caps->modes; + } else { + cli->xfer.blob.mode = + caps->modes == BT_MESH_BLOB_XFER_MODE_ALL ? + cli->xfer.blob.mode : caps->modes; + } - err = bt_mesh_blob_cli_send(b, b->inputs, &cli->xfer.blob, cli->xfer.io); - if (err) { - LOG_ERR("Starting BLOB xfer failed: %d", err); - dfu_failed(cli, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); - } + err = bt_mesh_blob_cli_send(b, b->inputs, &cli->xfer.blob, cli->xfer.io); + if (err) { + BT_ERR("Starting BLOB xfer failed: %d", err); + dfu_failed(cli, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + } } static void blob_lost_target(struct bt_mesh_blob_cli *b, - struct bt_mesh_blob_target *blobt, - enum bt_mesh_blob_status reason) + struct bt_mesh_blob_target *blobt, + enum bt_mesh_blob_status reason) { - struct bt_mesh_dfu_target *target = - CONTAINER_OF(blobt, struct bt_mesh_dfu_target, blob); - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_dfu_target *target = + CONTAINER_OF(blobt, struct bt_mesh_dfu_target, blob); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - if ((cli->xfer.state == STATE_CONFIRM || cli->xfer.state == STATE_APPLY) && - target->effect == BT_MESH_DFU_EFFECT_UNPROV) { - /* Reset status for such targets to use them in consequent procedures. See sections - * 7.1.2.6 and 7.1.2.9 of the MeshDFU. - */ - target->blob.status = BT_MESH_BLOB_SUCCESS; - return; - } + if ((cli->xfer.state == STATE_CONFIRM || cli->xfer.state == STATE_APPLY) && + target->effect == BLE_MESH_DFU_EFFECT_UNPROV) { + /* Reset status for such targets to use them in consequent procedures. See sections + * 7.1.2.6 and 7.1.2.9 of the MeshDFU. + */ + target->blob.status = BT_MESH_BLOB_SUCCESS; + return; + } - target_failed(cli, target, BT_MESH_DFU_ERR_INTERNAL); + target_failed(cli, target, BLE_MESH_DFU_ERR_INTERNAL); } static void blob_suspended(struct bt_mesh_blob_cli *b) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - LOG_DBG("BLOB transfer suspended"); + BT_DBG("BLOB transfer suspended"); - cli->xfer.state = STATE_SUSPENDED; + cli->xfer.state = STATE_SUSPENDED; - if (cli->cb && cli->cb->suspended) { - cli->cb->suspended(cli); - } + if (cli->cb && cli->cb->suspended) { + cli->cb->suspended(cli); + } } static void blob_end(struct bt_mesh_blob_cli *b, - const struct bt_mesh_blob_xfer *xfer, bool success) + const struct bt_mesh_blob_xfer *xfer, bool success) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + bt_mesh_dfu_cli_req_t *req = NULL; - cli->req.img_cb = NULL; + if (b->tx.target) { + req = bt_mesh_dfu_req_find_by_addr(b->tx.target->addr); + if (req) { + req->img_cb = NULL; + } + } - if (success) { - refresh(cli); - return; - } + if (success) { + refresh(cli); + return; + } - if (cli->xfer.state == STATE_CANCEL) { - /* The user cancelled the transfer, DFU will end when all - * targets have been notified. - */ - return; - } + if (cli->xfer.state == STATE_CANCEL) { + /* The user cancelled the transfer, DFU will end when all + * targets have been notified. + */ + return; + } - if (cli->xfer.state != STATE_TRANSFER) { - LOG_ERR("Blob failed in invalid state %u", cli->xfer.state); - return; - } + if (cli->xfer.state != STATE_TRANSFER) { + BT_ERR("Blob failed in invalid state %u", cli->xfer.state); + return; + } - dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); } const struct bt_mesh_blob_cli_cb _bt_mesh_dfu_cli_blob_handlers = { - .caps = blob_caps, - .lost_target = blob_lost_target, - .suspended = blob_suspended, - .end = blob_end, + .caps = blob_caps, + .lost_target = blob_lost_target, + .suspended = blob_suspended, + .end = blob_end, }; /******************************************************************************* @@ -287,123 +444,123 @@ static void tx_start(uint16_t dur, int err, void *cb_data); static void tx_end(int err, void *cb_data); static const struct bt_mesh_send_cb send_cb = { - .start = tx_start, - .end = tx_end, + .start = tx_start, + .end = tx_end, }; static void tx_start(uint16_t dur, int err, void *cb_data) { - if (err) { - tx_end(err, cb_data); - } + if (err) { + tx_end(err, cb_data); + } } static void tx_end(int err, void *cb_data) { - struct bt_mesh_dfu_cli *cli = cb_data; + struct bt_mesh_dfu_cli *cli = cb_data; - blob_cli_broadcast_tx_complete(&cli->blob); + blob_cli_broadcast_tx_complete(&cli->blob); } static int tx(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf, const struct bt_mesh_send_cb *cb, - struct bt_mesh_dfu_cli *cli) + struct net_buf_simple *buf, const struct bt_mesh_send_cb *cb, + struct bt_mesh_dfu_cli *cli) { - int err; + int err; - err = bt_mesh_model_send(mod, ctx, buf, cb, cli); - if (err) { - LOG_ERR("Send err: %d", err); - if (cb) { - cb->end(err, cli); - } - return err; - } + err = bt_mesh_model_send(mod, ctx, buf, cb, cli); + if (err) { + BT_ERR("Send err: %d", err); + if (cb) { + cb->end(err, cli); + } + return err; + } - return 0; + return 0; } static int info_get(struct bt_mesh_dfu_cli *cli, struct bt_mesh_msg_ctx *ctx, - uint8_t idx, uint8_t max_count, - const struct bt_mesh_send_cb *cb) + uint8_t idx, uint8_t max_count, + const struct bt_mesh_send_cb *cb) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_INFO_GET, 2); - bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_INFO_GET); - net_buf_simple_add_u8(&buf, idx); - net_buf_simple_add_u8(&buf, max_count); + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_INFO_GET, 2); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_INFO_GET); + net_buf_simple_add_u8(&buf, idx); + net_buf_simple_add_u8(&buf, max_count); - return tx(cli->mod, ctx, &buf, cb, cli); + return tx(cli->mod, ctx, &buf, cb, cli); } static void send_info_get(struct bt_mesh_blob_cli *b, uint16_t dst) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); - cli->req.img_cnt = 0xff; + cli->req->img_cnt = 0xff; - info_get(cli, &ctx, 0, cli->req.img_cnt, &send_cb); + info_get(cli, &ctx, 0, cli->req->img_cnt, &send_cb); } static void send_update_start(struct bt_mesh_blob_cli *b, uint16_t dst) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); - struct bt_mesh_dfu_target *target; + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + struct bt_mesh_dfu_target *target; - if (b->tx.ctx.force_unicast) { - target = target_get(cli, dst); - } else { - target = SYS_SLIST_PEEK_HEAD_CONTAINER( - (sys_slist_t *)&((cli)->blob.inputs)->targets, - target, blob.n); - } + if (b->tx.ctx.force_unicast) { + target = target_get(cli, dst); + } else { + target = SYS_SLIST_PEEK_HEAD_CONTAINER( + (sys_slist_t *) & ((cli)->blob.inputs)->targets, + target, blob.n); + } - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_START, - DFU_UPDATE_START_MSG_MAXLEN); - bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_START); + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_START, + DFU_UPDATE_START_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_START); - net_buf_simple_add_u8(&buf, cli->blob.inputs->ttl); - net_buf_simple_add_le16(&buf, cli->blob.inputs->timeout_base); - net_buf_simple_add_le64(&buf, cli->xfer.blob.id); - net_buf_simple_add_u8(&buf, target->img_idx); - net_buf_simple_add_mem(&buf, cli->xfer.slot->metadata, - cli->xfer.slot->metadata_len); + net_buf_simple_add_u8(&buf, cli->blob.inputs->ttl); + net_buf_simple_add_le16(&buf, cli->blob.inputs->timeout_base); + net_buf_simple_add_le64(&buf, cli->xfer.blob.id); + net_buf_simple_add_u8(&buf, target->img_idx); + net_buf_simple_add_mem(&buf, cli->xfer.slot->metadata, + cli->xfer.slot->metadata_len); - (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); } static void send_update_get(struct bt_mesh_blob_cli *b, uint16_t dst) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_GET, 0); - bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_GET); + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_GET, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_GET); - (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); } static void send_update_cancel(struct bt_mesh_blob_cli *b, uint16_t dst) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_CANCEL, 0); - bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_CANCEL); + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_CANCEL, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_CANCEL); - (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); } static void send_update_apply(struct bt_mesh_blob_cli *b, uint16_t dst) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_msg_ctx ctx = MSG_CTX(cli, dst); - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_APPLY, 0); - bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_APPLY); + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_APPLY, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_APPLY); - (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); + (void)tx(cli->mod, &ctx, &buf, &send_cb, cli); } /******************************************************************************* @@ -417,282 +574,282 @@ static void cancelled(struct bt_mesh_blob_cli *b); static void initiate(struct bt_mesh_dfu_cli *cli) { - struct blob_cli_broadcast_ctx tx = { - .send = send_update_start, - .next = transfer, - .acked = true, - }; - struct bt_mesh_dfu_target *target; - int img_idx = -1; + struct blob_cli_broadcast_ctx tx = { + .send = send_update_start, + .next = transfer, + .acked = true, + }; + struct bt_mesh_dfu_target *target; + int img_idx = -1; - /** If firmware img index is the same for all targets, we can send Firmware Update Start - * message using multicast address. Otherwise, it has to be send in a unicast way. - */ - TARGETS_FOR_EACH(cli, target) { - if (img_idx == -1) { - img_idx = target->img_idx; - } else if (target->img_idx != img_idx) { - tx.force_unicast = true; - break; - } - } + /** If firmware img index is the same for all targets, we can send Firmware Update Start + * message using multicast address. Otherwise, it has to be send in a unicast way. + */ + TARGETS_FOR_EACH(cli, target) { + if (img_idx == -1) { + img_idx = target->img_idx; + } else if (target->img_idx != img_idx) { + tx.force_unicast = true; + break; + } + } - LOG_DBG(""); + BT_DBG(""); - cli->op = BT_MESH_DFU_OP_UPDATE_STATUS; - cli->xfer.state = STATE_TRANSFER; + cli->op = BLE_MESH_DFU_OP_UPDATE_STATUS; + cli->xfer.state = STATE_TRANSFER; - blob_cli_broadcast(&cli->blob, &tx); + blob_cli_broadcast(&cli->blob, &tx); } static void skip_targets_from_broadcast(struct bt_mesh_dfu_cli *cli, bool skip) { - struct bt_mesh_dfu_target *target; + struct bt_mesh_dfu_target *target; - TARGETS_FOR_EACH(cli, target) { - /* If distributor is in the targets list, or target is in Verify phase, - * disable it until Retrieve Capabilities and BLOB Transfer procedures - * are completed. - */ - if (bt_mesh_has_addr(target->blob.addr) || - target->phase == BT_MESH_DFU_PHASE_VERIFY) { - target->blob.skip = skip; - break; - } - } + TARGETS_FOR_EACH(cli, target) { + /* If distributor is in the targets list, or target is in Verify phase, + * disable it until Retrieve Capabilities and BLOB Transfer procedures + * are completed. + */ + if (bt_mesh_has_addr(target->blob.addr) || + target->phase == BLE_MESH_DFU_PHASE_VERIFY) { + target->blob.skip = skip; + break; + } + } } static bool transfer_skip(struct bt_mesh_dfu_cli *cli) { - struct bt_mesh_dfu_target *target; + struct bt_mesh_dfu_target *target; - TARGETS_FOR_EACH(cli, target) { - if (!bt_mesh_has_addr(target->blob.addr) || !target->blob.skip) { - return false; - } - } + TARGETS_FOR_EACH(cli, target) { + if (!bt_mesh_has_addr(target->blob.addr) || !target->blob.skip) { + return false; + } + } - return true; + return true; } static void transfer(struct bt_mesh_blob_cli *b) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - int err; + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + int err; - LOG_DBG(""); + BT_DBG(""); - if (!targets_active(cli)) { - dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); - return; - } + if (!targets_active(cli)) { + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); + return; + } - skip_targets_from_broadcast(cli, true); + skip_targets_from_broadcast(cli, true); - if (transfer_skip(cli)) { - /* If distributor only updates itself, or all targets are in Verify phase, - * proceed to the refresh step immediately. - */ - refresh(cli); - return; - } + if (transfer_skip(cli)) { + /* If distributor only updates itself, or all targets are in Verify phase, + * proceed to the refresh step immediately. + */ + refresh(cli); + return; + } - if (cli->xfer.flags & FLAG_RESUME) { - cli->xfer.flags ^= FLAG_RESUME; - err = bt_mesh_blob_cli_resume(b); - if (err) { - LOG_ERR("Resuming BLOB xfer failed: %d", err); - dfu_failed(cli, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); - } - } else if (cli->xfer.flags & FLAG_SKIP_CAPS_GET) { - cli->xfer.flags ^= FLAG_SKIP_CAPS_GET; - err = bt_mesh_blob_cli_send(b, b->inputs, &cli->xfer.blob, cli->xfer.io); - if (err) { - LOG_ERR("Starting BLOB xfer failed: %d", err); - dfu_failed(cli, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); - } - } else { - err = bt_mesh_blob_cli_caps_get(&cli->blob, cli->blob.inputs); - if (err) { - LOG_ERR("Failed starting blob xfer: %d", err); - dfu_failed(cli, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); - } - } + if (cli->xfer.flags & FLAG_RESUME) { + cli->xfer.flags ^= FLAG_RESUME; + err = bt_mesh_blob_cli_resume(b); + if (err) { + BT_ERR("Resuming BLOB xfer failed: %d", err); + dfu_failed(cli, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + } + } else if (cli->xfer.flags & FLAG_SKIP_CAPS_GET) { + cli->xfer.flags ^= FLAG_SKIP_CAPS_GET; + err = bt_mesh_blob_cli_send(b, b->inputs, &cli->xfer.blob, cli->xfer.io); + if (err) { + BT_ERR("Starting BLOB xfer failed: %d", err); + dfu_failed(cli, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + } + } else { + err = bt_mesh_blob_cli_caps_get(&cli->blob, cli->blob.inputs); + if (err) { + BT_ERR("Failed starting blob xfer: %d", err); + dfu_failed(cli, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + } + } } static void refreshed(struct bt_mesh_blob_cli *b) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - if (!targets_active(cli)) { - dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); - return; - } + if (!targets_active(cli)) { + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); + return; + } - cli->xfer.state = STATE_VERIFIED; - dfu_complete(cli); + cli->xfer.state = STATE_VERIFIED; + dfu_complete(cli); } static void refresh(struct bt_mesh_dfu_cli *cli) { - const struct blob_cli_broadcast_ctx tx = { - .send = send_update_get, - .next = refreshed, - .acked = true - }; + const struct blob_cli_broadcast_ctx tx = { + .send = send_update_get, + .next = refreshed, + .acked = true + }; - LOG_DBG(""); + BT_DBG(""); - cli->xfer.state = STATE_REFRESH; - cli->op = BT_MESH_DFU_OP_UPDATE_STATUS; + cli->xfer.state = STATE_REFRESH; + cli->op = BLE_MESH_DFU_OP_UPDATE_STATUS; - /* If distributor is in the targets list, enable it again so it participates in Distribute - * Firmware procedure. - */ - skip_targets_from_broadcast(cli, false); + /* If distributor is in the targets list, enable it again so it participates in Distribute + * Firmware procedure. + */ + skip_targets_from_broadcast(cli, false); - blob_cli_broadcast(&cli->blob, &tx); + blob_cli_broadcast(&cli->blob, &tx); } static void apply(struct bt_mesh_dfu_cli *cli) { - const struct blob_cli_broadcast_ctx tx = { - .send = send_update_apply, - .next = applied, - .acked = true - }; + const struct blob_cli_broadcast_ctx tx = { + .send = send_update_apply, + .next = applied, + .acked = true + }; - LOG_DBG(""); + BT_DBG(""); - cli->xfer.state = STATE_APPLY; - cli->op = BT_MESH_DFU_OP_UPDATE_STATUS; + cli->xfer.state = STATE_APPLY; + cli->op = BLE_MESH_DFU_OP_UPDATE_STATUS; - blob_cli_broadcast(&cli->blob, &tx); + blob_cli_broadcast(&cli->blob, &tx); } static void applied(struct bt_mesh_blob_cli *b) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - if (!targets_active(cli)) { - dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); - return; - } + if (!targets_active(cli)) { + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); + return; + } - dfu_applied(cli); + dfu_applied(cli); } static enum bt_mesh_dfu_iter target_img_cb(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_msg_ctx *ctx, - uint8_t idx, uint8_t cnt, - const struct bt_mesh_dfu_img *img, - void *cb_data) + struct bt_mesh_msg_ctx *ctx, + uint8_t idx, uint8_t cnt, + const struct bt_mesh_dfu_img *img, + void *cb_data) { - struct bt_mesh_dfu_target *target; + struct bt_mesh_dfu_target *target; - if ((img->fwid_len != cli->xfer.slot->fwid_len) || - memcmp(cli->xfer.slot->fwid, img->fwid, img->fwid_len)) { - return BT_MESH_DFU_ITER_CONTINUE; - } + if ((img->fwid_len != cli->xfer.slot->fwid_len) || + memcmp(cli->xfer.slot->fwid, img->fwid, img->fwid_len)) { + return BLE_MESH_DFU_ITER_CONTINUE; + } - target = target_get(cli, ctx->addr); - if (target) { - LOG_DBG("SUCCESS: 0x%04x applied dfu (as image %u)", ctx->addr, - idx); - target->phase = BT_MESH_DFU_PHASE_APPLY_SUCCESS; - blob_cli_broadcast_rsp(&cli->blob, &target->blob); - } else { - LOG_WRN("Target 0x%04x not found", ctx->addr); - } + target = target_get(cli, ctx->addr); + if (target) { + BT_DBG("SUCCESS: 0x%04x applied dfu (as image %u)", ctx->addr, + idx); + target->phase = BLE_MESH_DFU_PHASE_APPLY_SUCCESS; + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + } else { + BT_WARN("Target 0x%04x not found", ctx->addr); + } - return BT_MESH_DFU_ITER_STOP; + return BLE_MESH_DFU_ITER_STOP; } static void confirm(struct bt_mesh_dfu_cli *cli) { - const struct blob_cli_broadcast_ctx tx = { - .send = send_info_get, - .next = confirmed, - .acked = true, - .optional = true, - }; + const struct blob_cli_broadcast_ctx tx = { + .send = send_info_get, + .next = confirmed, + .acked = true, + .optional = true, + }; - LOG_DBG(""); + BT_DBG(""); - cli->op = BT_MESH_DFU_OP_UPDATE_INFO_STATUS; - cli->req.img_cb = target_img_cb; - cli->req.ttl = cli->blob.inputs->ttl; + cli->op = BLE_MESH_DFU_OP_UPDATE_INFO_STATUS; + cli->req->img_cb = target_img_cb; + cli->req->ttl = cli->blob.inputs->ttl; - blob_cli_broadcast(&cli->blob, &tx); + blob_cli_broadcast(&cli->blob, &tx); } static void confirmed(struct bt_mesh_blob_cli *b) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - struct bt_mesh_dfu_target *target; - bool success = false; + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_dfu_target *target; + bool success = false; - cli->req.img_cb = NULL; + cli->req->img_cb = NULL; - TARGETS_FOR_EACH(cli, target) { - if (target->status != BT_MESH_DFU_SUCCESS) { - /* Target either failed at earlier stage or during confirmation. In any - * case, the app is already notified. Don't consider the target here. - */ - continue; - } + TARGETS_FOR_EACH(cli, target) { + if (target->status != BLE_MESH_DFU_SUCCESS) { + /* Target either failed at earlier stage or during confirmation. In any + * case, the app is already notified. Don't consider the target here. + */ + continue; + } - if (target->effect == BT_MESH_DFU_EFFECT_UNPROV) { - if (!target->blob.acked) { - success = true; - continue; - } + if (target->effect == BLE_MESH_DFU_EFFECT_UNPROV) { + if (!target->blob.acked) { + success = true; + continue; + } - LOG_DBG("Target 0x%04x still provisioned", target->blob.addr); - target->phase = BT_MESH_DFU_PHASE_APPLY_FAIL; - target_failed(cli, target, BT_MESH_DFU_ERR_INTERNAL); - } else if (!target->blob.acked) { - LOG_DBG("Target 0x%04x failed to respond", target->blob.addr); - target->phase = BT_MESH_DFU_PHASE_APPLY_FAIL; - target_failed(cli, target, BT_MESH_DFU_ERR_INTERNAL); - } else if (target->status == BT_MESH_DFU_SUCCESS) { - success = true; - } - } + BT_DBG("Target 0x%04x still provisioned", target->blob.addr); + target->phase = BLE_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BLE_MESH_DFU_ERR_INTERNAL); + } else if (!target->blob.acked) { + BT_DBG("Target 0x%04x failed to respond", target->blob.addr); + target->phase = BLE_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BLE_MESH_DFU_ERR_INTERNAL); + } else if (target->status == BLE_MESH_DFU_SUCCESS) { + success = true; + } + } - if (success) { - cli->xfer.state = STATE_IDLE; - cli->xfer.flags = FLAG_COMPLETED; + if (success) { + cli->xfer.state = STATE_IDLE; + cli->xfer.flags = FLAG_COMPLETED; - if (cli->cb && cli->cb->confirmed) { - cli->cb->confirmed(cli); - } - } else { - dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); - } + if (cli->cb && cli->cb->confirmed) { + cli->cb->confirmed(cli); + } + } else { + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); + } } static void cancel(struct bt_mesh_dfu_cli *cli) { - const struct blob_cli_broadcast_ctx tx = { - .send = send_update_cancel, - .next = cancelled, - .acked = true - }; + const struct blob_cli_broadcast_ctx tx = { + .send = send_update_cancel, + .next = cancelled, + .acked = true + }; - LOG_DBG(""); + BT_DBG(""); - cli->op = BT_MESH_DFU_OP_UPDATE_STATUS; + cli->op = BLE_MESH_DFU_OP_UPDATE_STATUS; - blob_cli_broadcast(&cli->blob, &tx); + blob_cli_broadcast(&cli->blob, &tx); } static void cancelled(struct bt_mesh_blob_cli *b) { - struct bt_mesh_dfu_cli *cli = DFU_CLI(b); + struct bt_mesh_dfu_cli *cli = DFU_CLI(b); - cli->xfer.flags |= FLAG_CANCELLED; - dfu_failed(cli, BT_MESH_DFU_ERR_INTERNAL); + cli->xfer.flags |= FLAG_CANCELLED; + dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); } /******************************************************************************* @@ -700,302 +857,351 @@ static void cancelled(struct bt_mesh_blob_cli *b) ******************************************************************************/ static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfu_cli *cli = mod->rt->user_data; - enum bt_mesh_dfu_status status; - enum bt_mesh_dfu_phase phase; - struct bt_mesh_dfu_target *target; - uint8_t byte; + struct bt_mesh_dfu_cli *cli = mod->user_data; + bt_mesh_dfu_cli_req_t *req = NULL; + enum bt_mesh_dfu_status status; + enum bt_mesh_dfu_phase phase; + struct bt_mesh_dfu_target *target; + uint8_t byte; - byte = net_buf_simple_pull_u8(buf); - status = byte & BIT_MASK(3); - phase = byte >> 5; + byte = net_buf_simple_pull_u8(buf); + status = byte & BIT_MASK(3); + phase = byte >> 5; - if (cli->req.type == REQ_STATUS && cli->req.addr == ctx->addr) { - if (cli->req.params) { - struct bt_mesh_dfu_target_status *rsp = cli->req.params; + req = bt_mesh_dfu_req_find_by_addr(ctx->addr); - rsp->status = status; - rsp->phase = phase; - if (buf->len == 13) { - rsp->ttl = net_buf_simple_pull_u8(buf); - rsp->effect = net_buf_simple_pull_u8(buf) & BIT_MASK(5); - rsp->timeout_base = net_buf_simple_pull_le16(buf); - rsp->blob_id = net_buf_simple_pull_le64(buf); - rsp->img_idx = net_buf_simple_pull_u8(buf); - } else if (buf->len) { - return -EINVAL; - } + // The req will be NULL if the target is a group address. + if (req && req->type == REQ_STATUS) { + if (req->params) { + struct bt_mesh_dfu_target_status *rsp = req->params; - rsp->ttl = 0U; - rsp->effect = BT_MESH_DFU_EFFECT_NONE; - rsp->timeout_base = 0U; - rsp->blob_id = 0U; - rsp->img_idx = 0U; - } - k_sem_give(&cli->req.sem); - } - if (cli->op != BT_MESH_DFU_OP_UPDATE_STATUS) { - return 0; - } + rsp->status = status; + rsp->phase = phase; + if (buf->len == 13) { + rsp->ttl = net_buf_simple_pull_u8(buf); + rsp->effect = net_buf_simple_pull_u8(buf) & BIT_MASK(5); + rsp->timeout_base = net_buf_simple_pull_le16(buf); + rsp->blob_id = net_buf_simple_pull_le64(buf); + rsp->img_idx = net_buf_simple_pull_u8(buf); + } else if (buf->len) { + return -EINVAL; + } - target = target_get(cli, ctx->addr); - if (!target) { - LOG_WRN("Unknown target 0x%04x", ctx->addr); - return -ENOENT; - } + rsp->ttl = 0U; + rsp->effect = BLE_MESH_DFU_EFFECT_NONE; + rsp->timeout_base = 0U; + rsp->blob_id = 0U; + rsp->img_idx = 0U; + } + bt_mesh_dfu_client_cb_evt_to_btc(req->opcode, BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP, + req->dfu_cli->mod, &req->ctx, req->params, + sizeof(struct bt_mesh_dfu_metadata_status)); + bt_mesh_free(req->params); + bt_mesh_dfu_cli_rm_req_from_list(req); + k_delayed_work_cancel(&req->timer); + req_free(req); + } - LOG_DBG("%u phase: %u, cur state: %u", status, phase, cli->xfer.state); + if (cli->op != BLE_MESH_DFU_OP_UPDATE_STATUS) { + return 0; + } - target->phase = phase; + target = target_get(cli, ctx->addr); + if (!target) { + BT_WARN("Unknown target 0x%04x", ctx->addr); + return -ENOENT; + } - if (cli->xfer.state == STATE_APPLY && phase == BT_MESH_DFU_PHASE_IDLE && - status == BT_MESH_DFU_ERR_WRONG_PHASE) { - LOG_DBG("Response received with Idle phase"); - blob_cli_broadcast_rsp(&cli->blob, &target->blob); - return 0; - } + BT_DBG("%u phase: %u, cur state: %u", status, phase, cli->xfer.state); - if (status != BT_MESH_DFU_SUCCESS) { - target_failed(cli, target, status); - blob_cli_broadcast_rsp(&cli->blob, &target->blob); - return 0; - } + target->phase = phase; - if (buf->len == 13) { - net_buf_simple_pull_u8(buf); /* ttl */ - target->effect = net_buf_simple_pull_u8(buf) & BIT_MASK(5); - net_buf_simple_pull_le16(buf); /* timeout */ + if (cli->xfer.state == STATE_APPLY && phase == BLE_MESH_DFU_PHASE_IDLE && + status == BLE_MESH_DFU_ERR_WRONG_PHASE) { + BT_DBG("Response received with Idle phase"); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } - if (net_buf_simple_pull_le64(buf) != cli->xfer.blob.id) { - LOG_WRN("Invalid BLOB ID"); - target_failed(cli, target, BT_MESH_DFU_ERR_BLOB_XFER_BUSY); - blob_cli_broadcast_rsp(&cli->blob, &target->blob); - return 0; - } + if (status != BLE_MESH_DFU_SUCCESS) { + target_failed(cli, target, status); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } - target->img_idx = net_buf_simple_pull_u8(buf); + if (buf->len == 13) { + net_buf_simple_pull_u8(buf); /* ttl */ + target->effect = net_buf_simple_pull_u8(buf) & BIT_MASK(5); + net_buf_simple_pull_le16(buf); /* timeout */ - LOG_DBG("Target 0x%04x receiving transfer", ctx->addr); - } else if (buf->len) { - return -EINVAL; - } + if (net_buf_simple_pull_le64(buf) != cli->xfer.blob.id) { + BT_WARN("Invalid BLOB ID"); + target_failed(cli, target, BLE_MESH_DFU_ERR_BLOB_XFER_BUSY); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } - if (cli->xfer.state == STATE_REFRESH) { - if (phase == BT_MESH_DFU_PHASE_VERIFY) { - LOG_DBG("Still pending..."); - return 0; - } else if (phase == BT_MESH_DFU_PHASE_VERIFY_FAIL) { - LOG_WRN("Verification failed on target 0x%04x", - target->blob.addr); - target_failed(cli, target, BT_MESH_DFU_ERR_WRONG_PHASE); - } - } else if (cli->xfer.state == STATE_APPLY) { - if (phase != BT_MESH_DFU_PHASE_APPLYING && - (target->effect == BT_MESH_DFU_EFFECT_UNPROV || - phase != BT_MESH_DFU_PHASE_IDLE)) { - LOG_WRN("Target 0x%04x in phase %u after apply", - target->blob.addr, phase); - target_failed(cli, target, BT_MESH_DFU_ERR_WRONG_PHASE); - blob_cli_broadcast_rsp(&cli->blob, &target->blob); - return 0; - } - return 0; - } else if (cli->xfer.state == STATE_CONFIRM) { - if (phase == BT_MESH_DFU_PHASE_APPLYING) { - LOG_DBG("Still pending..."); - return 0; - } + target->img_idx = net_buf_simple_pull_u8(buf); - if (phase != BT_MESH_DFU_PHASE_IDLE) { - LOG_WRN("Target 0x%04x in phase %u after apply", - target->blob.addr, phase); - target->phase = BT_MESH_DFU_PHASE_APPLY_FAIL; - target_failed(cli, target, BT_MESH_DFU_ERR_WRONG_PHASE); - blob_cli_broadcast_rsp(&cli->blob, &target->blob); - return 0; - } - } else if (cli->xfer.state == STATE_CANCEL) { - target->phase = BT_MESH_DFU_PHASE_TRANSFER_CANCELED; - } + BT_DBG("Target 0x%04x receiving transfer", ctx->addr); + } else if (buf->len) { + return -EINVAL; + } - blob_cli_broadcast_rsp(&cli->blob, &target->blob); + if (cli->xfer.state == STATE_REFRESH) { + if (phase == BLE_MESH_DFU_PHASE_VERIFY) { + BT_DBG("Still pending..."); + return 0; + } else if (phase == BLE_MESH_DFU_PHASE_VERIFY_FAIL) { + BT_WARN("Verification failed on target 0x%04x", + target->blob.addr); + target_failed(cli, target, BLE_MESH_DFU_ERR_WRONG_PHASE); + } + } else if (cli->xfer.state == STATE_APPLY) { + if (phase != BLE_MESH_DFU_PHASE_APPLYING && + (target->effect == BLE_MESH_DFU_EFFECT_UNPROV || + phase != BLE_MESH_DFU_PHASE_IDLE)) { + BT_WARN("Target 0x%04x in phase %u after apply", + target->blob.addr, phase); + target_failed(cli, target, BLE_MESH_DFU_ERR_WRONG_PHASE); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + return 0; + } else if (cli->xfer.state == STATE_CONFIRM) { + if (phase == BLE_MESH_DFU_PHASE_APPLYING) { + BT_DBG("Still pending..."); + return 0; + } - return 0; + if (phase != BLE_MESH_DFU_PHASE_IDLE) { + BT_WARN("Target 0x%04x in phase %u after apply", + target->blob.addr, phase); + target->phase = BLE_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BLE_MESH_DFU_ERR_WRONG_PHASE); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + return 0; + } + } else if (cli->xfer.state == STATE_CANCEL) { + target->phase = BLE_MESH_DFU_PHASE_TRANSFER_CANCELED; + } + + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + + return 0; } static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfu_cli *cli = mod->rt->user_data; - struct bt_mesh_dfu_target *target; - enum bt_mesh_dfu_iter it = BT_MESH_DFU_ITER_CONTINUE; - uint8_t img_cnt, idx; + struct bt_mesh_dfu_cli *cli = mod->user_data; + struct bt_mesh_dfu_target *target; + bt_mesh_dfu_cli_req_t *req = NULL; + enum bt_mesh_dfu_iter it = BLE_MESH_DFU_ITER_CONTINUE; + uint8_t img_cnt, idx; - if (!cli->req.img_cb || - (cli->req.type == REQ_IMG && cli->req.addr != ctx->addr)) { - LOG_WRN("Unexpected info status from 0x%04x", ctx->addr); - return 0; - } + req = bt_mesh_dfu_req_find_by_addr(ctx->addr); + if (!req) { + return 0; + } - img_cnt = net_buf_simple_pull_u8(buf); - if (img_cnt < cli->req.img_cnt) { - cli->req.img_cnt = img_cnt; - } + if (req->type == INTERNAL_REQ_IMG) { + goto confirm_procedure; + } - idx = net_buf_simple_pull_u8(buf); - if (idx >= img_cnt) { - LOG_WRN("Invalid idx %u", idx); - return -ENOENT; - } + if (!req->img_cb || + req->type != REQ_IMG) { + BT_WARN("Unexpected info status from 0x%04x req %p type %d", ctx->addr, req, req->type); + return 0; + } - LOG_DBG("Image list from 0x%04x from index %u", ctx->addr, idx); + img_cnt = net_buf_simple_pull_u8(buf); + if (img_cnt < req->img_cnt) { + req->img_cnt = img_cnt; + } - while (buf->len && cli->req.img_cb && idx < cli->req.img_cnt) { - char uri_buf[CONFIG_BT_MESH_DFU_URI_MAXLEN + 1]; - struct bt_mesh_dfu_img img; - size_t uri_len; + idx = net_buf_simple_pull_u8(buf); + if (idx >= img_cnt) { + BT_WARN("Invalid idx %u", idx); + return -ENOENT; + } - img.fwid_len = net_buf_simple_pull_u8(buf); - if (buf->len < img.fwid_len + 1) { - LOG_WRN("Invalid format: fwid"); - return -EINVAL; - } + BT_DBG("Image list from 0x%04x from index %u", ctx->addr, idx); - img.fwid = net_buf_simple_pull_mem(buf, img.fwid_len); + while (buf->len && req->img_cb && idx < req->img_cnt) { + char uri_buf[CONFIG_BLE_MESH_DFU_URI_MAXLEN + 1]; + struct bt_mesh_dfu_img img; + size_t uri_len; - uri_len = net_buf_simple_pull_u8(buf); - if (buf->len < uri_len) { - LOG_WRN("Invalid format: uri"); - return -EINVAL; - } + img.fwid_len = net_buf_simple_pull_u8(buf); + if (buf->len < img.fwid_len + 1) { + BT_WARN("Invalid format: fwid"); + return -EINVAL; + } - LOG_DBG("\tImage %u\n\r\tfwid: %s", idx, bt_hex(img.fwid, img.fwid_len)); + img.fwid = net_buf_simple_pull_mem(buf, img.fwid_len); - if (uri_len) { - size_t uri_buf_len = - MIN(CONFIG_BT_MESH_DFU_URI_MAXLEN, uri_len); + uri_len = net_buf_simple_pull_u8(buf); + if (buf->len < uri_len) { + BT_WARN("Invalid format: uri"); + return -EINVAL; + } - memcpy(uri_buf, net_buf_simple_pull_mem(buf, uri_len), - uri_buf_len); - uri_buf[uri_buf_len] = '\0'; - img.uri = uri_buf; - } else { - img.uri = NULL; - } + BT_DBG("\tImage %u\n\r\tfwid: %s", idx, bt_hex(img.fwid, img.fwid_len)); - it = cli->req.img_cb(cli, ctx, idx, img_cnt, &img, - cli->req.params); - if (it != BT_MESH_DFU_ITER_CONTINUE) { - if (cli->req.type == REQ_IMG) { - k_sem_give(&cli->req.sem); - } + if (uri_len) { + size_t uri_buf_len = + MIN(CONFIG_BLE_MESH_DFU_URI_MAXLEN, uri_len); - return 0; - } + memcpy(uri_buf, net_buf_simple_pull_mem(buf, uri_len), + uri_buf_len); + uri_buf[uri_buf_len] = '\0'; + img.uri = uri_buf; + } else { + img.uri = NULL; + } - idx++; - } + it = req->img_cb(cli, ctx, idx, img_cnt, &img, + req->params); + if (it != BLE_MESH_DFU_ITER_CONTINUE) { + if (req->type == REQ_IMG) { + bt_mesh_dfu_cli_rm_req_from_list(req); + req_free(req); + } - if (idx < cli->req.img_cnt) { - LOG_DBG("Fetching more images (%u/%u)", idx, cli->req.img_cnt); - ctx->send_ttl = cli->req.ttl; - info_get(cli, ctx, idx, cli->req.img_cnt - idx, - (cli->req.type == REQ_IMG) ? NULL : &send_cb); - return 0; - } + return 0; + } - if (cli->req.type == REQ_IMG) { - k_sem_give(&cli->req.sem); - return 0; - } + idx++; + } - /* Confirm-procedure termination: */ - target = target_get(cli, ctx->addr); - if (target) { - LOG_WRN("Target 0x%04x failed to apply image: %s", ctx->addr, - bt_hex(cli->xfer.slot->fwid, cli->xfer.slot->fwid_len)); - target->phase = BT_MESH_DFU_PHASE_APPLY_FAIL; - target_failed(cli, target, BT_MESH_DFU_ERR_INTERNAL); - blob_cli_broadcast_rsp(&cli->blob, &target->blob); - } + if (idx < req->img_cnt) { + BT_DBG("Fetching more images (%u/%u)", idx, req->img_cnt); + ctx->send_ttl = req->ttl; + info_get(cli, ctx, idx, req->img_cnt - idx, + (req->type == REQ_IMG) ? NULL : &send_cb); + return 0; + } else { + if (req->img_cb) { + // used to notify cb function the image output finished + req->img_cb(cli, ctx, idx, img_cnt, NULL, NULL); + } + } - return 0; + bt_mesh_dfu_cli_rm_req_from_list(req); + req_free(req); + return 0; + +confirm_procedure: + /* Confirm-procedure termination: */ + target = target_get(cli, ctx->addr); + if (target) { + BT_WARN("Target 0x%04x failed to apply image: %s", ctx->addr, + bt_hex(cli->xfer.slot->fwid, cli->xfer.slot->fwid_len)); + target->phase = BLE_MESH_DFU_PHASE_APPLY_FAIL; + target_failed(cli, target, BLE_MESH_DFU_ERR_INTERNAL); + blob_cli_broadcast_rsp(&cli->blob, &target->blob); + } + + bt_mesh_dfu_cli_rm_req_from_list(req); + req_free(req); + + return 0; } static int handle_metadata_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfu_cli *cli = mod->rt->user_data; - struct bt_mesh_dfu_metadata_status *rsp = cli->req.params; - uint8_t hdr, idx; + bt_mesh_dfu_cli_req_t *req = NULL; + struct bt_mesh_dfu_metadata_status *rsp = NULL; + uint8_t hdr, idx; - hdr = net_buf_simple_pull_u8(buf); - idx = net_buf_simple_pull_u8(buf); + hdr = net_buf_simple_pull_u8(buf); + idx = net_buf_simple_pull_u8(buf); - if (cli->req.type != REQ_METADATA || ctx->addr != cli->req.addr || - idx != rsp->idx) { - LOG_WRN("Unexpected metadata status from 0x%04x img %u", - ctx->addr, idx); - if (cli->req.type != REQ_METADATA) { - LOG_WRN("Expected %u", cli->req.type); - } else { - LOG_WRN("Expected 0x%04x img %u", cli->req.addr, idx); - } + req = bt_mesh_dfu_req_find_by_addr(ctx->addr); + if (!req) { + BT_WARN("Unexcept metadata status form 0x%04x", ctx->addr); + return 0; + } - return 0; - } + rsp = req->params; - rsp->status = hdr & BIT_MASK(3); - rsp->effect = (hdr >> 3); - k_sem_give(&cli->req.sem); + if (req->type != REQ_METADATA || + idx != rsp->idx) { + BT_WARN("Unexpected metadata status from 0x%04x img %u", + ctx->addr, idx); + if (req->type != REQ_METADATA) { + BT_WARN("Expected %u", req->type); + } else { + BT_WARN("Expected 0x%04x img %u", req->ctx.addr, idx); + } - return 0; + return 0; + } + + rsp->status = hdr & BIT_MASK(3); + rsp->effect = (hdr >> 3); + + bt_mesh_dfu_client_cb_evt_to_btc(req->opcode, BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP, + req->dfu_cli->mod, &req->ctx, req->params, + sizeof(struct bt_mesh_dfu_metadata_status)); + + bt_mesh_free(rsp); + bt_mesh_dfu_cli_rm_req_from_list(req); + req_free(req); + + return 0; } const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[] = { - {BT_MESH_DFU_OP_UPDATE_STATUS, BT_MESH_LEN_MIN(1), handle_status}, - {BT_MESH_DFU_OP_UPDATE_INFO_STATUS, BT_MESH_LEN_MIN(2), handle_info_status}, - {BT_MESH_DFU_OP_UPDATE_METADATA_STATUS, BT_MESH_LEN_EXACT(2), handle_metadata_status}, - BT_MESH_MODEL_OP_END, + {BLE_MESH_DFU_OP_UPDATE_STATUS, 1, (void *)handle_status}, + {BLE_MESH_DFU_OP_UPDATE_INFO_STATUS, 2, (void *)handle_info_status}, + {BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS, 2, (void *)handle_metadata_status}, + BLE_MESH_MODEL_OP_END, }; -static int dfu_cli_init(const struct bt_mesh_model *mod) +static int dfu_cli_init(struct bt_mesh_model *mod) { - struct bt_mesh_dfu_cli *cli = mod->rt->user_data; + struct bt_mesh_dfu_cli *cli = mod->user_data; - if (mod->rt->elem_idx != 0) { - LOG_ERR("DFU update client must be instantiated on first elem"); - return -EINVAL; - } + if (mod->elem_idx != 0) { + BT_ERR("DFU update client must be instantiated on first elem"); + return -EINVAL; + } - cli->mod = mod; + cli->mod = mod; - if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) { - bt_mesh_model_extend(mod, cli->blob.mod); - } + cli->blob.cb = &_bt_mesh_dfu_cli_blob_handlers; - k_sem_init(&cli->req.sem, 0, 1); + bt_mesh_dfu_cli_req_list_init(); - return 0; + return 0; } -static void dfu_cli_reset(const struct bt_mesh_model *mod) +static void dfu_cli_reset(struct bt_mesh_model *mod) { - struct bt_mesh_dfu_cli *cli = mod->rt->user_data; + struct bt_mesh_dfu_cli *cli = mod->user_data; - cli->req.type = REQ_NONE; - cli->req.addr = BT_MESH_ADDR_UNASSIGNED; - cli->req.img_cnt = 0; - cli->req.img_cb = NULL; - cli->xfer.state = STATE_IDLE; - cli->xfer.flags = 0; + bt_mesh_dfu_req_list_free(); + cli->req = NULL; + cli->xfer.state = STATE_IDLE; + cli->xfer.flags = 0; +} + +static int dfu_cli_deinit(struct bt_mesh_model *mod) +{ + dfu_cli_reset(mod); + return 0; } const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb = { - .init = dfu_cli_init, - .reset = dfu_cli_reset, + .init = dfu_cli_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = dfu_cli_deinit, +#endif }; /******************************************************************************* @@ -1003,263 +1209,303 @@ const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb = { ******************************************************************************/ int bt_mesh_dfu_cli_send(struct bt_mesh_dfu_cli *cli, - const struct bt_mesh_blob_cli_inputs *inputs, - const struct bt_mesh_blob_io *io, - const struct bt_mesh_dfu_cli_xfer *xfer) + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_io *io, + const struct bt_mesh_dfu_cli_xfer *xfer) { - struct bt_mesh_dfu_target *target; + struct bt_mesh_dfu_target *target; - if (bt_mesh_dfu_cli_is_busy(cli)) { - return -EBUSY; - } + if (bt_mesh_dfu_cli_is_busy(cli)) { + return -EBUSY; + } - cli->xfer.blob.mode = xfer->mode; - cli->xfer.blob.size = xfer->slot->size; + cli->xfer.blob.mode = xfer->mode; + cli->xfer.blob.size = xfer->slot->size; - if (xfer->blob_id == 0) { - int err = bt_rand(&cli->xfer.blob.id, sizeof(cli->xfer.blob.id)); + if (xfer->blob_id == 0) { + bt_mesh_rand(&cli->xfer.blob.id, sizeof(cli->xfer.blob.id)); + } else { + cli->xfer.blob.id = xfer->blob_id; + } - if (err) { - return err; - } - } else { - cli->xfer.blob.id = xfer->blob_id; - } + cli->xfer.io = io; + cli->blob.inputs = inputs; + cli->xfer.slot = xfer->slot; + cli->xfer.flags = 0U; - cli->xfer.io = io; - cli->blob.inputs = inputs; - cli->xfer.slot = xfer->slot; - cli->xfer.flags = 0U; + if (xfer->blob_params) { + cli->xfer.flags |= FLAG_SKIP_CAPS_GET; + cli->xfer.blob.block_size_log = xfer->blob_params->block_size_log; + cli->xfer.blob.chunk_size = xfer->blob_params->chunk_size; + } - if (xfer->blob_params) { - cli->xfer.flags |= FLAG_SKIP_CAPS_GET; - cli->xfer.blob.block_size_log = xfer->blob_params->block_size_log; - cli->xfer.blob.chunk_size = xfer->blob_params->chunk_size; - } + /* Phase will be set based on target status messages: */ + TARGETS_FOR_EACH(cli, target) { + target->status = BLE_MESH_DFU_SUCCESS; + target->phase = BLE_MESH_DFU_PHASE_UNKNOWN; + } - /* Phase will be set based on target status messages: */ - TARGETS_FOR_EACH(cli, target) { - target->status = BT_MESH_DFU_SUCCESS; - target->phase = BT_MESH_DFU_PHASE_UNKNOWN; - } - - initiate(cli); - return 0; + initiate(cli); + return 0; } int bt_mesh_dfu_cli_suspend(struct bt_mesh_dfu_cli *cli) { - int err; + int err; - err = bt_mesh_blob_cli_suspend(&cli->blob); - if (!err) { - cli->xfer.state = STATE_SUSPENDED; - } + err = bt_mesh_blob_cli_suspend(&cli->blob); + if (!err) { + cli->xfer.state = STATE_SUSPENDED; + } - return err; + return err; } int bt_mesh_dfu_cli_resume(struct bt_mesh_dfu_cli *cli) { - struct bt_mesh_dfu_target *target; + struct bt_mesh_dfu_target *target; - if (cli->xfer.state != STATE_SUSPENDED) { - return -EINVAL; - } + if (cli->xfer.state != STATE_SUSPENDED) { + return -EINVAL; + } - cli->xfer.flags = FLAG_RESUME; + cli->xfer.flags = FLAG_RESUME; - /* Restore timed out targets. */ - TARGETS_FOR_EACH(cli, target) { - if (!!target->blob.timedout) { - target->status = BT_MESH_DFU_SUCCESS; - target->phase = BT_MESH_DFU_PHASE_UNKNOWN; - } - } + /* Restore timed out targets. */ + TARGETS_FOR_EACH(cli, target) { + if (!!target->blob.timedout) { + target->status = BLE_MESH_DFU_SUCCESS; + target->phase = BLE_MESH_DFU_PHASE_UNKNOWN; + } + } - initiate(cli); - return 0; + initiate(cli); + return 0; } int bt_mesh_dfu_cli_cancel(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_msg_ctx *ctx) + struct bt_mesh_msg_ctx *ctx) { - if (ctx) { - int err; + bt_mesh_dfu_cli_req_t *req = NULL; + if (ctx) { + int err; + req = req_alloc(); + if (!req) { + return -ENOMEM; + } + cli->req = req; + err = req_setup(cli, REQ_STATUS, BLE_MESH_DFU_OP_UPDATE_CANCEL, ctx, NULL); + if (err) { + return err; + } + bt_mesh_dfu_cli_add_req_to_list(req); - err = req_setup(cli, REQ_STATUS, ctx->addr, NULL); - if (err) { - return err; - } + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_CANCEL, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_CANCEL); - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_CANCEL, 0); - bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_CANCEL); + err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); + if (err) { + cli->req->type = REQ_NONE; + return err; + } - err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); - if (err) { - cli->req.type = REQ_NONE; - return err; - } + return req_wait(cli, K_MSEC(dfu_cli_timeout)); + } - return req_wait(cli, K_MSEC(dfu_cli_timeout)); - } + if (cli->xfer.state == STATE_IDLE) { + return -EALREADY; + } - if (cli->xfer.state == STATE_IDLE) { - return -EALREADY; - } - - cli->xfer.state = STATE_CANCEL; - blob_cli_broadcast_abort(&cli->blob); - cancel(cli); - return 0; + cli->xfer.state = STATE_CANCEL; + blob_cli_broadcast_abort(&cli->blob); + cancel(cli); + return 0; } int bt_mesh_dfu_cli_apply(struct bt_mesh_dfu_cli *cli) { - if (cli->xfer.state != STATE_VERIFIED) { - return -EBUSY; - } + if (cli->xfer.state != STATE_VERIFIED) { + return -EBUSY; + } - apply(cli); + apply(cli); - return 0; + return 0; } int bt_mesh_dfu_cli_confirm(struct bt_mesh_dfu_cli *cli) { - if (cli->xfer.state != STATE_APPLIED) { - return -EBUSY; - } + bt_mesh_dfu_cli_req_t *req = NULL; - cli->xfer.state = STATE_CONFIRM; - confirm(cli); + if (cli->xfer.state != STATE_APPLIED) { + return -EBUSY; + } - return 0; + req = req_alloc(); + if (!req) { + BT_ERR("%s: alloc req failed", req); + return -ENOMEM; + } + + cli->req = req; + req_setup(cli, INTERNAL_REQ_IMG, BLE_MESH_DFU_OP_UPDATE_INFO_GET, NULL, NULL); + bt_mesh_dfu_cli_add_req_to_list(req); + + cli->xfer.state = STATE_CONFIRM; + confirm(cli); + + return 0; } uint8_t bt_mesh_dfu_cli_progress(struct bt_mesh_dfu_cli *cli) { - if (cli->xfer.state == STATE_TRANSFER) { - return bt_mesh_blob_cli_xfer_progress_active_get(&cli->blob); - } + if (cli->xfer.state == STATE_TRANSFER) { + return bt_mesh_blob_cli_xfer_progress_active_get(&cli->blob); + } - if (cli->xfer.state == STATE_IDLE) { - if (cli->xfer.flags & FLAG_COMPLETED) { - return 100U; - } - return 0U; - } + if (cli->xfer.state == STATE_IDLE) { + if (cli->xfer.flags & FLAG_COMPLETED) { + return 100U; + } + return 0U; + } - return 100U; + return 100U; } bool bt_mesh_dfu_cli_is_busy(struct bt_mesh_dfu_cli *cli) { - return (cli->xfer.state == STATE_TRANSFER || - cli->xfer.state == STATE_REFRESH || - cli->xfer.state == STATE_APPLY || - cli->xfer.state == STATE_CONFIRM) && - !(cli->xfer.flags & FLAG_FAILED); + return (cli->xfer.state == STATE_TRANSFER || + cli->xfer.state == STATE_REFRESH || + cli->xfer.state == STATE_APPLY || + cli->xfer.state == STATE_CONFIRM) && + !(cli->xfer.flags & FLAG_FAILED); } int bt_mesh_dfu_cli_imgs_get(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_msg_ctx *ctx, - bt_mesh_dfu_img_cb_t cb, void *cb_data, - uint8_t max_count) + struct bt_mesh_msg_ctx *ctx, + bt_mesh_dfu_img_cb_t cb, void *cb_data, + uint8_t first_idx, uint8_t max_count) { - int err; + int err; - if (cli->req.img_cb) { - return -EBUSY; - } + if (bt_mesh_dfu_req_find_by_addr(ctx->addr)) { + BT_WARN("Exists waiting request"); + return -EBUSY; + } - err = req_setup(cli, REQ_IMG, ctx->addr, NULL); - if (err) { - return err; - } + cli->req = req_alloc(); + if (!cli->req) { + return -ENOMEM; + } - cli->req.img_cb = cb; - cli->req.params = cb_data; - cli->req.ttl = ctx->send_ttl; - cli->req.img_cnt = max_count; + err = req_setup(cli, REQ_IMG, BLE_MESH_DFU_OP_UPDATE_INFO_GET, ctx, cb_data); + if (err) { + req_free(cli->req); + return err; + } - err = info_get(cli, ctx, 0, cli->req.img_cnt, NULL); - if (err) { - cli->req.img_cb = NULL; - cli->req.type = REQ_NONE; - return err; - } + cli->req->img_cb = cb; + cli->req->ttl = ctx->send_ttl; + cli->req->img_cnt = max_count; - err = req_wait(cli, K_MSEC(dfu_cli_timeout)); + err = info_get(cli, ctx, first_idx, cli->req->img_cnt, NULL); + if (err) { + cli->req->img_cb = NULL; + cli->req->type = REQ_NONE; + req_free(cli->req); + return err; + } - cli->req.img_cb = NULL; + err = req_wait(cli, K_MSEC(dfu_cli_timeout)); - return err; + return err; } int bt_mesh_dfu_cli_metadata_check(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_msg_ctx *ctx, uint8_t img_idx, - const struct bt_mesh_dfu_slot *slot, - struct bt_mesh_dfu_metadata_status *rsp) + struct bt_mesh_msg_ctx *ctx, uint8_t img_idx, + struct net_buf_simple *metadata) { - int err; + int err; + bt_mesh_dfu_cli_req_t *req = NULL; - err = req_setup(cli, REQ_METADATA, ctx->addr, rsp); - if (err) { - return err; - } + struct bt_mesh_dfu_metadata_status *rsp = bt_mesh_calloc(sizeof(struct bt_mesh_dfu_metadata_status)); + if (!rsp) { + BT_ERR("Alloc metadata status failed"); + return -ENOMEM; + } + req = req_alloc(); + if (!req) { + return -ENOMEM; + } + cli->req = req; + err = req_setup(cli, REQ_METADATA, BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK, ctx, rsp); + if (err) { + return err; + } - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_METADATA_CHECK, - 1 + CONFIG_BT_MESH_DFU_METADATA_MAXLEN); - bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_METADATA_CHECK); + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK, + 1 + CONFIG_BLE_MESH_DFU_METADATA_MAXLEN); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK); - net_buf_simple_add_u8(&buf, img_idx); + net_buf_simple_add_u8(&buf, img_idx); - if (slot->metadata_len) { - net_buf_simple_add_mem(&buf, slot->metadata, - slot->metadata_len); - } + if (metadata) { + net_buf_simple_add_mem(&buf, metadata->data, metadata->len); + } - rsp->idx = img_idx; + rsp->idx = img_idx; - err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); - if (err) { - cli->req.type = REQ_NONE; - return err; - } + err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); + if (err) { + cli->req->type = REQ_NONE; + return err; + } - return req_wait(cli, K_MSEC(dfu_cli_timeout)); + return req_wait(cli, K_MSEC(dfu_cli_timeout)); } int bt_mesh_dfu_cli_status_get(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_msg_ctx *ctx, - struct bt_mesh_dfu_target_status *rsp) + struct bt_mesh_msg_ctx *ctx) { - int err; + int err; + bt_mesh_dfu_cli_req_t *req = NULL; - err = req_setup(cli, REQ_STATUS, ctx->addr, rsp); - if (err) { - return err; - } + struct bt_mesh_dfu_target_status *rsp = bt_mesh_calloc(sizeof(struct bt_mesh_dfu_target_status)); + if (!rsp) { + BT_ERR("dfu target status alloc failed"); + return -ENOMEM; + } - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_GET, 0); - bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_GET); + req = req_alloc(); + if (!req) { + return -ENOMEM; + } + cli->req = req; + err = req_setup(cli, REQ_STATUS, BLE_MESH_DFU_OP_UPDATE_GET, ctx, rsp); + if (err) { + return err; + } - err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); - if (err) { - cli->req.type = REQ_NONE; - return err; - } + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_GET, 0); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_GET); - return req_wait(cli, K_MSEC(dfu_cli_timeout)); + err = bt_mesh_model_send(cli->mod, ctx, &buf, NULL, NULL); + if (err) { + cli->req->type = REQ_NONE; + return err; + } + + return req_wait(cli, K_MSEC(dfu_cli_timeout)); } int32_t bt_mesh_dfu_cli_timeout_get(void) { - return dfu_cli_timeout; + return dfu_cli_timeout; } void bt_mesh_dfu_cli_timeout_set(int32_t t) { - dfu_cli_timeout = t; + dfu_cli_timeout = t; } +#endif /* CONFIG_BLE_MESH_DFU_CLI */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c index 51a2cd0306..9c966c5e38 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_metadata.c @@ -1,102 +1,105 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include #include -#include #include "crypto.h" #include "access.h" +#include "mesh/byteorder.h" +#include "mesh/buf.h" +#include "mesh_v1.1/dfu/dfu_metadata.h" +#if CONFIG_BLE_MESH_DFU_METADATA int bt_mesh_dfu_metadata_decode(struct net_buf_simple *buf, - struct bt_mesh_dfu_metadata *metadata) + struct bt_mesh_dfu_metadata *metadata) { - if (buf->len < 12) { - return -EMSGSIZE; - } + if (buf->len < 12) { + return -EMSGSIZE; + } - metadata->fw_ver.major = net_buf_simple_pull_u8(buf); - metadata->fw_ver.minor = net_buf_simple_pull_u8(buf); - metadata->fw_ver.revision = net_buf_simple_pull_le16(buf); - metadata->fw_ver.build_num = net_buf_simple_pull_le32(buf); - metadata->fw_size = net_buf_simple_pull_le24(buf); - metadata->fw_core_type = net_buf_simple_pull_u8(buf); + metadata->fw_ver.major = net_buf_simple_pull_u8(buf); + metadata->fw_ver.minor = net_buf_simple_pull_u8(buf); + metadata->fw_ver.revision = net_buf_simple_pull_le16(buf); + metadata->fw_ver.build_num = net_buf_simple_pull_le32(buf); + metadata->fw_size = net_buf_simple_pull_le24(buf); + metadata->fw_core_type = net_buf_simple_pull_u8(buf); - if (metadata->fw_core_type & BT_MESH_DFU_FW_CORE_TYPE_APP) { - if (buf->len < 6) { - return -EMSGSIZE; - } + if (metadata->fw_core_type & BLE_MESH_DFU_FW_CORE_TYPE_APP) { + if (buf->len < 6) { + return -EMSGSIZE; + } - metadata->comp_hash = net_buf_simple_pull_le32(buf); - metadata->elems = net_buf_simple_pull_le16(buf); - } + metadata->comp_hash = net_buf_simple_pull_le32(buf); + metadata->elems = net_buf_simple_pull_le16(buf); + } - metadata->user_data = buf->len > 0 ? buf->data : NULL; - metadata->user_data_len = buf->len; + metadata->user_data = buf->len > 0 ? buf->data : NULL; + metadata->user_data_len = buf->len; - return 0; + return 0; } - int bt_mesh_dfu_metadata_encode(const struct bt_mesh_dfu_metadata *metadata, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - size_t md_len_min = 12 + metadata->user_data_len; + size_t md_len_min = 12 + metadata->user_data_len; - if (metadata->fw_core_type & BT_MESH_DFU_FW_CORE_TYPE_APP) { - md_len_min += 6; - } + if (metadata->fw_core_type & BLE_MESH_DFU_FW_CORE_TYPE_APP) { + md_len_min += 6; + } - if (net_buf_simple_tailroom(buf) < md_len_min) { - return -EMSGSIZE; - } + if (net_buf_simple_tailroom(buf) < md_len_min) { + return -EMSGSIZE; + } - net_buf_simple_add_u8(buf, metadata->fw_ver.major); - net_buf_simple_add_u8(buf, metadata->fw_ver.minor); - net_buf_simple_add_le16(buf, metadata->fw_ver.revision); - net_buf_simple_add_le32(buf, metadata->fw_ver.build_num); - net_buf_simple_add_le24(buf, metadata->fw_size); - net_buf_simple_add_u8(buf, metadata->fw_core_type); - net_buf_simple_add_le32(buf, metadata->comp_hash); - net_buf_simple_add_le16(buf, metadata->elems); + net_buf_simple_add_u8(buf, metadata->fw_ver.major); + net_buf_simple_add_u8(buf, metadata->fw_ver.minor); + net_buf_simple_add_le16(buf, metadata->fw_ver.revision); + net_buf_simple_add_le32(buf, metadata->fw_ver.build_num); + net_buf_simple_add_le24(buf, metadata->fw_size); + net_buf_simple_add_u8(buf, metadata->fw_core_type); + net_buf_simple_add_le32(buf, metadata->comp_hash); + net_buf_simple_add_le16(buf, metadata->elems); - if (metadata->user_data_len > 0) { - net_buf_simple_add_mem(buf, metadata->user_data, metadata->user_data_len); - } + if (metadata->user_data_len > 0) { + net_buf_simple_add_mem(buf, metadata->user_data, metadata->user_data_len); + } - return 0; + return 0; } int bt_mesh_dfu_metadata_comp_hash_get(struct net_buf_simple *buf, uint8_t *key, uint32_t *hash) { - uint8_t mac[16]; - int err; - struct bt_mesh_sg sg = {.data = buf->data, .len = buf->len}; + uint8_t mac[16]; + int err; + struct bt_mesh_sg sg = {.data = buf->data, .len = buf->len}; - err = bt_mesh_aes_cmac_raw_key(key, &sg, 1, mac); - if (err) { - return err; - } + /* The implementation of this function is the same as function `bt_mesh_aes_cmac_raw_key` in Zephyr. */ + err = bt_mesh_aes_cmac(key, &sg, 1, mac); + if (err) { + return err; + } - *hash = sys_get_le32(mac); + *hash = sys_get_le32(mac); - return 0; + return 0; } int bt_mesh_dfu_metadata_comp_hash_local_get(uint8_t *key, uint32_t *hash) { - NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX); - int err; + NET_BUF_SIMPLE_DEFINE(buf, BLE_MESH_TX_SDU_MAX); + int err; - err = bt_mesh_comp_data_get_page_0(&buf, 0); - if (err) { - return err; - } + err = bt_mesh_get_comp_data(&buf, 0, 0, true); + if (err) { + return err; + } - err = bt_mesh_dfu_metadata_comp_hash_get(&buf, key, hash); - return err; + err = bt_mesh_dfu_metadata_comp_hash_get(&buf, key, hash); + return err; } +#endif /* CONFIG_BLE_MESH_DFU_METADATA */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c index c11c16d44f..76f3a87e81 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.c @@ -1,402 +1,444 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include #include "dfu_slot.h" #include #include #include -#include -#include -#define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL -#include -LOG_MODULE_REGISTER(bt_mesh_dfu_slot); +#include "mesh/common.h" +#include "mesh/utils.h" +#include "settings_nvs.h" +#include "settings.h" +#if CONFIG_BLE_MESH_DFU_SLOTS #define SLOT_ENTRY_BUFLEN 25 -#define DFU_SLOT_SETTINGS_PATH "bt/mesh-dfu/slot" +#define DFU_SLOT_SETTINGS_PATH "mesh/dfu/s" #define HEADER_SIZE offsetof(struct slot, slot.fwid) #define PROP_HEADER "h" #define PROP_FWID "id" #define PROP_METADATA "m" +#define SETTINGS_NAME_END '=' +#define SETTINGS_NAME_SEPARATOR '/' static sys_slist_t list; static struct slot { - uint32_t idx; - struct bt_mesh_dfu_slot slot; - sys_snode_t n; -} slots[CONFIG_BT_MESH_DFU_SLOT_CNT]; + uint32_t idx; + struct bt_mesh_dfu_slot slot; + sys_snode_t n; +} slots[CONFIG_BLE_MESH_DFU_SLOT_CNT]; static uint32_t slot_index; -static char *slot_entry_encode(uint16_t idx, char buf[SLOT_ENTRY_BUFLEN], - const char *property) +inline int settings_name_next(const char *name, const char **next) { - snprintf(buf, SLOT_ENTRY_BUFLEN, DFU_SLOT_SETTINGS_PATH "/%x/%s", idx, - property); + int rc = 0; - return buf; + if (next) { + *next = NULL; + } + + if (!name) { + return 0; + } + + /* name might come from flash directly, in flash the name would end + * with '=' or '\0' depending how storage is done. Flash reading is + * limited to what can be read + */ + while ((*name != '\0') && (*name != SETTINGS_NAME_END) && + (*name != SETTINGS_NAME_SEPARATOR)) { + rc++; + name++; + } + + if (*name == SETTINGS_NAME_SEPARATOR) { + if (next) { + *next = name + 1; + } + return rc; + } + + return rc; } -static bool slot_eq(const struct bt_mesh_dfu_slot *slot, - const uint8_t *fwid, size_t fwid_len) +#if CONFIG_BLE_MESH_SETTINGS +static char *slot_entry_encode(uint16_t idx, char buf[SLOT_ENTRY_BUFLEN], + const char *property) { - return (slot->fwid_len == fwid_len) && - !memcmp(fwid, slot->fwid, fwid_len); + snprintf(buf, SLOT_ENTRY_BUFLEN, DFU_SLOT_SETTINGS_PATH "/%x/%s", idx, + property); + + return buf; +} +#endif + +static bool slot_eq(const struct bt_mesh_dfu_slot *slot, + const uint8_t *fwid, size_t fwid_len) +{ + return (slot->fwid_len == fwid_len) && + !memcmp(fwid, slot->fwid, fwid_len); } static bool is_slot_committed(struct slot *slot_to_check) { - struct slot *s; + struct slot *s; - SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { - if (s == slot_to_check) { - return true; - } - } + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (s == slot_to_check) { + return true; + } + } - return false; + return false; } static int slot_store(const struct slot *slot_to_store) { - uint16_t idx = ARRAY_INDEX(slots, slot_to_store); - char buf[SLOT_ENTRY_BUFLEN]; - int err; + int err = 0; +#if CONFIG_BLE_MESH_SETTINGS + uint16_t idx = ARRAY_INDEX(slots, slot_to_store); + char buf[SLOT_ENTRY_BUFLEN]; - err = settings_save_one(slot_entry_encode(idx, buf, PROP_HEADER), - slot_to_store, HEADER_SIZE); - if (err) { - return err; - } + err = bt_mesh_save_core_settings(slot_entry_encode(idx, buf, PROP_HEADER), + (uint8_t *)slot_to_store, HEADER_SIZE); + if (err) { + return err; + } - err = settings_save_one(slot_entry_encode(idx, buf, PROP_FWID), - slot_to_store->slot.fwid, slot_to_store->slot.fwid_len); - if (err) { - return err; - } + err = bt_mesh_save_core_settings(slot_entry_encode(idx, buf, PROP_FWID), + slot_to_store->slot.fwid, slot_to_store->slot.fwid_len); + if (err) { + return err; + } - err = settings_save_one(slot_entry_encode(idx, buf, - PROP_METADATA), - slot_to_store->slot.metadata, slot_to_store->slot.metadata_len); + err = bt_mesh_save_core_settings(slot_entry_encode(idx, buf, PROP_METADATA), + slot_to_store->slot.metadata, slot_to_store->slot.metadata_len); - return err; +#endif + return err; } static void slot_erase(struct slot *slot_to_erase) { - uint16_t idx = ARRAY_INDEX(slots, slot_to_erase); - char buf[SLOT_ENTRY_BUFLEN]; +#if CONFIG_BLE_MESH_SETTINGS + uint16_t idx = ARRAY_INDEX(slots, slot_to_erase); + char buf[SLOT_ENTRY_BUFLEN]; - (void)settings_delete(slot_entry_encode(idx, buf, PROP_HEADER)); - (void)settings_delete(slot_entry_encode(idx, buf, PROP_FWID)); - (void)settings_delete(slot_entry_encode(idx, buf, PROP_METADATA)); + bt_mesh_erase_core_settings(slot_entry_encode(idx, buf, PROP_HEADER)); + bt_mesh_erase_core_settings(slot_entry_encode(idx, buf, PROP_FWID)); + bt_mesh_erase_core_settings(slot_entry_encode(idx, buf, PROP_METADATA)); +#endif } static void slot_index_defrag(void) { - slot_index = 0; - struct slot *s; + slot_index = 0; + struct slot *s; - SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { - s->idx = ++slot_index; - slot_store(s); - } + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + s->idx = ++slot_index; + slot_store(s); + } } int bt_mesh_dfu_slot_count(void) { - int cnt = 0; - sys_snode_t *n; + int cnt = 0; + sys_snode_t *n; - SYS_SLIST_FOR_EACH_NODE(&list, n) { - cnt++; - } + SYS_SLIST_FOR_EACH_NODE(&list, n) { + cnt++; + } - return cnt; + return cnt; } struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_reserve(void) { - struct slot *slot = NULL; + struct slot *slot = NULL; - for (int i = 0; i < ARRAY_SIZE(slots); ++i) { - if (slots[i].idx == 0) { - slot = &slots[i]; - break; - } - } + for (int i = 0; i < ARRAY_SIZE(slots); ++i) { + if (slots[i].idx == 0) { + slot = &slots[i]; + break; + } + } - if (!slot) { - LOG_WRN("No space"); - return NULL; - } + if (!slot) { + BT_WARN("No space"); + return NULL; + } - if (slot_index == UINT32_MAX) { - slot_index_defrag(); - } + if (slot_index == UINT32_MAX) { + slot_index_defrag(); + } - slot->slot.fwid_len = 0; - slot->slot.metadata_len = 0; - slot->slot.size = 0; - slot->idx = ++slot_index; + slot->slot.fwid_len = 0; + slot->slot.metadata_len = 0; + slot->slot.size = 0; + slot->idx = ++slot_index; - LOG_DBG("Reserved slot #%u", slot - &slots[0]); + BT_DBG("Reserved slot #%u", slot - &slots[0]); - return &slot->slot; + return &slot->slot; } int bt_mesh_dfu_slot_info_set(struct bt_mesh_dfu_slot *dfu_slot, size_t size, - const uint8_t *metadata, size_t metadata_len) + const uint8_t *metadata, size_t metadata_len) { - struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); - if (metadata_len > CONFIG_BT_MESH_DFU_METADATA_MAXLEN) { - return -EFBIG; - } + if (metadata_len > CONFIG_BLE_MESH_DFU_METADATA_MAXLEN) { + return -EFBIG; + } - if (slot->idx == 0 || is_slot_committed(slot)) { - return -EINVAL; - } + if (slot->idx == 0 || is_slot_committed(slot)) { + return -EINVAL; + } - slot->slot.size = size; - slot->slot.metadata_len = metadata_len; - memcpy(slot->slot.metadata, metadata, metadata_len); - return 0; + slot->slot.size = size; + slot->slot.metadata_len = metadata_len; + memcpy(slot->slot.metadata, metadata, metadata_len); + return 0; } int bt_mesh_dfu_slot_fwid_set(struct bt_mesh_dfu_slot *dfu_slot, - const uint8_t *fwid, size_t fwid_len) + const uint8_t *fwid, size_t fwid_len) { - struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); - if (fwid_len > CONFIG_BT_MESH_DFU_FWID_MAXLEN) { - return -EFBIG; - } + if (fwid_len > CONFIG_BLE_MESH_DFU_FWID_MAXLEN) { + return -EFBIG; + } - if (slot->idx == 0 || is_slot_committed(slot)) { - return -EINVAL; - } + if (slot->idx == 0) { + return -EINVAL; + } - for (int i = 0; i < ARRAY_SIZE(slots); i++) { - if (slots[i].idx != 0 && - slot_eq(&slots[i].slot, fwid, fwid_len)) { - return is_slot_committed(&slots[i]) ? - -EEXIST : -EALREADY; - } - } + if (is_slot_committed(slot)) { + return -EEXIST; + } - slot->slot.fwid_len = fwid_len; - memcpy(slot->slot.fwid, fwid, fwid_len); - return 0; + for (int i = 0; i < ARRAY_SIZE(slots); i++) { + if (slots[i].idx != 0 && + slot_eq(&slots[i].slot, fwid, fwid_len)) { + return -EALREADY; + } + } + + slot->slot.fwid_len = fwid_len; + memcpy(slot->slot.fwid, fwid, fwid_len); + return 0; } int bt_mesh_dfu_slot_commit(struct bt_mesh_dfu_slot *dfu_slot) { - int err; - struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + int err; + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); - if (slot->idx == 0 || - slot->slot.fwid_len == 0 || - slot->slot.size == 0 || - is_slot_committed(slot)) { - return -EINVAL; - } + if (slot->idx == 0 || + slot->slot.fwid_len == 0 || + slot->slot.size == 0 || + is_slot_committed(slot)) { + return -EINVAL; + } - err = slot_store(slot); - if (err) { - LOG_WRN("Store failed (err: %d)", err); - return err; - } + err = slot_store(slot); + if (err) { + BT_WARN("Store failed (err: %d)", err); + return err; + } - sys_slist_append(&list, &slot->n); + sys_slist_append(&list, &slot->n); - LOG_DBG("Stored slot #%u: %s", ARRAY_INDEX(slots, slot), - bt_hex(slot->slot.fwid, slot->slot.fwid_len)); - return 0; + BT_DBG("Stored slot #%u: %s", ARRAY_INDEX(slots, slot), + bt_hex(slot->slot.fwid, slot->slot.fwid_len)); + return 0; } void bt_mesh_dfu_slot_release(const struct bt_mesh_dfu_slot *dfu_slot) { - struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); - if (is_slot_committed(slot)) { - return; - } + if (is_slot_committed(slot)) { + return; + } - slot->idx = 0; + slot->idx = 0; } int bt_mesh_dfu_slot_del(const struct bt_mesh_dfu_slot *dfu_slot) { - struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); + struct slot *slot = CONTAINER_OF(dfu_slot, struct slot, slot); - if (!sys_slist_find_and_remove(&list, &slot->n)) { - return -EINVAL; - } + if (!sys_slist_find_and_remove(&list, &slot->n)) { + return -EINVAL; + } - int idx = ARRAY_INDEX(slots, slot); + int idx = ARRAY_INDEX(slots, slot); - LOG_DBG("%u", idx); + BT_DBG("%u", idx); - slot_erase(slot); - slot->idx = 0; + slot_erase(slot); + slot->idx = 0; - return 0; + return 0; } void bt_mesh_dfu_slot_del_all(void) { - struct slot *s; - SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { - slot_erase(s); - s->idx = 0; - } + struct slot *s; + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + slot_erase(s); + s->idx = 0; + } - sys_slist_init(&list); + sys_slist_init(&list); } const struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_at(uint16_t img_idx) { - struct slot *s; + struct slot *s; - SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { - if (!img_idx--) { - return &s->slot; - } - } + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (!img_idx--) { + return &s->slot; + } + } - return NULL; + return NULL; } int bt_mesh_dfu_slot_get(const uint8_t *fwid, size_t fwid_len, struct bt_mesh_dfu_slot **slot) { - struct slot *s; - int idx = 0; + struct slot *s; + int idx = 0; - SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { - if (slot_eq(&s->slot, fwid, fwid_len)) { - if (slot) { - *slot = &s->slot; - } - return idx; - } - idx++; - } + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (slot_eq(&s->slot, fwid, fwid_len)) { + if (slot) { + *slot = &s->slot; + } + return idx; + } + idx++; + } - return -ENOENT; + return -ENOENT; } int bt_mesh_dfu_slot_img_idx_get(const struct bt_mesh_dfu_slot *dfu_slot) { - struct slot *s; - int idx = 0; + struct slot *s; + int idx = 0; - SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { - if (&s->slot == dfu_slot) { - return idx; - } - idx++; - } + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (&s->slot == dfu_slot) { + return idx; + } + idx++; + } - return -ENOENT; + return -ENOENT; } size_t bt_mesh_dfu_slot_foreach(bt_mesh_dfu_slot_cb_t cb, void *user_data) { - enum bt_mesh_dfu_iter iter; - size_t cnt = 0; - struct slot *s; + enum bt_mesh_dfu_iter iter; + size_t cnt = 0; + struct slot *s; - SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { - cnt++; + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + cnt++; - if (!cb) { - continue; - } + if (!cb) { + continue; + } - iter = cb(&s->slot, user_data); - if (iter != BT_MESH_DFU_ITER_CONTINUE) { - break; - } - } + iter = cb(&s->slot, user_data); + if (iter != BLE_MESH_DFU_ITER_CONTINUE) { + break; + } + } - return cnt; + return cnt; } +#if 0 static int slot_data_load(const char *key, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) + settings_read_cb read_cb, void *cb_arg) { - const char *prop; - size_t len; - uint16_t idx; + const char *prop; + size_t len; + uint16_t idx; - idx = strtol(key, NULL, 16); + idx = strtol(key, NULL, 16); - if (idx >= ARRAY_SIZE(slots)) { - return 0; - } + if (idx >= ARRAY_SIZE(slots)) { + return 0; + } - len = settings_name_next(key, &prop); + len = settings_name_next(key, &prop); - if (!strncmp(prop, PROP_HEADER, len)) { - if (read_cb(cb_arg, &slots[idx], HEADER_SIZE) > 0) { - struct slot *s, *prev = NULL; + if (!strncmp(prop, PROP_HEADER, len)) { + if (read_cb(cb_arg, &slots[idx], HEADER_SIZE) > 0) { + struct slot *s, *prev = NULL; - SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { - if (s->idx > slots[idx].idx) { - break; - } + SYS_SLIST_FOR_EACH_CONTAINER(&list, s, n) { + if (s->idx > slots[idx].idx) { + break; + } - prev = s; - } + prev = s; + } - if (prev == NULL) { - sys_slist_prepend(&list, &slots[idx].n); - } else { - sys_slist_insert(&list, &prev->n, &slots[idx].n); - } + if (prev == NULL) { + sys_slist_prepend(&list, &slots[idx].n); + } else { + sys_slist_insert(&list, &prev->n, &slots[idx].n); + } - if (slots[idx].idx >= slot_index) { - slot_index = slots[idx].idx + 1; - } - } - return 0; - } + if (slots[idx].idx >= slot_index) { + slot_index = slots[idx].idx + 1; + } + } + return 0; + } - if (!strncmp(prop, PROP_FWID, len)) { - if (read_cb(cb_arg, &slots[idx].slot.fwid, - sizeof(slots[idx].slot.fwid)) < 0) { - slots[idx].idx = 0; - sys_slist_find_and_remove(&list, &slots[idx].n); - return 0; - } + if (!strncmp(prop, PROP_FWID, len)) { + if (read_cb(cb_arg, &slots[idx].slot.fwid, + sizeof(slots[idx].slot.fwid)) < 0) { + slots[idx].idx = 0; + sys_slist_find_and_remove(&list, &slots[idx].n); + return 0; + } - slots[idx].slot.fwid_len = len_rd; - return 0; - } + slots[idx].slot.fwid_len = len_rd; + return 0; + } - if (!strncmp(prop, PROP_METADATA, len)) { - if (read_cb(cb_arg, &slots[idx].slot.metadata, - sizeof(slots[idx].slot.metadata)) < 0) { - slots[idx].idx = 0; - sys_slist_find_and_remove(&list, &slots[idx].n); - return 0; - } + if (!strncmp(prop, PROP_METADATA, len)) { + if (read_cb(cb_arg, &slots[idx].slot.metadata, + sizeof(slots[idx].slot.metadata)) < 0) { + slots[idx].idx = 0; + sys_slist_find_and_remove(&list, &slots[idx].n); + return 0; + } - slots[idx].slot.metadata_len = len_rd; - return 0; - } + slots[idx].slot.metadata_len = len_rd; + return 0; + } - return 0; + return 0; } - -SETTINGS_STATIC_HANDLER_DEFINE(bt_mesh_dfu_slots, DFU_SLOT_SETTINGS_PATH, NULL, - slot_data_load, NULL, NULL); +#endif +#endif /* CONFIG_BLE_MESH_DFU_SLOTS */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h index 969c6d3d25..7509ad24a6 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_slot.h @@ -1,11 +1,12 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include - +#include "mesh_v1.1/dfu/dfu.h" +#if CONFIG_BLE_MESH_DFU_SLOTS /** @brief Slot iteration callback. * * @param slot A valid DFU image slot. @@ -13,8 +14,8 @@ * * @return Iteration action determining next step. */ -typedef enum bt_mesh_dfu_iter (*bt_mesh_dfu_slot_cb_t)( - const struct bt_mesh_dfu_slot *slot, void *user_data); +typedef enum bt_mesh_dfu_iter(*bt_mesh_dfu_slot_cb_t) +(const struct bt_mesh_dfu_slot *slot, void *user_data); /** @brief Get the number of slots committed to the firmware list. * @@ -41,24 +42,24 @@ struct bt_mesh_dfu_slot *bt_mesh_dfu_slot_reserve(void); * @param size The size of the image. * @param metadata Metadata or NULL. * @param metadata_len Length of the metadata, at most @c - * CONFIG_BT_MESH_DFU_METADATA_MAXLEN. + * CONFIG_BLE_MESH_DFU_METADATA_MAXLEN. * * @return 0 on success, (negative) error code otherwise. */ int bt_mesh_dfu_slot_info_set(struct bt_mesh_dfu_slot *dfu_slot, size_t size, - const uint8_t *metadata, size_t metadata_len); + const uint8_t *metadata, size_t metadata_len); /** @brief Set the new fwid for the incoming image for a reserved slot. * * @param dfu_slot Pointer to the reserved slot for which to set the fwid. * @param fwid Fwid to set. * @param fwid_len Length of the fwid, at most @c - * CONFIG_BT_MESH_DFU_FWID_MAXLEN. + * CONFIG_BLE_MESH_DFU_FWID_MAXLEN. * * @return 0 on success, (negative) error code otherwise. */ int bt_mesh_dfu_slot_fwid_set(struct bt_mesh_dfu_slot *dfu_slot, - const uint8_t *fwid, size_t fwid_len); + const uint8_t *fwid, size_t fwid_len); /** @brief Commit the reserved slot to the list of slots, and store it * persistently. @@ -124,7 +125,7 @@ int bt_mesh_dfu_slot_img_idx_get(const struct bt_mesh_dfu_slot *slot); /** @brief Iterate through all DFU image slots. * * Calls the callback for every DFU image slot or until the callback returns - * something other than @ref BT_MESH_DFU_ITER_CONTINUE. + * something other than @ref BLE_MESH_DFU_ITER_CONTINUE. * * @param cb Callback to call for each slot, or NULL to just count the * number of slots. @@ -133,3 +134,4 @@ int bt_mesh_dfu_slot_img_idx_get(const struct bt_mesh_dfu_slot *slot); * @return The number of slots iterated over. */ size_t bt_mesh_dfu_slot_foreach(bt_mesh_dfu_slot_cb_t cb, void *user_data); +#endif /* CONFIG_BLE_MESH_DFU_SLOTS */ diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c index 0cb4b5e524..b36746a822 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_srv.c @@ -1,617 +1,631 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include +#include "mesh_v1.1/dfu/dfu.h" +#include "mesh_v1.1/dfu/dfu_srv.h" + #include "dfu.h" #include "blob.h" #include "access.h" -#define LOG_LEVEL CONFIG_BT_MESH_DFU_LOG_LEVEL -#include -LOG_MODULE_REGISTER(bt_mesh_dfu_srv); +#if CONFIG_BLE_MESH_SETTINGS +#include "settings.h" +#endif +#if CONFIG_BLE_MESH_DFU_SRV #define UPDATE_IDX_NONE 0xff -BUILD_ASSERT((DFU_UPDATE_START_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_START) + - BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, - "The Firmware Update Start message does not fit into the maximum incoming SDU size."); +_Static_assert((DFU_UPDATE_START_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFU_OP_UPDATE_START) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The Firmware Update Start message does not fit into the maximum incoming SDU size."); -BUILD_ASSERT((DFU_UPDATE_INFO_STATUS_MSG_MINLEN + - BT_MESH_MODEL_OP_LEN(BT_MESH_DFU_OP_UPDATE_INFO_STATUS) + BT_MESH_MIC_SHORT) - <= BT_MESH_TX_SDU_MAX, - "The Firmware Update Info Status message does not fit into the maximum outgoing SDU " - "size."); +_Static_assert((DFU_UPDATE_INFO_STATUS_MSG_MINLEN + + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFU_OP_UPDATE_INFO_STATUS) + BLE_MESH_MIC_SHORT) + <= BLE_MESH_TX_SDU_MAX, + "The Firmware Update Info Status message does not fit into the maximum outgoing SDU " + "size."); static void store_state(struct bt_mesh_dfu_srv *srv) { - bt_mesh_model_data_store(srv->mod, false, NULL, &srv->update, - sizeof(srv->update)); +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_model_data_store(srv->mod, false, NULL, &srv->update, + sizeof(srv->update)); +#endif } static void erase_state(struct bt_mesh_dfu_srv *srv) { - bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0); +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0); +#endif } static void xfer_failed(struct bt_mesh_dfu_srv *srv) { - if (!bt_mesh_dfu_srv_is_busy(srv) || - srv->update.idx >= srv->img_count) { - return; - } + if (!bt_mesh_dfu_srv_is_busy(srv) || + srv->update.idx >= srv->img_count) { + return; + } - erase_state(srv); + erase_state(srv); - if (srv->cb->end) { - srv->cb->end(srv, &srv->imgs[srv->update.idx], false); - } + if (srv->cb->end) { + srv->cb->end(srv, &srv->imgs[srv->update.idx], false); + } } static enum bt_mesh_dfu_status metadata_check(struct bt_mesh_dfu_srv *srv, - uint8_t idx, - struct net_buf_simple *buf, - enum bt_mesh_dfu_effect *effect) + uint8_t idx, + struct net_buf_simple *buf, + enum bt_mesh_dfu_effect *effect) { - *effect = BT_MESH_DFU_EFFECT_NONE; + *effect = BLE_MESH_DFU_EFFECT_NONE; - if (idx >= srv->img_count) { - return BT_MESH_DFU_ERR_FW_IDX; - } + if (idx >= srv->img_count) { + return BLE_MESH_DFU_ERR_FW_IDX; + } - if (!srv->cb->check) { - return BT_MESH_DFU_SUCCESS; - } + if (!srv->cb->check) { + return BLE_MESH_DFU_SUCCESS; + } - if (srv->cb->check(srv, &srv->imgs[idx], buf, effect)) { - *effect = BT_MESH_DFU_EFFECT_NONE; - return BT_MESH_DFU_ERR_METADATA; - } + if (srv->cb->check(srv, &srv->imgs[idx], buf, effect)) { + *effect = BLE_MESH_DFU_EFFECT_NONE; + return BLE_MESH_DFU_ERR_METADATA; + } - return BT_MESH_DFU_SUCCESS; + return BLE_MESH_DFU_SUCCESS; } static void apply_rsp_sent(int err, void *cb_params) { - struct bt_mesh_dfu_srv *srv = cb_params; + struct bt_mesh_dfu_srv *srv = cb_params; - if (err) { - /* return phase back to give client one more chance. */ - srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_OK; - LOG_WRN("Apply response failed, wait for retry (err %d)", err); - return; - } + if (err) { + /* return phase back to give client one more chance. */ + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY_OK; + BT_WARN("Apply response failed, wait for retry (err %d)", err); + return; + } - LOG_DBG(""); + BT_DBG(""); - if (!srv->cb->apply || srv->update.idx == UPDATE_IDX_NONE) { - srv->update.phase = BT_MESH_DFU_PHASE_IDLE; - store_state(srv); - LOG_DBG("Prerequisites for apply callback are wrong"); - return; - } + if (!srv->cb->apply || srv->update.idx == UPDATE_IDX_NONE) { + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + store_state(srv); + BT_DBG("Prerequisites for apply callback are wrong"); + return; + } - store_state(srv); + store_state(srv); - err = srv->cb->apply(srv, &srv->imgs[srv->update.idx]); - if (err) { - srv->update.phase = BT_MESH_DFU_PHASE_IDLE; - store_state(srv); - LOG_DBG("Application apply callback failed (err %d)", err); - } + err = srv->cb->apply(srv, &srv->imgs[srv->update.idx]); + if (err) { + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + store_state(srv); + BT_DBG("Application apply callback failed (err %d)", err); + } } static void apply_rsp_sending(uint16_t duration, int err, void *cb_params) { - if (err) { - apply_rsp_sent(err, cb_params); - } + if (err) { + apply_rsp_sent(err, cb_params); + } } static void verify(struct bt_mesh_dfu_srv *srv) { - srv->update.phase = BT_MESH_DFU_PHASE_VERIFY; + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY; - if (srv->update.idx >= srv->img_count) { - bt_mesh_dfu_srv_rejected(srv); - return; - } + if (srv->update.idx >= srv->img_count) { + bt_mesh_dfu_srv_rejected(srv); + return; + } - if (!srv->cb->end) { - bt_mesh_dfu_srv_verified(srv); - return; - } + if (!srv->cb->end) { + bt_mesh_dfu_srv_verified(srv); + return; + } - srv->cb->end(srv, &srv->imgs[srv->update.idx], true); - if (srv->update.phase == BT_MESH_DFU_PHASE_VERIFY) { - store_state(srv); - } + srv->cb->end(srv, &srv->imgs[srv->update.idx], true); + if (srv->update.phase == BLE_MESH_DFU_PHASE_VERIFY) { + store_state(srv); + } } static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->rt->user_data; - uint8_t idx, limit; + struct bt_mesh_dfu_srv *srv = mod->user_data; + uint8_t idx, limit; - if (srv->update.phase == BT_MESH_DFU_PHASE_APPLYING) { - LOG_INF("Still applying, not responding"); - return -EBUSY; - } + if (srv->update.phase == BLE_MESH_DFU_PHASE_APPLYING) { + BT_INFO("Still applying, not responding"); + return -EBUSY; + } - idx = net_buf_simple_pull_u8(buf); - limit = net_buf_simple_pull_u8(buf); + idx = net_buf_simple_pull_u8(buf); + limit = net_buf_simple_pull_u8(buf); - LOG_DBG("from %u (limit: %u)", idx, limit); + BT_DBG("from %u (limit: %u)", idx, limit); - NET_BUF_SIMPLE_DEFINE(rsp, BT_MESH_TX_SDU_MAX); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFU_OP_UPDATE_INFO_STATUS); - net_buf_simple_add_u8(&rsp, srv->img_count); - net_buf_simple_add_u8(&rsp, idx); + NET_BUF_SIMPLE_DEFINE(rsp, BLE_MESH_TX_SDU_MAX); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFU_OP_UPDATE_INFO_STATUS); + net_buf_simple_add_u8(&rsp, srv->img_count); + net_buf_simple_add_u8(&rsp, idx); - for (; idx < srv->img_count && limit > 0; ++idx) { - uint32_t entry_len; + for (; idx < srv->img_count && limit > 0; ++idx) { + uint32_t entry_len; - if (!srv->imgs[idx].fwid) { - continue; - } + if (!srv->imgs[idx].fwid) { + continue; + } - entry_len = 2 + srv->imgs[idx].fwid_len; - if (srv->imgs[idx].uri) { - entry_len += strlen(srv->imgs[idx].uri); - } + entry_len = 2 + srv->imgs[idx].fwid_len; + if (srv->imgs[idx].uri) { + entry_len += strlen(srv->imgs[idx].uri); + } - if (net_buf_simple_tailroom(&rsp) + BT_MESH_MIC_SHORT < entry_len) { - break; - } + if (net_buf_simple_tailroom(&rsp) + BLE_MESH_MIC_SHORT < entry_len) { + break; + } - net_buf_simple_add_u8(&rsp, srv->imgs[idx].fwid_len); - net_buf_simple_add_mem(&rsp, srv->imgs[idx].fwid, - srv->imgs[idx].fwid_len); + net_buf_simple_add_u8(&rsp, srv->imgs[idx].fwid_len); + net_buf_simple_add_mem(&rsp, srv->imgs[idx].fwid, + srv->imgs[idx].fwid_len); - if (srv->imgs[idx].uri) { - size_t len = strlen(srv->imgs[idx].uri); + if (srv->imgs[idx].uri) { + size_t len = strlen(srv->imgs[idx].uri); - net_buf_simple_add_u8(&rsp, len); - net_buf_simple_add_mem(&rsp, srv->imgs[idx].uri, len); - } else { - net_buf_simple_add_u8(&rsp, 0); - } + net_buf_simple_add_u8(&rsp, len); + net_buf_simple_add_mem(&rsp, srv->imgs[idx].uri, len); + } else { + net_buf_simple_add_u8(&rsp, 0); + } - limit--; - } + limit--; + } - if (srv->update.phase != BT_MESH_DFU_PHASE_IDLE) { - ctx->send_ttl = srv->update.ttl; - } + if (srv->update.phase != BLE_MESH_DFU_PHASE_IDLE) { + ctx->send_ttl = srv->update.ttl; + } - bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); + bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); - return 0; + return 0; } static int handle_metadata_check(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->rt->user_data; - enum bt_mesh_dfu_status status; - enum bt_mesh_dfu_effect effect; - uint8_t idx; + struct bt_mesh_dfu_srv *srv = mod->user_data; + enum bt_mesh_dfu_status status; + enum bt_mesh_dfu_effect effect; + uint8_t idx; - BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFU_OP_UPDATE_METADATA_STATUS, 2); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFU_OP_UPDATE_METADATA_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS, 2); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFU_OP_UPDATE_METADATA_STATUS); - idx = net_buf_simple_pull_u8(buf); - status = metadata_check(srv, idx, buf, &effect); + idx = net_buf_simple_pull_u8(buf); + status = metadata_check(srv, idx, buf, &effect); - LOG_DBG("%u", idx); + BT_DBG("%u", idx); - net_buf_simple_add_u8(&rsp, (status & BIT_MASK(3)) | (effect << 3)); - net_buf_simple_add_u8(&rsp, idx); + net_buf_simple_add_u8(&rsp, (status & BIT_MASK(3)) | (effect << 3)); + net_buf_simple_add_u8(&rsp, idx); - if (srv->update.phase != BT_MESH_DFU_PHASE_IDLE) { - ctx->send_ttl = srv->update.ttl; - } + if (srv->update.phase != BLE_MESH_DFU_PHASE_IDLE) { + ctx->send_ttl = srv->update.ttl; + } - bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); + bt_mesh_model_send(mod, ctx, &rsp, NULL, NULL); - return 0; + return 0; } static void update_status_rsp(struct bt_mesh_dfu_srv *srv, - struct bt_mesh_msg_ctx *ctx, - enum bt_mesh_dfu_status status, - const struct bt_mesh_send_cb *send_cb) + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_dfu_status status, + const struct bt_mesh_send_cb *send_cb) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFU_OP_UPDATE_STATUS, 14); - bt_mesh_model_msg_init(&buf, BT_MESH_DFU_OP_UPDATE_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFU_OP_UPDATE_STATUS, 14); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFU_OP_UPDATE_STATUS); - net_buf_simple_add_u8(&buf, ((status & BIT_MASK(3)) | - (srv->update.phase << 5))); + net_buf_simple_add_u8(&buf, ((status & BIT_MASK(3)) | + (srv->update.phase << 5))); - if (srv->update.phase != BT_MESH_DFU_PHASE_IDLE) { - net_buf_simple_add_u8(&buf, srv->update.ttl); - net_buf_simple_add_u8(&buf, srv->update.effect); - net_buf_simple_add_le16(&buf, srv->update.timeout_base); - net_buf_simple_add_le64(&buf, srv->blob.state.xfer.id); - net_buf_simple_add_u8(&buf, srv->update.idx); + if (srv->update.phase != BLE_MESH_DFU_PHASE_IDLE) { + net_buf_simple_add_u8(&buf, srv->update.ttl); + net_buf_simple_add_u8(&buf, srv->update.effect); + net_buf_simple_add_le16(&buf, srv->update.timeout_base); + net_buf_simple_add_le64(&buf, srv->blob.state.xfer.id); + net_buf_simple_add_u8(&buf, srv->update.idx); - ctx->send_ttl = srv->update.ttl; - } + ctx->send_ttl = srv->update.ttl; + } - bt_mesh_model_send(srv->mod, ctx, &buf, send_cb, srv); + bt_mesh_model_send(srv->mod, ctx, &buf, send_cb, srv); } static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + struct bt_mesh_dfu_srv *srv = mod->user_data; - LOG_DBG(""); + BT_DBG(""); - update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, NULL); + update_status_rsp(srv, ctx, BLE_MESH_DFU_SUCCESS, NULL); - return 0; + return 0; } static inline bool is_active_update(struct bt_mesh_dfu_srv *srv, uint8_t idx, - uint16_t timeout_base, - const uint64_t *blob_id, uint8_t ttl, - uint16_t meta_checksum) + uint16_t timeout_base, + const uint64_t *blob_id, uint8_t ttl, + uint16_t meta_checksum) { - return (srv->update.idx != idx || srv->blob.state.xfer.id != *blob_id || - srv->update.ttl != ttl || - srv->update.timeout_base != timeout_base || - srv->update.meta != meta_checksum); + return (srv->update.idx != idx || srv->blob.state.xfer.id != *blob_id || + srv->update.ttl != ttl || + srv->update.timeout_base != timeout_base || + srv->update.meta != meta_checksum); } static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->rt->user_data; - const struct bt_mesh_blob_io *io; - uint16_t timeout_base, meta_checksum; - enum bt_mesh_dfu_status status; - uint8_t ttl, idx; - uint64_t blob_id; - int err; - struct net_buf_simple_state buf_state; + struct bt_mesh_dfu_srv *srv = mod->user_data; + const struct bt_mesh_blob_io *io; + uint16_t timeout_base, meta_checksum; + enum bt_mesh_dfu_status status; + uint8_t ttl, idx; + uint64_t blob_id; + int err; + struct net_buf_simple_state buf_state; - ttl = net_buf_simple_pull_u8(buf); - timeout_base = net_buf_simple_pull_le16(buf); - blob_id = net_buf_simple_pull_le64(buf); - idx = net_buf_simple_pull_u8(buf); - meta_checksum = dfu_metadata_checksum(buf); + ttl = net_buf_simple_pull_u8(buf); + timeout_base = net_buf_simple_pull_le16(buf); + blob_id = net_buf_simple_pull_le64(buf); + idx = net_buf_simple_pull_u8(buf); + meta_checksum = dfu_metadata_checksum(buf); - LOG_DBG("%u ttl: %u extra time: %u", idx, ttl, timeout_base); + BT_DBG("%u ttl: %u extra time: %u", idx, ttl, timeout_base); - if ((!buf->len || meta_checksum == srv->update.meta) && - srv->update.phase == BT_MESH_DFU_PHASE_TRANSFER_ERR && - srv->update.ttl == ttl && - srv->update.timeout_base == timeout_base && - srv->update.idx == idx && - srv->blob.state.xfer.id == blob_id) { - srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ACTIVE; - status = BT_MESH_DFU_SUCCESS; - store_state(srv); - /* blob srv will resume the transfer. */ - LOG_DBG("Resuming transfer"); - goto rsp; - } + if ((!buf->len || meta_checksum == srv->update.meta) && + srv->update.phase == BLE_MESH_DFU_PHASE_TRANSFER_ERR && + srv->update.ttl == ttl && + srv->update.timeout_base == timeout_base && + srv->update.idx == idx && + srv->blob.state.xfer.id == blob_id) { + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE; + status = BLE_MESH_DFU_SUCCESS; + store_state(srv); + /* blob srv will resume the transfer. */ + BT_DBG("Resuming transfer"); + goto rsp; + } - if (bt_mesh_dfu_srv_is_busy(srv)) { - if (is_active_update(srv, idx, timeout_base, &blob_id, ttl, - meta_checksum)) { - status = BT_MESH_DFU_ERR_WRONG_PHASE; - } else { - status = BT_MESH_DFU_SUCCESS; - srv->update.ttl = ttl; - srv->blob.state.xfer.id = blob_id; - } + if (bt_mesh_dfu_srv_is_busy(srv)) { + if (is_active_update(srv, idx, timeout_base, &blob_id, ttl, + meta_checksum)) { + status = BLE_MESH_DFU_ERR_WRONG_PHASE; + } else { + status = BLE_MESH_DFU_SUCCESS; + srv->update.ttl = ttl; + srv->blob.state.xfer.id = blob_id; + } - LOG_WRN("Busy. Phase: %u", srv->update.phase); - goto rsp; - } + BT_WARN("Busy. Phase: %u", srv->update.phase); + goto rsp; + } - net_buf_simple_save(buf, &buf_state); - status = metadata_check(srv, idx, buf, - (enum bt_mesh_dfu_effect *)&srv->update.effect); - net_buf_simple_restore(buf, &buf_state); - if (status != BT_MESH_DFU_SUCCESS) { - goto rsp; - } + net_buf_simple_save(buf, &buf_state); + status = metadata_check(srv, idx, buf, + (enum bt_mesh_dfu_effect *)&srv->update.effect); + net_buf_simple_restore(buf, &buf_state); + if (status != BLE_MESH_DFU_SUCCESS) { + goto rsp; + } - srv->update.ttl = ttl; - srv->update.timeout_base = timeout_base; - srv->update.meta = meta_checksum; + srv->update.ttl = ttl; + srv->update.timeout_base = timeout_base; + srv->update.meta = meta_checksum; - io = NULL; - err = srv->cb->start(srv, &srv->imgs[idx], buf, &io); - if (err == -EALREADY || (!err && bt_mesh_has_addr(ctx->addr))) { - /* This image has already been received or this is a - * self-update. Skip the transfer phase and proceed to - * verifying update. - */ - status = BT_MESH_DFU_SUCCESS; - srv->update.idx = idx; - srv->blob.state.xfer.id = blob_id; - srv->update.phase = BT_MESH_DFU_PHASE_VERIFY; - update_status_rsp(srv, ctx, status, NULL); - verify(srv); - return 0; - } + io = NULL; + err = srv->cb->start(srv, &srv->imgs[idx], buf, &io); + if (err == -EALREADY || (!err && bt_mesh_has_addr(ctx->addr))) { + /* This image has already been received or this is a + * self-update. Skip the transfer phase and proceed to + * verifying update. + */ + status = BLE_MESH_DFU_SUCCESS; + srv->update.idx = idx; + srv->blob.state.xfer.id = blob_id; + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY; + update_status_rsp(srv, ctx, status, NULL); + verify(srv); + return 0; + } - if (err == -ENOMEM) { - status = BT_MESH_DFU_ERR_RESOURCES; - goto rsp; - } + if (err == -ENOMEM) { + status = BLE_MESH_DFU_ERR_RESOURCES; + goto rsp; + } - if (err == -EBUSY) { - status = BT_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE; - goto rsp; - } + if (err == -EBUSY) { + status = BLE_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE; + goto rsp; + } - if (err || !io || !io->wr) { - status = BT_MESH_DFU_ERR_INTERNAL; - goto rsp; - } + if (err || !io || !io->wr) { + status = BLE_MESH_DFU_ERR_INTERNAL; + goto rsp; + } - err = bt_mesh_blob_srv_recv(&srv->blob, blob_id, io, - ttl, timeout_base); - if (err) { - status = BT_MESH_DFU_ERR_BLOB_XFER_BUSY; - goto rsp; - } + err = bt_mesh_blob_srv_recv(&srv->blob, blob_id, io, + ttl, timeout_base); + if (err) { + status = BLE_MESH_DFU_ERR_BLOB_XFER_BUSY; + goto rsp; + } - srv->update.idx = idx; - srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ACTIVE; - status = BT_MESH_DFU_SUCCESS; - store_state(srv); + srv->update.idx = idx; + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE; + status = BLE_MESH_DFU_SUCCESS; + store_state(srv); rsp: - update_status_rsp(srv, ctx, status, NULL); + update_status_rsp(srv, ctx, status, NULL); - return 0; + return 0; } static int handle_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + struct bt_mesh_dfu_srv *srv = mod->user_data; - if (srv->update.idx == UPDATE_IDX_NONE) { - goto rsp; - } + if (srv->update.idx == UPDATE_IDX_NONE) { + goto rsp; + } - LOG_DBG(""); + BT_DBG(""); - bt_mesh_blob_srv_cancel(&srv->blob); - srv->update.phase = BT_MESH_DFU_PHASE_IDLE; - xfer_failed(srv); + bt_mesh_blob_srv_cancel(&srv->blob); + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + xfer_failed(srv); rsp: - update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, NULL); + update_status_rsp(srv, ctx, BLE_MESH_DFU_SUCCESS, NULL); - return 0; + return 0; } static int handle_apply(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_dfu_srv *srv = mod->rt->user_data; - static const struct bt_mesh_send_cb send_cb = { - .start = apply_rsp_sending, - .end = apply_rsp_sent, - }; + struct bt_mesh_dfu_srv *srv = mod->user_data; + static const struct bt_mesh_send_cb send_cb = { + .start = apply_rsp_sending, + .end = apply_rsp_sent, + }; - LOG_DBG(""); + BT_DBG(""); - if (srv->update.phase == BT_MESH_DFU_PHASE_APPLYING) { - update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, NULL); - return 0; - } + if (srv->update.phase == BLE_MESH_DFU_PHASE_APPLYING) { + update_status_rsp(srv, ctx, BLE_MESH_DFU_SUCCESS, NULL); + return 0; + } - if (srv->update.phase != BT_MESH_DFU_PHASE_VERIFY_OK) { - LOG_WRN("Apply: Invalid phase %u", srv->update.phase); - update_status_rsp(srv, ctx, BT_MESH_DFU_ERR_WRONG_PHASE, NULL); - return 0; - } + if (srv->update.phase != BLE_MESH_DFU_PHASE_VERIFY_OK) { + BT_WARN("Apply: Invalid phase %u", srv->update.phase); + update_status_rsp(srv, ctx, BLE_MESH_DFU_ERR_WRONG_PHASE, NULL); + return 0; + } - /* Postponing the apply callback until the response has been sent, in - * case it triggers a reboot: - */ - srv->update.phase = BT_MESH_DFU_PHASE_APPLYING; - update_status_rsp(srv, ctx, BT_MESH_DFU_SUCCESS, &send_cb); + /* Postponing the apply callback until the response has been sent, in + * case it triggers a reboot: + */ + srv->update.phase = BLE_MESH_DFU_PHASE_APPLYING; + update_status_rsp(srv, ctx, BLE_MESH_DFU_SUCCESS, &send_cb); - return 0; + return 0; } const struct bt_mesh_model_op _bt_mesh_dfu_srv_op[] = { - { BT_MESH_DFU_OP_UPDATE_INFO_GET, BT_MESH_LEN_EXACT(2), handle_info_get }, - { BT_MESH_DFU_OP_UPDATE_METADATA_CHECK, BT_MESH_LEN_MIN(1), handle_metadata_check }, - { BT_MESH_DFU_OP_UPDATE_GET, BT_MESH_LEN_EXACT(0), handle_get }, - { BT_MESH_DFU_OP_UPDATE_START, BT_MESH_LEN_MIN(12), handle_start }, - { BT_MESH_DFU_OP_UPDATE_CANCEL, BT_MESH_LEN_EXACT(0), handle_cancel }, - { BT_MESH_DFU_OP_UPDATE_APPLY, BT_MESH_LEN_EXACT(0), handle_apply }, - BT_MESH_MODEL_OP_END, + { BLE_MESH_DFU_OP_UPDATE_INFO_GET, 2, (void *)handle_info_get }, + { BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK, 1, (void *)handle_metadata_check }, + { BLE_MESH_DFU_OP_UPDATE_GET, 0, (void *)handle_get }, + { BLE_MESH_DFU_OP_UPDATE_START, 12, (void *)handle_start }, + { BLE_MESH_DFU_OP_UPDATE_CANCEL, 0, (void *)handle_cancel }, + { BLE_MESH_DFU_OP_UPDATE_APPLY, 0, (void *)handle_apply }, + BLE_MESH_MODEL_OP_END, }; -static int dfu_srv_init(const struct bt_mesh_model *mod) +static int dfu_srv_init(struct bt_mesh_model *mod) { - struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + struct bt_mesh_dfu_srv *srv = mod->user_data; - srv->mod = mod; - srv->update.idx = UPDATE_IDX_NONE; + srv->mod = mod; + srv->update.idx = UPDATE_IDX_NONE; + srv->blob.cb = &_bt_mesh_dfu_srv_blob_cb; - if (!srv->cb || !srv->cb->start || !srv->imgs || srv->img_count == 0 || - srv->img_count == UPDATE_IDX_NONE) { - LOG_ERR("Invalid DFU Server initialization"); - return -EINVAL; - } + if (!srv->cb || !srv->cb->start || !srv->imgs || srv->img_count == 0 || + srv->img_count == UPDATE_IDX_NONE) { + BT_ERR("Invalid DFU Server initialization"); + return -EINVAL; + } - if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) { - bt_mesh_model_extend(mod, srv->blob.mod); - } - - return 0; + return 0; } +__attribute__((unused)) static int dfu_srv_settings_set(const struct bt_mesh_model *mod, const char *name, - size_t len_rd, settings_read_cb read_cb, - void *cb_arg) + size_t len_rd, settings_read_cb read_cb, + void *cb_arg) { - struct bt_mesh_dfu_srv *srv = mod->rt->user_data; - ssize_t len; + struct bt_mesh_dfu_srv *srv = mod->user_data; + ssize_t len; - if (len_rd < sizeof(srv->update)) { - return -EINVAL; - } + if (len_rd < sizeof(srv->update)) { + return -EINVAL; + } - len = read_cb(cb_arg, &srv->update, sizeof(srv->update)); - if (len < 0) { - return len; - } + len = read_cb(cb_arg, &srv->update, sizeof(srv->update)); + if (len < 0) { + return len; + } - LOG_DBG("Recovered transfer (phase: %u, idx: %u)", srv->update.phase, - srv->update.idx); - if (srv->update.phase == BT_MESH_DFU_PHASE_TRANSFER_ACTIVE) { - LOG_DBG("Settings recovered mid-transfer, setting transfer error"); - srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ERR; - } else if (srv->update.phase == BT_MESH_DFU_PHASE_VERIFY_OK) { - LOG_DBG("Settings recovered before application, setting verification fail"); - srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_FAIL; - } + BT_DBG("Recovered transfer (phase: %u, idx: %u)", srv->update.phase, + srv->update.idx); + if (srv->update.phase == BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE) { + BT_DBG("Settings recovered mid-transfer, setting transfer error"); + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ERR; + } else if (srv->update.phase == BLE_MESH_DFU_PHASE_VERIFY_OK) { + BT_DBG("Settings recovered before application, setting verification fail"); + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY_FAIL; + } - return 0; + return 0; } -static void dfu_srv_reset(const struct bt_mesh_model *mod) +static void dfu_srv_reset(struct bt_mesh_model *mod) { - struct bt_mesh_dfu_srv *srv = mod->rt->user_data; + struct bt_mesh_dfu_srv *srv = mod->user_data; - srv->update.phase = BT_MESH_DFU_PHASE_IDLE; - erase_state(srv); + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + erase_state(srv); +} + +static int dfu_srv_deinit(struct bt_mesh_model *mod) +{ + dfu_srv_reset(mod); + return 0; } const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb = { - .init = dfu_srv_init, - .settings_set = dfu_srv_settings_set, - .reset = dfu_srv_reset, + .init = dfu_srv_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = dfu_srv_deinit, +#endif }; static void blob_suspended(struct bt_mesh_blob_srv *b) { - struct bt_mesh_dfu_srv *srv = CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); + struct bt_mesh_dfu_srv *srv = CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); - srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ERR; - store_state(srv); + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ERR; + store_state(srv); } static void blob_end(struct bt_mesh_blob_srv *b, uint64_t id, bool success) { - struct bt_mesh_dfu_srv *srv = - CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); + struct bt_mesh_dfu_srv *srv = + CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); - LOG_DBG("success: %u", success); + BT_DBG("success: %u", success); - if (!success) { - srv->update.phase = BT_MESH_DFU_PHASE_TRANSFER_ERR; - xfer_failed(srv); - return; - } + if (!success) { + srv->update.phase = BLE_MESH_DFU_PHASE_TRANSFER_ERR; + xfer_failed(srv); + return; + } - verify(srv); + verify(srv); } static int blob_recover(struct bt_mesh_blob_srv *b, - struct bt_mesh_blob_xfer *xfer, - const struct bt_mesh_blob_io **io) + struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io **io) { - struct bt_mesh_dfu_srv *srv = - CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); + struct bt_mesh_dfu_srv *srv = + CONTAINER_OF(b, struct bt_mesh_dfu_srv, blob); - if (!srv->cb->recover || - srv->update.phase != BT_MESH_DFU_PHASE_TRANSFER_ERR || - srv->update.idx >= srv->img_count) { - return -ENOTSUP; - } + if (!srv->cb->recover || + srv->update.phase != BLE_MESH_DFU_PHASE_TRANSFER_ERR || + srv->update.idx >= srv->img_count) { + return -ENOTSUP; + } - return srv->cb->recover(srv, &srv->imgs[srv->update.idx], io); + return srv->cb->recover(srv, &srv->imgs[srv->update.idx], io); } const struct bt_mesh_blob_srv_cb _bt_mesh_dfu_srv_blob_cb = { - .suspended = blob_suspended, - .end = blob_end, - .recover = blob_recover, + .suspended = blob_suspended, + .end = blob_end, + .recover = blob_recover, }; void bt_mesh_dfu_srv_verified(struct bt_mesh_dfu_srv *srv) { - if (srv->update.phase != BT_MESH_DFU_PHASE_VERIFY) { - LOG_WRN("Wrong state"); - return; - } + if (srv->update.phase != BLE_MESH_DFU_PHASE_VERIFY) { + BT_WARN("Wrong state"); + return; + } - LOG_DBG(""); + BT_DBG(""); - srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_OK; - store_state(srv); + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY_OK; + store_state(srv); } void bt_mesh_dfu_srv_rejected(struct bt_mesh_dfu_srv *srv) { - if (srv->update.phase != BT_MESH_DFU_PHASE_VERIFY) { - LOG_WRN("Wrong state"); - return; - } + if (srv->update.phase != BLE_MESH_DFU_PHASE_VERIFY) { + BT_WARN("Wrong state"); + return; + } - LOG_DBG(""); + BT_DBG(""); - srv->update.phase = BT_MESH_DFU_PHASE_VERIFY_FAIL; - store_state(srv); + srv->update.phase = BLE_MESH_DFU_PHASE_VERIFY_FAIL; + store_state(srv); } void bt_mesh_dfu_srv_cancel(struct bt_mesh_dfu_srv *srv) { - if (srv->update.phase == BT_MESH_DFU_PHASE_IDLE) { - LOG_WRN("Wrong state"); - return; - } + if (srv->update.phase == BLE_MESH_DFU_PHASE_IDLE) { + BT_WARN("Wrong state"); + return; + } - (void)bt_mesh_blob_srv_cancel(&srv->blob); + (void)bt_mesh_blob_srv_cancel(&srv->blob); } void bt_mesh_dfu_srv_applied(struct bt_mesh_dfu_srv *srv) { - if (srv->update.phase != BT_MESH_DFU_PHASE_APPLYING) { - LOG_WRN("Wrong state"); - return; - } + if (srv->update.phase != BLE_MESH_DFU_PHASE_APPLYING) { + BT_WARN("Wrong state"); + return; + } - LOG_DBG(""); + BT_DBG(""); - srv->update.phase = BT_MESH_DFU_PHASE_IDLE; - store_state(srv); + srv->update.phase = BLE_MESH_DFU_PHASE_IDLE; + store_state(srv); } bool bt_mesh_dfu_srv_is_busy(const struct bt_mesh_dfu_srv *srv) { - return srv->update.phase != BT_MESH_DFU_PHASE_IDLE && - srv->update.phase != BT_MESH_DFU_PHASE_TRANSFER_ERR && - srv->update.phase != BT_MESH_DFU_PHASE_VERIFY_FAIL; + return srv->update.phase != BLE_MESH_DFU_PHASE_IDLE && + srv->update.phase != BLE_MESH_DFU_PHASE_TRANSFER_ERR && + srv->update.phase != BLE_MESH_DFU_PHASE_VERIFY_FAIL; } uint8_t bt_mesh_dfu_srv_progress(const struct bt_mesh_dfu_srv *srv) { - if (!bt_mesh_dfu_srv_is_busy(srv)) { - return 0U; - } + if (!bt_mesh_dfu_srv_is_busy(srv)) { + return 0U; + } - if (srv->update.phase == BT_MESH_DFU_PHASE_TRANSFER_ACTIVE) { - return bt_mesh_blob_srv_progress(&srv->blob); - } + if (srv->update.phase == BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE) { + return bt_mesh_blob_srv_progress(&srv->blob); + } - return 100U; + return 100U; } +#endif /* CONFIG_BLE_MESH_DFU_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h index cddde76618..b91ee418e2 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h @@ -1,13 +1,12 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_H__ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_H__ - -#include +#ifndef _BLE_MESH_v11_DFD_H__ +#define _BLE_MESH_v11_DFD_H__ #ifdef __cplusplus extern "C" { @@ -21,97 +20,97 @@ extern "C" { /** Firmware distribution status. */ enum bt_mesh_dfd_status { - /** The message was processed successfully. */ - BT_MESH_DFD_SUCCESS, + /** The message was processed successfully. */ + BT_MESH_DFD_SUCCESS, - /** Insufficient resources on the node. */ - BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES, + /** Insufficient resources on the node. */ + BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES, - /** The operation cannot be performed while the Server is in the current - * phase. - */ - BT_MESH_DFD_ERR_WRONG_PHASE, + /** The operation cannot be performed while the Server is in the current + * phase. + */ + BT_MESH_DFD_ERR_WRONG_PHASE, - /** An internal error occurred on the node. */ - BT_MESH_DFD_ERR_INTERNAL, + /** An internal error occurred on the node. */ + BT_MESH_DFD_ERR_INTERNAL, - /** The requested firmware image is not stored on the Distributor. */ - BT_MESH_DFD_ERR_FW_NOT_FOUND, + /** The requested firmware image is not stored on the Distributor. */ + BT_MESH_DFD_ERR_FW_NOT_FOUND, - /** The AppKey identified by the AppKey Index is not known to the node. - */ - BT_MESH_DFD_ERR_INVALID_APPKEY_INDEX, + /** The AppKey identified by the AppKey Index is not known to the node. + */ + BT_MESH_DFD_ERR_INVALID_APPKEY_INDEX, - /** There are no Target nodes in the Distribution Receivers List - * state. - */ - BT_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY, + /** There are no Target nodes in the Distribution Receivers List + * state. + */ + BT_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY, - /** Another firmware image distribution is in progress. */ - BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION, + /** Another firmware image distribution is in progress. */ + BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION, - /** Another upload is in progress. */ - BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD, + /** Another upload is in progress. */ + BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD, - /** The URI scheme name indicated by the Update URI is not supported. */ - BT_MESH_DFD_ERR_URI_NOT_SUPPORTED, + /** The URI scheme name indicated by the Update URI is not supported. */ + BT_MESH_DFD_ERR_URI_NOT_SUPPORTED, - /** The format of the Update URI is invalid. */ - BT_MESH_DFD_ERR_URI_MALFORMED, + /** The format of the Update URI is invalid. */ + BT_MESH_DFD_ERR_URI_MALFORMED, - /** The URI is currently unreachable. */ - BT_MESH_DFD_ERR_URI_UNREACHABLE, + /** The URI is currently unreachable. */ + BT_MESH_DFD_ERR_URI_UNREACHABLE, - /** The Check Firmware OOB procedure did not find any new firmware. */ - BT_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE, + /** The Check Firmware OOB procedure did not find any new firmware. */ + BT_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE, - /** The suspension of the Distribute Firmware procedure failed. */ - BT_MESH_DFD_ERR_SUSPEND_FAILED, + /** The suspension of the Distribute Firmware procedure failed. */ + BT_MESH_DFD_ERR_SUSPEND_FAILED, }; /** Firmware distribution phases. */ enum bt_mesh_dfd_phase { - /** No firmware distribution is in progress. */ - BT_MESH_DFD_PHASE_IDLE, + /** No firmware distribution is in progress. */ + BT_MESH_DFD_PHASE_IDLE, - /** Firmware distribution is in progress. */ - BT_MESH_DFD_PHASE_TRANSFER_ACTIVE, + /** Firmware distribution is in progress. */ + BT_MESH_DFD_PHASE_TRANSFER_ACTIVE, - /** The Transfer BLOB procedure has completed successfully. */ - BT_MESH_DFD_PHASE_TRANSFER_SUCCESS, + /** The Transfer BLOB procedure has completed successfully. */ + BT_MESH_DFD_PHASE_TRANSFER_SUCCESS, - /** The Apply Firmware on Target Nodes procedure is being executed. */ - BT_MESH_DFD_PHASE_APPLYING_UPDATE, + /** The Apply Firmware on Target Nodes procedure is being executed. */ + BT_MESH_DFD_PHASE_APPLYING_UPDATE, - /** The Distribute Firmware procedure has completed successfully. */ - BT_MESH_DFD_PHASE_COMPLETED, + /** The Distribute Firmware procedure has completed successfully. */ + BT_MESH_DFD_PHASE_COMPLETED, - /** The Distribute Firmware procedure has failed. */ - BT_MESH_DFD_PHASE_FAILED, + /** The Distribute Firmware procedure has failed. */ + BT_MESH_DFD_PHASE_FAILED, - /** The Cancel Firmware Update procedure is being executed. */ - BT_MESH_DFD_PHASE_CANCELING_UPDATE, + /** The Cancel Firmware Update procedure is being executed. */ + BT_MESH_DFD_PHASE_CANCELING_UPDATE, - /** The Transfer BLOB procedure is suspended. */ - BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED, + /** The Transfer BLOB procedure is suspended. */ + BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED, }; /** Firmware upload phases. */ enum bt_mesh_dfd_upload_phase { - /** No firmware upload is in progress. */ - BT_MESH_DFD_UPLOAD_PHASE_IDLE, + /** No firmware upload is in progress. */ + BT_MESH_DFD_UPLOAD_PHASE_IDLE, - /** The Store Firmware procedure is being executed. */ - BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE, + /** The Store Firmware procedure is being executed. */ + BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE, - /** The Store Firmware procedure or Store Firmware OOB procedure failed. - */ - BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR, + /** The Store Firmware procedure or Store Firmware OOB procedure failed. + */ + BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR, - /** The Store Firmware procedure or the Store Firmware OOB procedure - * completed successfully. - */ - BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS, + /** The Store Firmware procedure or the Store Firmware OOB procedure + * completed successfully. + */ + BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS, }; /** @} */ @@ -120,4 +119,4 @@ enum bt_mesh_dfd_upload_phase { } #endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_H__ */ +#endif /* _BLE_MESH_v11_DFD_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h index 2abfbf0f90..fd0223af1c 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,34 +13,34 @@ * @brief API for the Firmware Distribution Server model */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_H__ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_H__ +#ifndef _BLE_MESH_v11_DFD_SRV_H__ +#define _BLE_MESH_v11_DFD_SRV_H__ -#include -#include -#include -#include -#include +#include "mesh/access.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" #ifdef __cplusplus extern "C" { #endif -#ifndef CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX -#define CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX 0 +#ifndef CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX +#define CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX 0 #endif -#ifndef CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE -#define CONFIG_BT_MESH_DFD_SRV_SLOT_MAX_SIZE 0 +#ifndef CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE +#define CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE 0 #endif -#ifndef CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE -#define CONFIG_BT_MESH_DFD_SRV_SLOT_SPACE 0 +#ifndef CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE +#define CONFIG_BLE_MESH_DFD_SRV_SLOT_SPACE 0 #endif struct bt_mesh_dfd_srv; -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD /** * * @brief Initialization parameters for the @ref bt_mesh_dfd_srv with OOB @@ -51,19 +52,19 @@ struct bt_mesh_dfd_srv; * Bluetooth SIG Assigned Numbers document. * @param[in] _oob_schemes_count Number of schemes in @c _oob_schemes. */ -#define BT_MESH_DFD_SRV_OOB_INIT(_cb, _oob_schemes, _oob_schemes_count) \ - { \ - .cb = _cb, \ - .dfu = BT_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb), \ - .upload = { \ - .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb }, \ - }, \ - .oob_schemes = { \ - .schemes = _oob_schemes, \ - .count = _oob_schemes_count, \ - }, \ - } -#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ +#define BT_MESH_DFD_SRV_OOB_INIT(_cb, _oob_schemes, _oob_schemes_count) \ + { \ + .cb = _cb, \ + .dfu = BLE_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb), \ + .upload = { \ + .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb }, \ + }, \ + .oob_schemes = { \ + .schemes = _oob_schemes, \ + .count = _oob_schemes_count, \ + }, \ + } +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ /** * @@ -71,14 +72,14 @@ struct bt_mesh_dfd_srv; * * @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance. */ -#define BT_MESH_DFD_SRV_INIT(_cb) \ - { \ - .cb = _cb, \ - .dfu = BT_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb), \ - .upload = { \ - .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb }, \ - }, \ - } +#define BT_MESH_DFD_SRV_INIT(_cb) \ + { \ + .cb = _cb, \ + .dfu = BLE_MESH_DFU_CLI_INIT(&_bt_mesh_dfd_srv_dfu_cb), \ + .upload = { \ + .blob = { .cb = &_bt_mesh_dfd_srv_blob_cb }, \ + }, \ + } /** * @@ -86,168 +87,168 @@ struct bt_mesh_dfd_srv; * * @param _srv Pointer to a @ref bt_mesh_dfd_srv instance. */ -#define BT_MESH_MODEL_DFD_SRV(_srv) \ - BT_MESH_MODEL_DFU_CLI(&(_srv)->dfu), \ - BT_MESH_MODEL_BLOB_SRV(&(_srv)->upload.blob), \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_DFD_SRV, _bt_mesh_dfd_srv_op, NULL, \ - _srv, &_bt_mesh_dfd_srv_cb) +#define BT_MESH_MODEL_DFD_SRV(_srv) \ + BT_MESH_MODEL_DFU_CLI(&(_srv)->dfu), \ + BT_MESH_MODEL_BLOB_SRV(&(_srv)->upload.blob), \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_DFD_SRV, _bt_mesh_dfd_srv_op, NULL, \ + _srv, &_bt_mesh_dfd_srv_cb) /** Firmware Distribution Server callbacks: */ struct bt_mesh_dfd_srv_cb { - /** @brief Slot receive callback. - * - * Called at the start of an upload procedure. The callback must fill - * @c io with a pointer to a writable BLOB stream for the Firmware Distribution - * Server to write the firmware image to. - * - * @param srv Firmware Distribution Server model instance. - * @param slot DFU image slot being received. - * @param io BLOB stream response pointer. - * - * @return 0 on success, or (negative) error code otherwise. - */ - int (*recv)(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot, - const struct bt_mesh_blob_io **io); + /** @brief Slot receive callback. + * + * Called at the start of an upload procedure. The callback must fill + * @c io with a pointer to a writable BLOB stream for the Firmware Distribution + * Server to write the firmware image to. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being received. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*recv)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, + const struct bt_mesh_blob_io **io); -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - /** @brief Firmware upload OOB start callback. - * - * Called at the start of an OOB firmware upload. The application must - * start a firmware check using an OOB mechanism, and then call - * @ref bt_mesh_dfd_srv_oob_check_complete. Depending on the return - * value of this function, the application must then start storing the - * firmware image using an OOB mechanism, and call - * @ref bt_mesh_dfd_srv_oob_store_complete. This callback is mandatory - * to support OOB uploads. - * - * @param srv Firmware Distribution Server model instance. - * @param slot Slot to be used for the upload. - * @param uri Pointer to buffer containing the URI used to - * check for new firmware. - * @param uri_len Length of the URI buffer. - * @param fwid Pointer to buffer containing the current - * firmware ID to be used when checking for - * availability of new firmware. - * @param fwid_len Length of the current firmware ID. Must be set - * to the length of the new firmware ID if it is - * available, or to 0 if new firmware is not - * available. - * - * @return BT_MESH_DFD_SUCCESS on success, or error code otherwise. - */ - int (*start_oob_upload)(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot, - const char *uri, uint8_t uri_len, - const uint8_t *fwid, uint16_t fwid_len); +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + /** @brief Firmware upload OOB start callback. + * + * Called at the start of an OOB firmware upload. The application must + * start a firmware check using an OOB mechanism, and then call + * @ref bt_mesh_dfd_srv_oob_check_complete. Depending on the return + * value of this function, the application must then start storing the + * firmware image using an OOB mechanism, and call + * @ref bt_mesh_dfd_srv_oob_store_complete. This callback is mandatory + * to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot Slot to be used for the upload. + * @param uri Pointer to buffer containing the URI used to + * check for new firmware. + * @param uri_len Length of the URI buffer. + * @param fwid Pointer to buffer containing the current + * firmware ID to be used when checking for + * availability of new firmware. + * @param fwid_len Length of the current firmware ID. Must be set + * to the length of the new firmware ID if it is + * available, or to 0 if new firmware is not + * available. + * + * @return BT_MESH_DFD_SUCCESS on success, or error code otherwise. + */ + int (*start_oob_upload)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, + const char *uri, uint8_t uri_len, + const uint8_t *fwid, uint16_t fwid_len); - /** @brief Cancel store OOB callback - * - * Called when an OOB store is cancelled. The application must stop - * any ongoing OOB image transfer. This callback is mandatory to - * support OOB uploads. - * - * @param srv Firmware Distribution Server model instance. - * @param slot DFU image slot to cancel - */ - void (*cancel_oob_upload)(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot); + /** @brief Cancel store OOB callback + * + * Called when an OOB store is cancelled. The application must stop + * any ongoing OOB image transfer. This callback is mandatory to + * support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to cancel + */ + void (*cancel_oob_upload)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot); - /** @brief Get the progress of an ongoing OOB store - * - * Called by the Firmware Distribution Server model when it needs to - * get the current progress of an ongoing OOB store from the - * application. This callback is mandatory to support OOB uploads. - * - * @param srv Firmware Distribution Server model instance. - * @param slot DFU image slot to get progress for. - * - * @return The current progress of the ongoing OOB store, in percent. - */ - uint8_t (*oob_progress_get)(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot); -#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ + /** @brief Get the progress of an ongoing OOB store + * + * Called by the Firmware Distribution Server model when it needs to + * get the current progress of an ongoing OOB store from the + * application. This callback is mandatory to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to get progress for. + * + * @return The current progress of the ongoing OOB store, in percent. + */ + uint8_t (*oob_progress_get)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ - /** @brief Slot delete callback. - * - * Called when the Firmware Distribution Server is about to delete a DFU image slot. - * All allocated data associated with the firmware slot should be - * deleted. - * - * @param srv Firmware Update Server instance. - * @param slot DFU image slot being deleted. - */ - void (*del)(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot); + /** @brief Slot delete callback. + * + * Called when the Firmware Distribution Server is about to delete a DFU image slot. + * All allocated data associated with the firmware slot should be + * deleted. + * + * @param srv Firmware Update Server instance. + * @param slot DFU image slot being deleted. + */ + void (*del)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot); - /** @brief Slot send callback. - * - * Called at the start of a distribution procedure. The callback must - * fill @c io with a pointer to a readable BLOB stream for the Firmware - * Distribution Server to read the firmware image from. - * - * @param srv Firmware Distribution Server model instance. - * @param slot DFU image slot being sent. - * @param io BLOB stream response pointer. - * - * @return 0 on success, or (negative) error code otherwise. - */ - int (*send)(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot, - const struct bt_mesh_blob_io **io); + /** @brief Slot send callback. + * + * Called at the start of a distribution procedure. The callback must + * fill @c io with a pointer to a readable BLOB stream for the Firmware + * Distribution Server to read the firmware image from. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being sent. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*send)(struct bt_mesh_dfd_srv *srv, + const struct bt_mesh_dfu_slot *slot, + const struct bt_mesh_blob_io **io); - /** @brief Phase change callback (Optional). - * - * Called whenever the phase of the Firmware Distribution Server changes. - * - * @param srv Firmware Distribution Server model instance. - * @param phase New Firmware Distribution phase. - */ - void (*phase)(struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_phase phase); + /** @brief Phase change callback (Optional). + * + * Called whenever the phase of the Firmware Distribution Server changes. + * + * @param srv Firmware Distribution Server model instance. + * @param phase New Firmware Distribution phase. + */ + void (*phase)(struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_phase phase); }; /** Firmware Distribution Server instance. */ struct bt_mesh_dfd_srv { - const struct bt_mesh_dfd_srv_cb *cb; - const struct bt_mesh_model *mod; - struct bt_mesh_dfu_cli dfu; - struct bt_mesh_dfu_target targets[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX]; - struct bt_mesh_blob_target_pull pull_ctxs[CONFIG_BT_MESH_DFD_SRV_TARGETS_MAX]; - const struct bt_mesh_blob_io *io; - uint16_t target_cnt; - uint16_t slot_idx; - bool apply; - enum bt_mesh_dfd_phase phase; - struct bt_mesh_blob_cli_inputs inputs; + const struct bt_mesh_dfd_srv_cb *cb; + const struct bt_mesh_model *mod; + struct bt_mesh_dfu_cli dfu; + struct bt_mesh_dfu_target targets[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX]; + struct bt_mesh_blob_target_pull pull_ctxs[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX]; + const struct bt_mesh_blob_io *io; + uint16_t target_cnt; + uint16_t slot_idx; + bool apply; + enum bt_mesh_dfd_phase phase; + struct bt_mesh_blob_cli_inputs inputs; - struct { - enum bt_mesh_dfd_upload_phase phase; - struct bt_mesh_dfu_slot *slot; - const struct flash_area *area; - struct bt_mesh_blob_srv blob; -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - bool is_oob; - bool is_pending_oob_check; - struct { - uint8_t uri_len; - uint8_t uri[CONFIG_BT_MESH_DFU_URI_MAXLEN]; - uint16_t current_fwid_len; - uint8_t current_fwid[CONFIG_BT_MESH_DFU_FWID_MAXLEN]; - struct bt_mesh_msg_ctx ctx; - } oob; -#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ - } upload; + struct { + enum bt_mesh_dfd_upload_phase phase; + struct bt_mesh_dfu_slot *slot; + const struct flash_area *area; + struct bt_mesh_blob_srv blob; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + bool is_oob; + bool is_pending_oob_check; + struct { + uint8_t uri_len; + char uri[CONFIG_BLE_MESH_DFU_URI_MAXLEN]; + uint16_t current_fwid_len; + uint8_t current_fwid[CONFIG_BLE_MESH_DFU_FWID_MAXLEN]; + struct bt_mesh_msg_ctx ctx; + } oob; +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + } upload; -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD - struct { - const uint8_t *schemes; - const uint8_t count; - } oob_schemes; -#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + struct { + const uint8_t *schemes; + const uint8_t count; + } oob_schemes; +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ }; -#ifdef CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD /** @brief Call when an OOB check has completed or failed * * This should be called by the application after an OOB check started by the @c start_oob_upload @@ -274,8 +275,8 @@ struct bt_mesh_dfd_srv { * @return 0 on success, (negative) error code otherwise. */ int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot, int status, - uint8_t *fwid, size_t fwid_len); + const struct bt_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len); /** @brief Call when an OOB store has completed or failed * @@ -293,9 +294,9 @@ int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, * @return 0 on success, (negative) error code otherwise. */ int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv, - const struct bt_mesh_dfu_slot *slot, bool success, - size_t size, const uint8_t *metadata, size_t metadata_len); -#endif /* CONFIG_BT_MESH_DFD_SRV_OOB_UPLOAD */ + const struct bt_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ /** @cond INTERNAL_HIDDEN */ extern const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[]; @@ -308,6 +309,6 @@ extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb; } #endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFD_SRV_H__ */ +#endif /* _BLE_MESH_v11_DFD_SRV_H__ */ /** @} */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h index 4745355f03..073aae901b 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu.h @@ -1,16 +1,19 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_H__ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_H__ +#ifndef _BLE_MESH_v11_DFU_H__ +#define _BLE_MESH_v11_DFU_H__ #include -#include -#include +#include "mesh/types.h" +#include "mesh/utils.h" + +#include "mesh_v1.1/mbt/blob.h" #ifdef __cplusplus extern "C" { @@ -22,115 +25,114 @@ extern "C" { * @{ */ -#ifndef CONFIG_BT_MESH_DFU_FWID_MAXLEN -#define CONFIG_BT_MESH_DFU_FWID_MAXLEN 0 +#ifndef CONFIG_BLE_MESH_DFU_FWID_MAXLEN +#define CONFIG_BLE_MESH_DFU_FWID_MAXLEN 0 #endif -#ifndef CONFIG_BT_MESH_DFU_METADATA_MAXLEN -#define CONFIG_BT_MESH_DFU_METADATA_MAXLEN 0 +#ifndef CONFIG_BLE_MESH_DFU_METADATA_MAXLEN +#define CONFIG_BLE_MESH_DFU_METADATA_MAXLEN 0 #endif -#ifndef CONFIG_BT_MESH_DFU_URI_MAXLEN -#define CONFIG_BT_MESH_DFU_URI_MAXLEN 0 +#ifndef CONFIG_BLE_MESH_DFU_URI_MAXLEN +#define CONFIG_BLE_MESH_DFU_URI_MAXLEN 0 #endif -#ifndef CONFIG_BT_MESH_DFU_SLOT_CNT -#define CONFIG_BT_MESH_DFU_SLOT_CNT 0 +#ifndef CONFIG_BLE_MESH_DFU_SLOT_CNT +#define CONFIG_BLE_MESH_DFU_SLOT_CNT 0 #endif /** DFU transfer phase. */ enum bt_mesh_dfu_phase { - /** Ready to start a Receive Firmware procedure. */ - BT_MESH_DFU_PHASE_IDLE, + /** Ready to start a Receive Firmware procedure. */ + BLE_MESH_DFU_PHASE_IDLE, - /** The Transfer BLOB procedure failed. */ - BT_MESH_DFU_PHASE_TRANSFER_ERR, + /** The Transfer BLOB procedure failed. */ + BLE_MESH_DFU_PHASE_TRANSFER_ERR, - /** The Receive Firmware procedure is being executed. */ - BT_MESH_DFU_PHASE_TRANSFER_ACTIVE, + /** The Receive Firmware procedure is being executed. */ + BLE_MESH_DFU_PHASE_TRANSFER_ACTIVE, - /** The Verify Firmware procedure is being executed. */ - BT_MESH_DFU_PHASE_VERIFY, + /** The Verify Firmware procedure is being executed. */ + BLE_MESH_DFU_PHASE_VERIFY, - /** The Verify Firmware procedure completed successfully. */ - BT_MESH_DFU_PHASE_VERIFY_OK, + /** The Verify Firmware procedure completed successfully. */ + BLE_MESH_DFU_PHASE_VERIFY_OK, - /** The Verify Firmware procedure failed. */ - BT_MESH_DFU_PHASE_VERIFY_FAIL, + /** The Verify Firmware procedure failed. */ + BLE_MESH_DFU_PHASE_VERIFY_FAIL, - /** The Apply New Firmware procedure is being executed. */ - BT_MESH_DFU_PHASE_APPLYING, + /** The Apply New Firmware procedure is being executed. */ + BLE_MESH_DFU_PHASE_APPLYING, - /** Firmware transfer has been canceled. */ - BT_MESH_DFU_PHASE_TRANSFER_CANCELED, + /** Firmware transfer has been canceled. */ + BLE_MESH_DFU_PHASE_TRANSFER_CANCELED, - /** Firmware applying succeeded. */ - BT_MESH_DFU_PHASE_APPLY_SUCCESS, + /** Firmware applying succeeded. */ + BLE_MESH_DFU_PHASE_APPLY_SUCCESS, - /** Firmware applying failed. */ - BT_MESH_DFU_PHASE_APPLY_FAIL, + /** Firmware applying failed. */ + BLE_MESH_DFU_PHASE_APPLY_FAIL, - /** Phase of a node was not yet retrieved. */ - BT_MESH_DFU_PHASE_UNKNOWN, + /** Phase of a node was not yet retrieved. */ + BLE_MESH_DFU_PHASE_UNKNOWN, }; - /** DFU status. */ enum bt_mesh_dfu_status { - /** The message was processed successfully. */ - BT_MESH_DFU_SUCCESS, + /** The message was processed successfully. */ + BLE_MESH_DFU_SUCCESS, - /** Insufficient resources on the node */ - BT_MESH_DFU_ERR_RESOURCES, + /** Insufficient resources on the node */ + BLE_MESH_DFU_ERR_RESOURCES, - /** The operation cannot be performed while the Server is in the current - * phase. - */ - BT_MESH_DFU_ERR_WRONG_PHASE, + /** The operation cannot be performed while the Server is in the current + * phase. + */ + BLE_MESH_DFU_ERR_WRONG_PHASE, - /** An internal error occurred on the node. */ - BT_MESH_DFU_ERR_INTERNAL, + /** An internal error occurred on the node. */ + BLE_MESH_DFU_ERR_INTERNAL, - /** The message contains a firmware index value that is not expected. */ - BT_MESH_DFU_ERR_FW_IDX, + /** The message contains a firmware index value that is not expected. */ + BLE_MESH_DFU_ERR_FW_IDX, - /** The metadata check failed. */ - BT_MESH_DFU_ERR_METADATA, + /** The metadata check failed. */ + BLE_MESH_DFU_ERR_METADATA, - /** The Server cannot start a firmware update. */ - BT_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE, + /** The Server cannot start a firmware update. */ + BLE_MESH_DFU_ERR_TEMPORARILY_UNAVAILABLE, - /** Another BLOB transfer is in progress. */ - BT_MESH_DFU_ERR_BLOB_XFER_BUSY, + /** Another BLOB transfer is in progress. */ + BLE_MESH_DFU_ERR_BLOB_XFER_BUSY, }; /** Expected effect of a DFU transfer. */ enum bt_mesh_dfu_effect { - /** No changes to node Composition Data. */ - BT_MESH_DFU_EFFECT_NONE, + /** No changes to node Composition Data. */ + BLE_MESH_DFU_EFFECT_NONE, - /** Node Composition Data changed and the node does not support remote - * provisioning. - */ - BT_MESH_DFU_EFFECT_COMP_CHANGE_NO_RPR, + /** Node Composition Data changed and the node does not support remote + * provisioning. + */ + BLE_MESH_DFU_EFFECT_COMP_CHANGE_NO_RPR, - /** Node Composition Data changed, and remote provisioning is supported. - * The node supports remote provisioning and Composition Data Page - * 0x80. Page 0x80 contains different Composition Data than Page 0x0. - */ - BT_MESH_DFU_EFFECT_COMP_CHANGE, + /** Node Composition Data changed, and remote provisioning is supported. + * The node supports remote provisioning and Composition Data Page + * 0x80. Page 0x80 contains different Composition Data than Page 0x0. + */ + BLE_MESH_DFU_EFFECT_COMP_CHANGE, - /** Node will be unprovisioned after the update. */ - BT_MESH_DFU_EFFECT_UNPROV, + /** Node will be unprovisioned after the update. */ + BLE_MESH_DFU_EFFECT_UNPROV, }; /** Action for DFU iteration callbacks. */ enum bt_mesh_dfu_iter { - /** Stop iterating. */ - BT_MESH_DFU_ITER_STOP, + /** Stop iterating. */ + BLE_MESH_DFU_ITER_STOP, - /** Continue iterating. */ - BT_MESH_DFU_ITER_CONTINUE, + /** Continue iterating. */ + BLE_MESH_DFU_ITER_CONTINUE, }; /** DFU image instance. @@ -138,28 +140,28 @@ enum bt_mesh_dfu_iter { * Each DFU image represents a single updatable firmware image. */ struct bt_mesh_dfu_img { - /** Firmware ID. */ - const void *fwid; + /** Firmware ID. */ + const void *fwid; - /** Length of the firmware ID. */ - size_t fwid_len; + /** Length of the firmware ID. */ + size_t fwid_len; - /** Update URI, or NULL. */ - const char *uri; + /** Update URI, or NULL. */ + const char *uri; }; /** DFU image slot for DFU distribution. */ struct bt_mesh_dfu_slot { - /** Size of the firmware in bytes. */ - size_t size; - /** Length of the firmware ID. */ - size_t fwid_len; - /** Length of the metadata. */ - size_t metadata_len; - /** Firmware ID. */ - uint8_t fwid[CONFIG_BT_MESH_DFU_FWID_MAXLEN]; - /** Metadata. */ - uint8_t metadata[CONFIG_BT_MESH_DFU_METADATA_MAXLEN]; + /** Size of the firmware in bytes. */ + size_t size; + /** Length of the firmware ID. */ + size_t fwid_len; + /** Length of the metadata. */ + size_t metadata_len; + /** Firmware ID. */ + uint8_t fwid[CONFIG_BLE_MESH_DFU_FWID_MAXLEN]; + /** Metadata. */ + uint8_t metadata[CONFIG_BLE_MESH_DFU_METADATA_MAXLEN]; }; /** @} */ @@ -168,4 +170,4 @@ struct bt_mesh_dfu_slot { } #endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_H__ */ +#endif /* _BLE_MESH_v11_DFU_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h index ad8881ebc2..531e359994 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,12 +13,14 @@ * @brief API for the Bluetooth Mesh Firmware Update Client model */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ +#ifndef _BLE_MESH_v11_DFU_CLI_H__ +#define _BLE_MESH_v11_DFU_CLI_H__ -#include -#include -#include +#include "freertos/semphr.h" + +#include "mesh/access.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/dfu/dfu.h" #ifdef __cplusplus extern "C" { @@ -33,11 +36,11 @@ struct bt_mesh_dfu_cli; * * @param _handlers Handler callback structure. */ -#define BT_MESH_DFU_CLI_INIT(_handlers) \ - { \ - .cb = _handlers, \ - .blob = { .cb = &_bt_mesh_dfu_cli_blob_handlers }, \ - } +#define BLE_MESH_DFU_CLI_INIT(_handlers) \ + { \ + .cb = _handlers, \ + .blob = { .cb = &_bt_mesh_dfu_cli_blob_handlers }, \ + } /** * @@ -45,64 +48,67 @@ struct bt_mesh_dfu_cli; * * @param _cli Pointer to a @ref bt_mesh_dfu_cli instance. */ -#define BT_MESH_MODEL_DFU_CLI(_cli) \ - BT_MESH_MODEL_BLOB_CLI(&(_cli)->blob), \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_DFU_CLI, _bt_mesh_dfu_cli_op, NULL, \ - _cli, &_bt_mesh_dfu_cli_cb) +#define BT_MESH_MODEL_DFU_CLI(_cli) \ + BT_MESH_MODEL_BLOB_CLI(&(_cli)->blob), \ + BT_MESH_MODEL_CB(BLE_MESH_MODEL_ID_DFU_CLI, _bt_mesh_dfu_cli_op, NULL, \ + _cli, &_bt_mesh_dfu_cli_cb) /** DFU Target node. */ struct bt_mesh_dfu_target { - /** BLOB Target node */ - struct bt_mesh_blob_target blob; - /** Image index on the Target node */ - uint8_t img_idx; - /** Expected DFU effect, see @ref bt_mesh_dfu_effect. */ - uint8_t effect; - /** Current DFU status, see @ref bt_mesh_dfu_status. */ - uint8_t status; - /** Current DFU phase, see @ref bt_mesh_dfu_phase. */ - uint8_t phase; + /** BLOB Target node */ + struct bt_mesh_blob_target blob; + /** Image index on the Target node */ + uint8_t img_idx; + /** Expected DFU effect, see @ref bt_mesh_dfu_effect. */ + uint8_t effect; + /** Current DFU status, see @ref bt_mesh_dfu_status. */ + uint8_t status; + /** Current DFU phase, see @ref bt_mesh_dfu_phase. */ + uint8_t phase; }; /** Metadata status response. */ struct bt_mesh_dfu_metadata_status { - /** Image index. */ - uint8_t idx; - /** Status code. */ - enum bt_mesh_dfu_status status; - /** Effect of transfer. */ - enum bt_mesh_dfu_effect effect; + /** Image index. */ + uint8_t idx; + /** Status code. */ + enum bt_mesh_dfu_status status; + /** Effect of transfer. */ + enum bt_mesh_dfu_effect effect; }; -/** DFU Target node status parameters. */ +/** DFU Target node status parameters. + * The structure should be same as + * @ref esp_ble_mesh_device_firmware_update_status_t +*/ struct bt_mesh_dfu_target_status { - /** Status of the previous operation. */ - enum bt_mesh_dfu_status status; - /** Phase of the current DFU transfer. */ - enum bt_mesh_dfu_phase phase; - /** The effect the update will have on the Target device's state. */ - enum bt_mesh_dfu_effect effect; - /** BLOB ID used in the transfer. */ - uint64_t blob_id; - /** Image index to transfer. */ - uint8_t img_idx; - /** TTL used in the transfer. */ - uint8_t ttl; + /** Status of the previous operation. */ + enum bt_mesh_dfu_status status; + /** Phase of the current DFU transfer. */ + enum bt_mesh_dfu_phase phase; + /** The effect the update will have on the Target device's state. */ + enum bt_mesh_dfu_effect effect; + /** BLOB ID used in the transfer. */ + uint64_t blob_id; + /** Image index to transfer. */ + uint8_t img_idx; + /** TTL used in the transfer. */ + uint8_t ttl; - /** Additional response time for the Target nodes, in 10-second increments. - * - * The extra time can be used to give the Target nodes more time to respond - * to messages from the Client. The actual timeout will be calculated - * according to the following formula: - * - * @verbatim - * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) - * @endverbatim - * - * If a Target node fails to respond to a message from the Client within the - * configured transfer timeout, the Target node is dropped. - */ - uint16_t timeout_base; + /** Additional response time for the Target nodes, in 10-second increments. + * + * The extra time can be used to give the Target nodes more time to respond + * to messages from the Client. The actual timeout will be calculated + * according to the following formula: + * + * @verbatim + * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) + * @endverbatim + * + * If a Target node fails to respond to a message from the Client within the + * configured transfer timeout, the Target node is dropped. + */ + uint16_t timeout_base; }; /** @brief DFU image callback. @@ -117,120 +123,140 @@ struct bt_mesh_dfu_target_status { * @param img Image information for the given image index. * @param cb_data Callback data. * - * @retval BT_MESH_DFU_ITER_STOP Stop iterating through the image list and + * @retval BLE_MESH_DFU_ITER_STOP Stop iterating through the image list and * return from @ref bt_mesh_dfu_cli_imgs_get. - * @retval BT_MESH_DFU_ITER_CONTINUE Continue iterating through the image list + * @retval BLE_MESH_DFU_ITER_CONTINUE Continue iterating through the image list * if any images remain. */ -typedef enum bt_mesh_dfu_iter (*bt_mesh_dfu_img_cb_t)( - struct bt_mesh_dfu_cli *cli, struct bt_mesh_msg_ctx *ctx, uint8_t idx, - uint8_t total, const struct bt_mesh_dfu_img *img, void *cb_data); +typedef enum bt_mesh_dfu_iter(*bt_mesh_dfu_img_cb_t)(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_msg_ctx *ctx, + uint8_t idx, uint8_t total, + const struct bt_mesh_dfu_img *img, + void *cb_data); /** Firmware Update Client event callbacks. */ struct bt_mesh_dfu_cli_cb { - /** @brief BLOB transfer is suspended. - * - * Called when the BLOB transfer is suspended due to response timeout from all Target nodes. - * - * @param cli Firmware Update Client model instance. - */ - void (*suspended)(struct bt_mesh_dfu_cli *cli); + /** @brief BLOB transfer is suspended. + * + * Called when the BLOB transfer is suspended due to response timeout from all Target nodes. + * + * @param cli Firmware Update Client model instance. + */ + void (*suspended)(struct bt_mesh_dfu_cli *cli); - /** @brief DFU ended. - * - * Called when the DFU transfer ends, either because all Target nodes were - * lost or because the transfer was completed successfully. - * - * @param cli Firmware Update Client model instance. - * @param reason Reason for ending. - */ - void (*ended)(struct bt_mesh_dfu_cli *cli, - enum bt_mesh_dfu_status reason); + /** @brief DFU ended. + * + * Called when the DFU transfer ends, either because all Target nodes were + * lost or because the transfer was completed successfully. + * + * @param cli Firmware Update Client model instance. + * @param reason Reason for ending. + */ + void (*ended)(struct bt_mesh_dfu_cli *cli, + enum bt_mesh_dfu_status reason); - /** @brief DFU transfer applied on all active Target nodes. - * - * Called at the end of the apply procedure started by @ref - * bt_mesh_dfu_cli_apply. - * - * @param cli Firmware Update Client model instance. - */ - void (*applied)(struct bt_mesh_dfu_cli *cli); + /** @brief DFU transfer applied on all active Target nodes. + * + * Called at the end of the apply procedure started by @ref + * bt_mesh_dfu_cli_apply. + * + * @param cli Firmware Update Client model instance. + */ + void (*applied)(struct bt_mesh_dfu_cli *cli); - /** @brief DFU transfer confirmed on all active Target nodes. - * - * Called at the end of the apply procedure started by @ref - * bt_mesh_dfu_cli_confirm. - * - * @param cli Firmware Update Client model instance. - */ - void (*confirmed)(struct bt_mesh_dfu_cli *cli); + /** @brief DFU transfer confirmed on all active Target nodes. + * + * Called at the end of the apply procedure started by @ref + * bt_mesh_dfu_cli_confirm. + * + * @param cli Firmware Update Client model instance. + */ + void (*confirmed)(struct bt_mesh_dfu_cli *cli); - /** @brief DFU Target node was lost. - * - * A DFU Target node was dropped from the receivers list. The Target node's - * @c status is set to reflect the reason for the failure. - * - * @param cli Firmware Update Client model instance. - * @param target DFU Target node that was lost. - */ - void (*lost_target)(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_dfu_target *target); + /** @brief DFU Target node was lost. + * + * A DFU Target node was dropped from the receivers list. The Target node's + * @c status is set to reflect the reason for the failure. + * + * @param cli Firmware Update Client model instance. + * @param target DFU Target node that was lost. + */ + void (*lost_target)(struct bt_mesh_dfu_cli *cli, + struct bt_mesh_dfu_target *target); }; +enum { + STATE_IDLE, + STATE_TRANSFER, + STATE_REFRESH, + STATE_VERIFIED, + STATE_APPLY, + STATE_APPLIED, + STATE_CONFIRM, + STATE_CANCEL, + STATE_SUSPENDED, +}; + +typedef struct { + sys_snode_t node; + uint8_t ttl; + uint8_t type; + uint8_t img_cnt; + uint32_t opcode; + void *params; + bt_mesh_dfu_img_cb_t img_cb; + struct bt_mesh_dfu_cli *dfu_cli; + struct bt_mesh_msg_ctx ctx; + int32_t timeout; + struct k_delayed_work timer; /* Time used to get response. Only for internal use. */ +} bt_mesh_dfu_cli_req_t; + /** Firmware Update Client model instance. * - * Should be initialized with @ref BT_MESH_DFU_CLI_INIT. + * Should be initialized with @ref BLE_MESH_DFU_CLI_INIT. */ struct bt_mesh_dfu_cli { - /** Callback structure. */ - const struct bt_mesh_dfu_cli_cb *cb; - /** Underlying BLOB Transfer Client. */ - struct bt_mesh_blob_cli blob; + /** Callback structure. */ + const struct bt_mesh_dfu_cli_cb *cb; + /** Underlying BLOB Transfer Client. */ + struct bt_mesh_blob_cli blob; - /* runtime state */ + /* runtime state */ - uint32_t op; - const struct bt_mesh_model *mod; + uint32_t op; + struct bt_mesh_model *mod; - struct { - const struct bt_mesh_dfu_slot *slot; - const struct bt_mesh_blob_io *io; - struct bt_mesh_blob_xfer blob; - uint8_t state; - uint8_t flags; - } xfer; + struct { + const struct bt_mesh_dfu_slot *slot; + const struct bt_mesh_blob_io *io; + struct bt_mesh_blob_xfer blob; + uint8_t state; + uint8_t flags; + } xfer; - struct { - uint8_t ttl; - uint8_t type; - uint8_t img_cnt; - uint16_t addr; - struct k_sem sem; - void *params; - bt_mesh_dfu_img_cb_t img_cb; - } req; + bt_mesh_dfu_cli_req_t *req; }; /** BLOB parameters for Firmware Update Client transfer: */ struct bt_mesh_dfu_cli_xfer_blob_params { - /* Logarithmic representation of the block size. */ - uint8_t block_size_log; - /** Base chunk size. May be smaller for the last chunk. */ - uint16_t chunk_size; + /* Logarithmic representation of the block size. */ + uint8_t block_size_log; + /** Base chunk size. May be smaller for the last chunk. */ + uint16_t chunk_size; }; /** Firmware Update Client transfer parameters: */ struct bt_mesh_dfu_cli_xfer { - /** BLOB ID to use for this transfer, or 0 to set it randomly. */ - uint64_t blob_id; - /** DFU image slot to transfer. */ - const struct bt_mesh_dfu_slot *slot; - /** Transfer mode (Push (Push BLOB Transfer Mode) or Pull (Pull BLOB Transfer Mode)) */ - enum bt_mesh_blob_xfer_mode mode; - /** BLOB parameters to be used for the transfer, or NULL to retrieve Target nodes' - * capabilities before sending a firmware. - */ - const struct bt_mesh_dfu_cli_xfer_blob_params *blob_params; + /** BLOB ID to use for this transfer, or 0 to set it randomly. */ + uint64_t blob_id; + /** DFU image slot to transfer. */ + const struct bt_mesh_dfu_slot *slot; + /** Transfer mode (Push (Push BLOB Transfer Mode) or Pull (Pull BLOB Transfer Mode)) */ + enum bt_mesh_blob_xfer_mode mode; + /** BLOB parameters to be used for the transfer, or NULL to retrieve Target nodes' + * capabilities before sending a firmware. + */ + const struct bt_mesh_dfu_cli_xfer_blob_params *blob_params; }; /** @brief Start distributing a DFU. @@ -250,9 +276,9 @@ struct bt_mesh_dfu_cli_xfer { * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_dfu_cli_send(struct bt_mesh_dfu_cli *cli, - const struct bt_mesh_blob_cli_inputs *inputs, - const struct bt_mesh_blob_io *io, - const struct bt_mesh_dfu_cli_xfer *xfer); + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_io *io, + const struct bt_mesh_dfu_cli_xfer *xfer); /** @brief Suspend a DFU transfer. * @@ -281,7 +307,7 @@ int bt_mesh_dfu_cli_resume(struct bt_mesh_dfu_cli *cli); * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_dfu_cli_cancel(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_msg_ctx *ctx); + struct bt_mesh_msg_ctx *ctx); /** @brief Apply the completed DFU transfer. * @@ -300,7 +326,7 @@ int bt_mesh_dfu_cli_apply(struct bt_mesh_dfu_cli *cli); * Client's @c confirmed callback is called at the end of the confirm * procedure. * - * Target nodes that have reported the effect as @ref BT_MESH_DFU_EFFECT_UNPROV + * Target nodes that have reported the effect as @ref BLE_MESH_DFU_EFFECT_UNPROV * are expected to not respond to the query, and will fail if they do. * * @param cli Firmware Update Client model instance. @@ -341,14 +367,15 @@ bool bt_mesh_dfu_cli_is_busy(struct bt_mesh_dfu_cli *cli); * @param ctx Message context. * @param cb Callback to call for each image index. * @param cb_data Callback data to pass to @c cb. + * @param first_idx Index of the first requested imgs entry. * @param max_count Max number of images to return. * * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_dfu_cli_imgs_get(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_msg_ctx *ctx, - bt_mesh_dfu_img_cb_t cb, void *cb_data, - uint8_t max_count); + struct bt_mesh_msg_ctx *ctx, + bt_mesh_dfu_img_cb_t cb, void *cb_data, + uint8_t first_idx, uint8_t max_count); /** @brief Perform a metadata check for the given DFU image slot. * @@ -357,30 +384,26 @@ int bt_mesh_dfu_cli_imgs_get(struct bt_mesh_dfu_cli *cli, * * Waits for a response until the procedure timeout expires. * - * @param cli Firmware Update Client model instance. - * @param ctx Message context. - * @param img_idx Target node's image index to check. - * @param slot DFU image slot to check for. - * @param rsp Metadata status response buffer. + * @param cli Firmware Update Client model instance. + * @param ctx Message context. + * @param img_idx Target node's image index to check. + * @param metadata DFU image metadata to check for. * * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_dfu_cli_metadata_check(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_msg_ctx *ctx, uint8_t img_idx, - const struct bt_mesh_dfu_slot *slot, - struct bt_mesh_dfu_metadata_status *rsp); + struct bt_mesh_msg_ctx *ctx, uint8_t img_idx, + struct net_buf_simple *metadata); /** @brief Get the status of a Target node. * * @param cli Firmware Update Client model instance. * @param ctx Message context. - * @param rsp Response data buffer. * * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_dfu_cli_status_get(struct bt_mesh_dfu_cli *cli, - struct bt_mesh_msg_ctx *ctx, - struct bt_mesh_dfu_target_status *rsp); + struct bt_mesh_msg_ctx *ctx); /** @brief Get the current procedure timeout value. * @@ -404,6 +427,4 @@ extern const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[]; } #endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_CLI_H__ */ - -/** @} */ +#endif /* _BLE_MESH_v11_DFU_CLI_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h index 8f6430c4b0..baa4049a2b 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_metadata.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2021 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,14 +13,15 @@ * @brief Common types and functions for the Bluetooth Mesh DFU metadata. */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_METADATA_H__ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_METADATA_H__ +#ifndef _BLE_MESH_v11_DFU_METADATA_H__ +#define _BLE_MESH_v11_DFU_METADATA_H__ #include #include -#include +#include "mesh/types.h" +#include "mesh/utils.h" #ifdef __cplusplus extern "C" { @@ -27,42 +29,40 @@ extern "C" { /** Firmware version. */ struct bt_mesh_dfu_metadata_fw_ver { - /** Firmware major version. */ - uint8_t major; - /** Firmware minor version. */ - uint8_t minor; - /** Firmware revision. */ - uint16_t revision; - /** Firmware build number. */ - uint32_t build_num; + /** Firmware major version. */ + uint8_t major; + /** Firmware minor version. */ + uint8_t minor; + /** Firmware revision. */ + uint16_t revision; + /** Firmware build number. */ + uint32_t build_num; }; /** Firmware core type. */ enum bt_mesh_dfu_metadata_fw_core_type { - /** Application core. */ - BT_MESH_DFU_FW_CORE_TYPE_APP = BIT(0), - /** Network core. */ - BT_MESH_DFU_FW_CORE_TYPE_NETWORK = BIT(1), - /** Application-specific BLOB. */ - BT_MESH_DFU_FW_CORE_TYPE_APP_SPECIFIC_BLOB = BIT(2), + /** Application core. */ + BLE_MESH_DFU_FW_CORE_TYPE_APP = BIT(0), + /** Application-specific BLOB. */ + BLE_MESH_DFU_FW_CORE_TYPE_APP_SPECIFIC_BLOB = BIT(2), }; /** Firmware metadata. */ struct bt_mesh_dfu_metadata { - /** New firmware version. */ - struct bt_mesh_dfu_metadata_fw_ver fw_ver; - /** New firmware size. */ - uint32_t fw_size; - /** New firmware core type. */ - enum bt_mesh_dfu_metadata_fw_core_type fw_core_type; - /** Hash of incoming Composition Data. */ - uint32_t comp_hash; - /** New number of node elements. */ - uint16_t elems; - /** Application-specific data for new firmware. This field is optional. */ - uint8_t *user_data; - /** Length of the application-specific field. */ - uint32_t user_data_len; + /** New firmware version. */ + struct bt_mesh_dfu_metadata_fw_ver fw_ver; + /** New firmware size. */ + uint32_t fw_size; + /** New firmware core type. */ + enum bt_mesh_dfu_metadata_fw_core_type fw_core_type; + /** Hash of incoming Composition Data. */ + uint32_t comp_hash; + /** New number of node elements. */ + uint16_t elems; + /** Application-specific data for new firmware. This field is optional. */ + uint8_t *user_data; + /** Length of the application-specific field. */ + uint32_t user_data_len; }; /** @brief Decode a firmware metadata from a network buffer. @@ -73,7 +73,7 @@ struct bt_mesh_dfu_metadata { * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_dfu_metadata_decode(struct net_buf_simple *buf, - struct bt_mesh_dfu_metadata *metadata); + struct bt_mesh_dfu_metadata *metadata); /** @brief Encode a firmware metadata into a network buffer. * @@ -83,7 +83,7 @@ int bt_mesh_dfu_metadata_decode(struct net_buf_simple *buf, * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_dfu_metadata_encode(const struct bt_mesh_dfu_metadata *metadata, - struct net_buf_simple *buf); + struct net_buf_simple *buf); /** @brief Compute hash of the Composition Data state. * @@ -110,6 +110,4 @@ int bt_mesh_dfu_metadata_comp_hash_local_get(uint8_t *key, uint32_t *hash); } #endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_METADATA_H__ */ - -/** @} */ +#endif /* _BLE_MESH_v11_DFU_METADATA_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h index 2beaf2d977..dc134fe07e 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_srv.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,12 +13,11 @@ * @brief API for the Bluetooth Mesh Firmware Update Server model */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_SRV_H__ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_SRV_H__ +#ifndef _BLE_MESH_v11_DFU_SRV_H__ +#define _BLE_MESH_v11_DFU_SRV_H__ -#include -#include -#include +#include "mesh/access.h" +#include "mesh_v1.1/mbt/blob_srv.h" #ifdef __cplusplus extern "C" { @@ -33,11 +33,11 @@ struct bt_mesh_dfu_srv; * @param _imgs List of @ref bt_mesh_dfu_img managed by this Server. * @param _img_count Number of DFU images managed by this Server. */ -#define BT_MESH_DFU_SRV_INIT(_handlers, _imgs, _img_count) \ - { \ - .blob = { .cb = &_bt_mesh_dfu_srv_blob_cb }, .cb = _handlers, \ - .imgs = _imgs, .img_count = _img_count, \ - } +#define BLE_MESH_DFU_SRV_INIT(_handlers, _imgs, _img_count) \ + { \ + .blob = { .cb = &_bt_mesh_dfu_srv_blob_cb }, .cb = _handlers, \ + .imgs = _imgs, .img_count = _img_count, \ + } /** * @@ -45,156 +45,156 @@ struct bt_mesh_dfu_srv; * * @param _srv Pointer to a @ref bt_mesh_dfu_srv instance. */ -#define BT_MESH_MODEL_DFU_SRV(_srv) \ - BT_MESH_MODEL_BLOB_SRV(&(_srv)->blob), \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_DFU_SRV, _bt_mesh_dfu_srv_op, NULL, \ - _srv, &_bt_mesh_dfu_srv_cb) +#define BT_MESH_MODEL_DFU_SRV(_srv) \ + BT_MESH_MODEL_BLOB_SRV(&(_srv)->blob), \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_DFU_SRV, _bt_mesh_dfu_srv_op, NULL, \ + _srv, &_bt_mesh_dfu_srv_cb) /** @brief Firmware Update Server event callbacks. */ struct bt_mesh_dfu_srv_cb { - /** @brief Transfer check callback. - * - * The transfer check can be used to validate the incoming transfer - * before it starts. The contents of the metadata is implementation - * specific, and should contain all the information the application - * needs to determine whether this image should be accepted, and what - * the effect of the transfer would be. - * - * If applying the image will have an effect on the provisioning state - * of the mesh stack, this can be communicated through the @c effect - * return parameter. - * - * The metadata check can be performed both as part of starting a new - * transfer and as a separate procedure. - * - * This handler is optional. - * - * @param srv Firmware Update Server instance. - * @param img DFU image the metadata check is performed on. - * @param metadata Image metadata. - * @param effect Return parameter for the image effect on the - * provisioning state of the mesh stack. - * - * @return 0 on success, or (negative) error code otherwise. - */ - int (*check)(struct bt_mesh_dfu_srv *srv, - const struct bt_mesh_dfu_img *img, - struct net_buf_simple *metadata, - enum bt_mesh_dfu_effect *effect); + /** @brief Transfer check callback. + * + * The transfer check can be used to validate the incoming transfer + * before it starts. The contents of the metadata is implementation + * specific, and should contain all the information the application + * needs to determine whether this image should be accepted, and what + * the effect of the transfer would be. + * + * If applying the image will have an effect on the provisioning state + * of the mesh stack, this can be communicated through the @c effect + * return parameter. + * + * The metadata check can be performed both as part of starting a new + * transfer and as a separate procedure. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image the metadata check is performed on. + * @param metadata Image metadata. + * @param effect Return parameter for the image effect on the + * provisioning state of the mesh stack. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*check)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, + struct net_buf_simple *metadata, + enum bt_mesh_dfu_effect *effect); - /** @brief Transfer start callback. - * - * Called when the Firmware Update Server is ready to start a new DFU transfer. - * The application must provide an initialized BLOB stream to be used - * during the DFU transfer. - * - * The following error codes are treated specially, and should be used - * to communicate these issues: - * - @c -ENOMEM: The device cannot fit this image. - * - @c -EBUSY: The application is temporarily unable to accept the - * transfer. - * - @c -EALREADY: The device has already received and verified this - * image, and there's no need to transfer it again. The Firmware Update model - * will skip the transfer phase, and mark the image as verified. - * - * This handler is mandatory. - * - * @param srv Firmware Update Server instance. - * @param img DFU image being updated. - * @param metadata Image metadata. - * @param io BLOB stream return parameter. Must be set to a - * valid BLOB stream by the callback. - * - * @return 0 on success, or (negative) error code otherwise. Return - * codes @c -ENOMEM, @c -EBUSY @c -EALREADY will be passed to - * the updater, other error codes are reported as internal - * errors. - */ - int (*start)(struct bt_mesh_dfu_srv *srv, - const struct bt_mesh_dfu_img *img, - struct net_buf_simple *metadata, - const struct bt_mesh_blob_io **io); + /** @brief Transfer start callback. + * + * Called when the Firmware Update Server is ready to start a new DFU transfer. + * The application must provide an initialized BLOB stream to be used + * during the DFU transfer. + * + * The following error codes are treated specially, and should be used + * to communicate these issues: + * - @c -ENOMEM: The device cannot fit this image. + * - @c -EBUSY: The application is temporarily unable to accept the + * transfer. + * - @c -EALREADY: The device has already received and verified this + * image, and there's no need to transfer it again. The Firmware Update model + * will skip the transfer phase, and mark the image as verified. + * + * This handler is mandatory. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param metadata Image metadata. + * @param io BLOB stream return parameter. Must be set to a + * valid BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code otherwise. Return + * codes @c -ENOMEM, @c -EBUSY @c -EALREADY will be passed to + * the updater, other error codes are reported as internal + * errors. + */ + int (*start)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, + struct net_buf_simple *metadata, + const struct bt_mesh_blob_io **io); - /** @brief Transfer end callback. - * - * This handler is optional. - * - * If the transfer is successful, the application should verify the - * firmware image, and call either @ref bt_mesh_dfu_srv_verified or - * @ref bt_mesh_dfu_srv_rejected depending on the outcome. - * - * If the transfer fails, the Firmware Update Server will be available for new - * transfers immediately after this function returns. - * - * @param srv Firmware Update Server instance. - * @param img DFU image that failed the update. - * @param success Whether the DFU transfer was successful. - */ - void (*end)(struct bt_mesh_dfu_srv *srv, - const struct bt_mesh_dfu_img *img, bool success); + /** @brief Transfer end callback. + * + * This handler is optional. + * + * If the transfer is successful, the application should verify the + * firmware image, and call either @ref bt_mesh_dfu_srv_verified or + * @ref bt_mesh_dfu_srv_rejected depending on the outcome. + * + * If the transfer fails, the Firmware Update Server will be available for new + * transfers immediately after this function returns. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that failed the update. + * @param success Whether the DFU transfer was successful. + */ + void (*end)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, bool success); - /** @brief Transfer recovery callback. - * - * If the device reboots in the middle of a transfer, the Firmware Update Server - * calls this function when the Bluetooth Mesh subsystem is started. - * - * This callback is optional, but transfers will not be recovered after - * a reboot without it. - * - * @param srv Firmware Update Server instance. - * @param img DFU image being updated. - * @param io BLOB stream return parameter. Must be set to a valid BLOB - * stream by the callback. - * - * @return 0 on success, or (negative) error code to abandon the - * transfer. - */ - int (*recover)(struct bt_mesh_dfu_srv *srv, - const struct bt_mesh_dfu_img *img, - const struct bt_mesh_blob_io **io); + /** @brief Transfer recovery callback. + * + * If the device reboots in the middle of a transfer, the Firmware Update Server + * calls this function when the Bluetooth Mesh subsystem is started. + * + * This callback is optional, but transfers will not be recovered after + * a reboot without it. + * + * @param srv Firmware Update Server instance. + * @param img DFU image being updated. + * @param io BLOB stream return parameter. Must be set to a valid BLOB + * stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img, + const struct bt_mesh_blob_io **io); - /** @brief Transfer apply callback. - * - * Called after a transfer has been validated, and the updater sends an - * apply message to the Target nodes. - * - * This handler is optional. - * - * @param srv Firmware Update Server instance. - * @param img DFU image that should be applied. - * - * @return 0 on success, or (negative) error code otherwise. - */ - int (*apply)(struct bt_mesh_dfu_srv *srv, - const struct bt_mesh_dfu_img *img); + /** @brief Transfer apply callback. + * + * Called after a transfer has been validated, and the updater sends an + * apply message to the Target nodes. + * + * This handler is optional. + * + * @param srv Firmware Update Server instance. + * @param img DFU image that should be applied. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*apply)(struct bt_mesh_dfu_srv *srv, + const struct bt_mesh_dfu_img *img); }; /** @brief Firmware Update Server instance. * - * Should be initialized with @ref BT_MESH_DFU_SRV_INIT. + * Should be initialized with @ref BLE_MESH_DFU_SRV_INIT. */ struct bt_mesh_dfu_srv { - /** Underlying BLOB Transfer Server. */ - struct bt_mesh_blob_srv blob; - /** Callback structure. */ - const struct bt_mesh_dfu_srv_cb *cb; - /** List of updatable images. */ - const struct bt_mesh_dfu_img *imgs; - /** Number of updatable images. */ - size_t img_count; + /** Underlying BLOB Transfer Server. */ + struct bt_mesh_blob_srv blob; + /** Callback structure. */ + const struct bt_mesh_dfu_srv_cb *cb; + /** List of updatable images. */ + const struct bt_mesh_dfu_img *imgs; + /** Number of updatable images. */ + size_t img_count; - /* Runtime state */ - const struct bt_mesh_model *mod; - struct { - /* Effect of transfer, @see bt_mesh_dfu_effect. */ - uint8_t effect; - /* Current phase, @see bt_mesh_dfu_phase. */ - uint8_t phase; - uint8_t ttl; - uint8_t idx; - uint16_t timeout_base; - uint16_t meta; - } update; + /* Runtime state */ + const struct bt_mesh_model *mod; + struct { + /* Effect of transfer, @see bt_mesh_dfu_effect. */ + uint8_t effect; + /* Current phase, @see bt_mesh_dfu_phase. */ + uint8_t phase; + uint8_t ttl; + uint8_t idx; + uint16_t timeout_base; + uint16_t meta; + } update; }; /** @brief Accept the received DFU transfer. @@ -235,7 +235,7 @@ void bt_mesh_dfu_srv_cancel(struct bt_mesh_dfu_srv *srv); */ void bt_mesh_dfu_srv_applied(struct bt_mesh_dfu_srv *srv); -/** @brief Check if the Firmware Update Server is busy processing a transfer. +/** @brief Check if the Firmware Update Server is busy processing a transfer. * * @param srv Firmware Update Server instance. * @@ -261,6 +261,4 @@ extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfu_srv_blob_cb; } #endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_DFU_SRV_H__ */ - -/** @} */ +#endif /* _BLE_MESH_v11_DFU_SRV_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h index 18304f39f6..29199360a4 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob.h @@ -1,15 +1,25 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_H__ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_H__ +#ifndef _BLE_MESH_v11_BLOB_H__ +#define _BLE_MESH_v11_BLOB_H__ #include - -#include +#include "mesh/types.h" +#include "mesh/utils.h" +#include "mesh.h" +#include "mesh/utils.h" +#include "mesh/access.h" +#include "mesh/atomic.h" +#include "mesh/timer.h" +#include "mesh/compiler.h" +#include "mesh/trace.h" +#include "transport.h" +#include "mesh_v1.1/mbt/blob.h" #ifdef __cplusplus extern "C" { @@ -21,236 +31,236 @@ extern "C" { * @{ */ -#ifndef CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX -#define CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX 0 +#ifndef CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX +#define CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX 0 #endif /** BLOB transfer mode. */ enum bt_mesh_blob_xfer_mode { - /** No valid transfer mode. */ - BT_MESH_BLOB_XFER_MODE_NONE, - /** Push mode (Push BLOB Transfer Mode). */ - BT_MESH_BLOB_XFER_MODE_PUSH, - /** Pull mode (Pull BLOB Transfer Mode). */ - BT_MESH_BLOB_XFER_MODE_PULL, - /** Both modes are valid. */ - BT_MESH_BLOB_XFER_MODE_ALL, + /** No valid transfer mode. */ + BT_MESH_BLOB_XFER_MODE_NONE, + /** Push mode (Push BLOB Transfer Mode). */ + BT_MESH_BLOB_XFER_MODE_PUSH, + /** Pull mode (Pull BLOB Transfer Mode). */ + BT_MESH_BLOB_XFER_MODE_PULL, + /** Both modes are valid. */ + BT_MESH_BLOB_XFER_MODE_ALL, }; /** Transfer phase. */ enum bt_mesh_blob_xfer_phase { - /** The BLOB Transfer Server is awaiting configuration. */ - BT_MESH_BLOB_XFER_PHASE_INACTIVE, - /** The BLOB Transfer Server is ready to receive a BLOB transfer. */ - BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START, - /** The BLOB Transfer Server is waiting for the next block of data. */ - BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK, - /** The BLOB Transfer Server is waiting for the next chunk of data. */ - BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK, - /** The BLOB was transferred successfully. */ - BT_MESH_BLOB_XFER_PHASE_COMPLETE, - /** The BLOB transfer is paused. */ - BT_MESH_BLOB_XFER_PHASE_SUSPENDED, + /** The BLOB Transfer Server is awaiting configuration. */ + BT_MESH_BLOB_XFER_PHASE_INACTIVE, + /** The BLOB Transfer Server is ready to receive a BLOB transfer. */ + BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START, + /** The BLOB Transfer Server is waiting for the next block of data. */ + BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK, + /** The BLOB Transfer Server is waiting for the next chunk of data. */ + BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK, + /** The BLOB was transferred successfully. */ + BT_MESH_BLOB_XFER_PHASE_COMPLETE, + /** The BLOB transfer is paused. */ + BT_MESH_BLOB_XFER_PHASE_SUSPENDED, }; /** BLOB model status codes. */ enum bt_mesh_blob_status { - /** The message was processed successfully. */ - BT_MESH_BLOB_SUCCESS, - /** The Block Number field value is not within the range of blocks being - * transferred. - */ - BT_MESH_BLOB_ERR_INVALID_BLOCK_NUM, - /** The block size is smaller than the size indicated by the Min Block - * Size Log state or is larger than the size indicated by the Max Block - * Size Log state. - */ - BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE, - /** The chunk size exceeds the size indicated by the Max Chunk Size - * state, or the number of chunks exceeds the number specified by the - * Max Total Chunks state. - */ - BT_MESH_BLOB_ERR_INVALID_CHUNK_SIZE, - /** The operation cannot be performed while the server is in the current - * phase. - */ - BT_MESH_BLOB_ERR_WRONG_PHASE, - /** A parameter value in the message cannot be accepted. */ - BT_MESH_BLOB_ERR_INVALID_PARAM, - /** The message contains a BLOB ID value that is not expected. */ - BT_MESH_BLOB_ERR_WRONG_BLOB_ID, - /** There is not enough space available in memory to receive the BLOB. - */ - BT_MESH_BLOB_ERR_BLOB_TOO_LARGE, - /** The transfer mode is not supported by the BLOB Transfer Server - * model. - */ - BT_MESH_BLOB_ERR_UNSUPPORTED_MODE, - /** An internal error occurred on the node. */ - BT_MESH_BLOB_ERR_INTERNAL, - /** The requested information cannot be provided while the server is in - * the current phase. - */ - BT_MESH_BLOB_ERR_INFO_UNAVAILABLE, + /** The message was processed successfully. */ + BT_MESH_BLOB_SUCCESS, + /** The Block Number field value is not within the range of blocks being + * transferred. + */ + BT_MESH_BLOB_ERR_INVALID_BLOCK_NUM, + /** The block size is smaller than the size indicated by the Min Block + * Size Log state or is larger than the size indicated by the Max Block + * Size Log state. + */ + BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE, + /** The chunk size exceeds the size indicated by the Max Chunk Size + * state, or the number of chunks exceeds the number specified by the + * Max Total Chunks state. + */ + BT_MESH_BLOB_ERR_INVALID_CHUNK_SIZE, + /** The operation cannot be performed while the server is in the current + * phase. + */ + BT_MESH_BLOB_ERR_WRONG_PHASE, + /** A parameter value in the message cannot be accepted. */ + BT_MESH_BLOB_ERR_INVALID_PARAM, + /** The message contains a BLOB ID value that is not expected. */ + BT_MESH_BLOB_ERR_WRONG_BLOB_ID, + /** There is not enough space available in memory to receive the BLOB. + */ + BT_MESH_BLOB_ERR_BLOB_TOO_LARGE, + /** The transfer mode is not supported by the BLOB Transfer Server + * model. + */ + BT_MESH_BLOB_ERR_UNSUPPORTED_MODE, + /** An internal error occurred on the node. */ + BT_MESH_BLOB_ERR_INTERNAL, + /** The requested information cannot be provided while the server is in + * the current phase. + */ + BT_MESH_BLOB_ERR_INFO_UNAVAILABLE, }; /** BLOB transfer data block. */ struct bt_mesh_blob_block { - /** Block size in bytes */ - size_t size; - /** Offset in bytes from the start of the BLOB. */ - off_t offset; - /** Block number */ - uint16_t number; - /** Number of chunks in block. */ - uint16_t chunk_count; - /** Bitmap of missing chunks. */ - uint8_t missing[DIV_ROUND_UP(CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX, - 8)]; + /** Block size in bytes */ + size_t size; + /** Offset in bytes from the start of the BLOB. */ + off_t offset; + /** Block number */ + uint16_t number; + /** Number of chunks in block. */ + uint16_t chunk_count; + /** Bitmap of missing chunks. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX, + 8)]; }; /** BLOB data chunk. */ struct bt_mesh_blob_chunk { - /** Offset of the chunk data from the start of the block. */ - off_t offset; - /** Chunk data size. */ - size_t size; - /** Chunk data. */ - uint8_t *data; + /** Offset of the chunk data from the start of the block. */ + off_t offset; + /** Chunk data size. */ + size_t size; + /** Chunk data. */ + uint8_t *data; }; /** BLOB transfer. */ struct bt_mesh_blob_xfer { - /** BLOB ID. */ - uint64_t id; - /** Total BLOB size in bytes. */ - size_t size; - /** BLOB transfer mode. */ - enum bt_mesh_blob_xfer_mode mode; - /* Logarithmic representation of the block size. */ - uint8_t block_size_log; - /** Base chunk size. May be smaller for the last chunk. */ - uint16_t chunk_size; + /** BLOB ID. */ + uint64_t id; + /** Total BLOB size in bytes. */ + size_t size; + /** BLOB transfer mode. */ + enum bt_mesh_blob_xfer_mode mode; + /* Logarithmic representation of the block size. */ + uint8_t block_size_log; + /** Base chunk size. May be smaller for the last chunk. */ + uint16_t chunk_size; }; /** BLOB stream interaction mode. */ enum bt_mesh_blob_io_mode { - /** Read data from the stream. */ - BT_MESH_BLOB_READ, - /** Write data to the stream. */ - BT_MESH_BLOB_WRITE, + /** Read data from the stream. */ + BT_MESH_BLOB_READ, + /** Write data to the stream. */ + BT_MESH_BLOB_WRITE, }; /** BLOB stream. */ struct bt_mesh_blob_io { - /** @brief Open callback. - * - * Called when the reader is opened for reading. - * - * @param io BLOB stream. - * @param xfer BLOB transfer. - * @param mode Direction of the stream (read/write). - * - * @return 0 on success, or (negative) error code otherwise. - */ - int (*open)(const struct bt_mesh_blob_io *io, - const struct bt_mesh_blob_xfer *xfer, - enum bt_mesh_blob_io_mode mode); + /** @brief Open callback. + * + * Called when the reader is opened for reading. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param mode Direction of the stream (read/write). + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*open)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + enum bt_mesh_blob_io_mode mode); - /** @brief Close callback. - * - * Called when the reader is closed. - * - * @param io BLOB stream. - * @param xfer BLOB transfer. - */ - void (*close)(const struct bt_mesh_blob_io *io, - const struct bt_mesh_blob_xfer *xfer); + /** @brief Close callback. + * + * Called when the reader is closed. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + */ + void (*close)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer); - /** @brief Block start callback. - * - * Called when a new block is opened for sending. Each block is only - * sent once, and are always sent in increasing order. The data chunks - * inside a single block may be requested out of order and multiple - * times. - * - * @param io BLOB stream. - * @param xfer BLOB transfer. - * @param block Block that was started. - */ - int (*block_start)(const struct bt_mesh_blob_io *io, - const struct bt_mesh_blob_xfer *xfer, - const struct bt_mesh_blob_block *block); + /** @brief Block start callback. + * + * Called when a new block is opened for sending. Each block is only + * sent once, and are always sent in increasing order. The data chunks + * inside a single block may be requested out of order and multiple + * times. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that was started. + */ + int (*block_start)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block); - /** @brief Block end callback. - * - * Called when the current block has been transmitted in full. - * No data from this block will be requested again, and the application - * data associated with this block may be discarded. - * - * @param io BLOB stream. - * @param xfer BLOB transfer. - * @param block Block that finished sending. - */ - void (*block_end)(const struct bt_mesh_blob_io *io, - const struct bt_mesh_blob_xfer *xfer, - const struct bt_mesh_blob_block *block); + /** @brief Block end callback. + * + * Called when the current block has been transmitted in full. + * No data from this block will be requested again, and the application + * data associated with this block may be discarded. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block that finished sending. + */ + void (*block_end)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block); - /** @brief Chunk data write callback. - * - * Used by the BLOB Transfer Server on incoming data. - * - * Each block is divided into chunks of data. This callback is called - * when a new chunk of data is received. Chunks may be received in - * any order within their block. - * - * If the callback returns successfully, this chunk will be marked as - * received, and will not be received again unless the block is - * restarted due to a transfer suspension. If the callback returns a - * non-zero value, the chunk remains unreceived, and the BLOB Transfer - * Client will attempt to resend it later. - * - * Note that the Client will only perform a limited number of attempts - * at delivering a chunk before dropping a Target node from the transfer. - * The number of retries performed by the Client is implementation - * specific. - * - * @param io BLOB stream. - * @param xfer BLOB transfer. - * @param block Block the chunk is part of. - * @param chunk Received chunk. - * - * @return 0 on success, or (negative) error code otherwise. - */ - int (*wr)(const struct bt_mesh_blob_io *io, - const struct bt_mesh_blob_xfer *xfer, - const struct bt_mesh_blob_block *block, - const struct bt_mesh_blob_chunk *chunk); + /** @brief Chunk data write callback. + * + * Used by the BLOB Transfer Server on incoming data. + * + * Each block is divided into chunks of data. This callback is called + * when a new chunk of data is received. Chunks may be received in + * any order within their block. + * + * If the callback returns successfully, this chunk will be marked as + * received, and will not be received again unless the block is + * restarted due to a transfer suspension. If the callback returns a + * non-zero value, the chunk remains unreceived, and the BLOB Transfer + * Client will attempt to resend it later. + * + * Note that the Client will only perform a limited number of attempts + * at delivering a chunk before dropping a Target node from the transfer. + * The number of retries performed by the Client is implementation + * specific. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Received chunk. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*wr)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block, + const struct bt_mesh_blob_chunk *chunk); - /** @brief Chunk data read callback. - * - * Used by the BLOB Transfer Client to fetch outgoing data. - * - * The Client calls the chunk data request callback to populate a chunk - * message going out to the Target nodes. The data request callback - * may be called out of order and multiple times for each offset, and - * cannot be used as an indication of progress. - * - * Returning a non-zero status code on the chunk data request callback - * results in termination of the transfer. - * - * @param io BLOB stream. - * @param xfer BLOB transfer. - * @param block Block the chunk is part of. - * @param chunk Chunk to get the data of. The buffer pointer to by the - * @c data member should be filled by the callback. - * - * @return 0 on success, or (negative) error code otherwise. - */ - int (*rd)(const struct bt_mesh_blob_io *io, - const struct bt_mesh_blob_xfer *xfer, - const struct bt_mesh_blob_block *block, - const struct bt_mesh_blob_chunk *chunk); + /** @brief Chunk data read callback. + * + * Used by the BLOB Transfer Client to fetch outgoing data. + * + * The Client calls the chunk data request callback to populate a chunk + * message going out to the Target nodes. The data request callback + * may be called out of order and multiple times for each offset, and + * cannot be used as an indication of progress. + * + * Returning a non-zero status code on the chunk data request callback + * results in termination of the transfer. + * + * @param io BLOB stream. + * @param xfer BLOB transfer. + * @param block Block the chunk is part of. + * @param chunk Chunk to get the data of. The buffer pointer to by the + * @c data member should be filled by the callback. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*rd)(const struct bt_mesh_blob_io *io, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_block *block, + const struct bt_mesh_blob_chunk *chunk); }; /** @} */ @@ -259,4 +269,4 @@ struct bt_mesh_blob_io { } #endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_H__ */ +#endif /* _BLE_MESH_v11_BLOB_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h index 574ec82715..59b2169370 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_cli.h @@ -1,16 +1,26 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_CLI_H_ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_CLI_H_ +#ifndef _BLE_MESH_v11_BLOB_CLI_H_ +#define _BLE_MESH_v11_BLOB_CLI_H_ #include -#include -#include +#include "mesh/access.h" +#include "mesh/utils.h" +#include "mesh.h" +#include "mesh/utils.h" +#include "mesh/access.h" +#include "mesh/atomic.h" +#include "mesh/timer.h" +#include "mesh/compiler.h" +#include "mesh/trace.h" +#include "transport.h" +#include "mesh_v1.1/mbt/blob.h" #ifdef __cplusplus extern "C" { @@ -30,41 +40,41 @@ struct bt_mesh_blob_cli; * * @param _cli Pointer to a @ref bt_mesh_blob_cli instance. */ -#define BT_MESH_MODEL_BLOB_CLI(_cli) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_BLOB_CLI, _bt_mesh_blob_cli_op, \ - NULL, _cli, &_bt_mesh_blob_cli_cb) +#define BT_MESH_MODEL_BLOB_CLI(_cli) \ + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_BLOB_CLI, _bt_mesh_blob_cli_op, \ + NULL, _cli, &_bt_mesh_blob_cli_cb) /** Target node's Pull mode (Pull BLOB Transfer Mode) context used * while sending chunks to the Target node. */ struct bt_mesh_blob_target_pull { - /** Timestamp when the Block Report Timeout Timer expires for this Target node. */ - int64_t block_report_timestamp; + /** Timestamp when the Block Report Timeout Timer expires for this Target node. */ + int64_t block_report_timestamp; - /** Missing chunks reported by this Target node. */ - uint8_t missing[DIV_ROUND_UP(CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX, 8)]; + /** Missing chunks reported by this Target node. */ + uint8_t missing[DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX, 8)]; }; /** BLOB Transfer Client Target node. */ struct bt_mesh_blob_target { - /** Linked list node */ - sys_snode_t n; + /** Linked list node */ + sys_snode_t n; - /** Target node address. */ - uint16_t addr; + /** Target node address. */ + uint16_t addr; /** Target node's Pull mode context. * Needs to be initialized when sending a BLOB in Pull mode. */ - struct bt_mesh_blob_target_pull *pull; + struct bt_mesh_blob_target_pull *pull; - /** BLOB transfer status, see @ref bt_mesh_blob_status. */ - uint8_t status; + /** BLOB transfer status, see @ref bt_mesh_blob_status. */ + uint8_t status; - uint8_t procedure_complete:1, /* Procedure has been completed. */ - acked:1, /* Message has been acknowledged. Not used when sending. */ - timedout:1, /* Target node didn't respond after specified timeout. */ - skip:1; /* Skip Target node from broadcast. */ + uint8_t procedure_complete: 1, /* Procedure has been completed. */ + acked: 1, /* Message has been acknowledged. Not used when sending. */ + timedout: 1, /* Target node didn't respond after specified timeout. */ + skip: 1; /* Skip Target node from broadcast. */ }; /** BLOB transfer information. @@ -75,112 +85,112 @@ struct bt_mesh_blob_target { * the fields below @c id are not initialized. */ struct bt_mesh_blob_xfer_info { - /** BLOB transfer status. */ - enum bt_mesh_blob_status status; + /** BLOB transfer status. */ + enum bt_mesh_blob_status status; - /** BLOB transfer mode. */ - enum bt_mesh_blob_xfer_mode mode; + /** BLOB transfer mode. */ + enum bt_mesh_blob_xfer_mode mode; - /** BLOB transfer phase. */ - enum bt_mesh_blob_xfer_phase phase; + /** BLOB transfer phase. */ + enum bt_mesh_blob_xfer_phase phase; - /** BLOB ID. */ - uint64_t id; + /** BLOB ID. */ + uint64_t id; - /** BLOB size in octets. */ - uint32_t size; + /** BLOB size in octets. */ + uint32_t size; - /** Logarithmic representation of the block size. */ - uint8_t block_size_log; + /** Logarithmic representation of the block size. */ + uint8_t block_size_log; - /** MTU size in octets. */ - uint16_t mtu_size; + /** MTU size in octets. */ + uint16_t mtu_size; - /** Bit field indicating blocks that were not received. */ - const uint8_t *missing_blocks; + /** Bit field indicating blocks that were not received. */ + const uint8_t *missing_blocks; }; /** BLOB Transfer Client transfer inputs. */ struct bt_mesh_blob_cli_inputs { - /** Linked list of Target nodes. Each node should point to @ref - * bt_mesh_blob_target::n. - */ - sys_slist_t targets; + /** Linked list of Target nodes. Each node should point to @ref + * bt_mesh_blob_target::n. + */ + sys_slist_t targets; - /** AppKey index to send with. */ - uint16_t app_idx; + /** AppKey index to send with. */ + uint16_t app_idx; - /** Group address destination for the BLOB transfer, or @ref - * BT_MESH_ADDR_UNASSIGNED to send every message to each Target - * node individually. - */ - uint16_t group; + /** Group address destination for the BLOB transfer, or @ref + * BLE_MESH_ADDR_UNASSIGNED to send every message to each Target + * node individually. + */ + uint16_t group; - /** Time to live value of BLOB transfer messages. */ - uint8_t ttl; + /** Time to live value of BLOB transfer messages. */ + uint8_t ttl; - /** Additional response time for the Target nodes, in 10-second increments. - * - * The extra time can be used to give the Target nodes more time to respond - * to messages from the Client. The actual timeout will be calculated - * according to the following formula: - * - * @verbatim - * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) - * @endverbatim - * - * If a Target node fails to respond to a message from the Client within the - * configured transfer timeout, the Target node is dropped. - */ - uint16_t timeout_base; + /** Additional response time for the Target nodes, in 10-second increments. + * + * The extra time can be used to give the Target nodes more time to respond + * to messages from the Client. The actual timeout will be calculated + * according to the following formula: + * + * @verbatim + * timeout = 20 seconds + (10 seconds * timeout_base) + (100 ms * TTL) + * @endverbatim + * + * If a Target node fails to respond to a message from the Client within the + * configured transfer timeout, the Target node is dropped. + */ + uint16_t timeout_base; }; /** Transfer capabilities of a Target node. */ struct bt_mesh_blob_cli_caps { - /** Max BLOB size. */ - size_t max_size; + /** Max BLOB size. */ + size_t max_size; - /** Logarithmic representation of the minimum block size. */ - uint8_t min_block_size_log; + /** Logarithmic representation of the minimum block size. */ + uint8_t min_block_size_log; - /** Logarithmic representation of the maximum block size. */ - uint8_t max_block_size_log; + /** Logarithmic representation of the maximum block size. */ + uint8_t max_block_size_log; - /** Max number of chunks per block. */ - uint16_t max_chunks; + /** Max number of chunks per block. */ + uint16_t max_chunks; - /** Max chunk size. */ - uint16_t max_chunk_size; + /** Max chunk size. */ + uint16_t max_chunk_size; - /** Max MTU size. */ - uint16_t mtu_size; + /** Max MTU size. */ + uint16_t mtu_size; - /** Supported transfer modes. */ - enum bt_mesh_blob_xfer_mode modes; + /** Supported transfer modes. */ + enum bt_mesh_blob_xfer_mode modes; }; /** BLOB Transfer Client state. */ enum bt_mesh_blob_cli_state { - /** No transfer is active. */ - BT_MESH_BLOB_CLI_STATE_NONE, - /** Retrieving transfer capabilities. */ - BT_MESH_BLOB_CLI_STATE_CAPS_GET, - /** Sending transfer start. */ - BT_MESH_BLOB_CLI_STATE_START, - /** Sending block start. */ - BT_MESH_BLOB_CLI_STATE_BLOCK_START, - /** Sending block chunks. */ - BT_MESH_BLOB_CLI_STATE_BLOCK_SEND, - /** Checking block status. */ - BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK, - /** Checking transfer status. */ - BT_MESH_BLOB_CLI_STATE_XFER_CHECK, - /** Cancelling transfer. */ - BT_MESH_BLOB_CLI_STATE_CANCEL, - /** Transfer is suspended. */ - BT_MESH_BLOB_CLI_STATE_SUSPENDED, - /** Checking transfer progress. */ - BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET, + /** No transfer is active. */ + BT_MESH_BLOB_CLI_STATE_NONE, + /** Retrieving transfer capabilities. */ + BT_MESH_BLOB_CLI_STATE_CAPS_GET, + /** Sending transfer start. */ + BT_MESH_BLOB_CLI_STATE_START, + /** Sending block start. */ + BT_MESH_BLOB_CLI_STATE_BLOCK_START, + /** Sending block chunks. */ + BT_MESH_BLOB_CLI_STATE_BLOCK_SEND, + /** Checking block status. */ + BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK, + /** Checking transfer status. */ + BT_MESH_BLOB_CLI_STATE_XFER_CHECK, + /** Cancelling transfer. */ + BT_MESH_BLOB_CLI_STATE_CANCEL, + /** Transfer is suspended. */ + BT_MESH_BLOB_CLI_STATE_SUSPENDED, + /** Checking transfer progress. */ + BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET, }; /** Event handler callbacks for the BLOB Transfer Client model. @@ -188,138 +198,138 @@ enum bt_mesh_blob_cli_state { * All handlers are optional. */ struct bt_mesh_blob_cli_cb { - /** @brief Capabilities retrieval completion callback. - * - * Called when the capabilities retrieval procedure completes, indicating that - * a common set of acceptable transfer parameters have been established - * for the given list of Target nodes. All compatible Target nodes have - * status code @ref BT_MESH_BLOB_SUCCESS. - * - * @param cli BLOB Transfer Client instance. - * @param caps Safe transfer capabilities if the transfer capabilities - * of at least one Target node has satisfied the Client, or NULL otherwise. - */ - void (*caps)(struct bt_mesh_blob_cli *cli, - const struct bt_mesh_blob_cli_caps *caps); + /** @brief Capabilities retrieval completion callback. + * + * Called when the capabilities retrieval procedure completes, indicating that + * a common set of acceptable transfer parameters have been established + * for the given list of Target nodes. All compatible Target nodes have + * status code @ref BT_MESH_BLOB_SUCCESS. + * + * @param cli BLOB Transfer Client instance. + * @param caps Safe transfer capabilities if the transfer capabilities + * of at least one Target node has satisfied the Client, or NULL otherwise. + */ + void (*caps)(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_cli_caps *caps); - /** @brief Target node loss callback. - * - * Called whenever a Target node has been lost due to some error in the - * transfer. Losing a Target node is not considered a fatal error for - * the Client until all Target nodes have been lost. - * - * @param cli BLOB Transfer Client instance. - * @param target Target node that was lost. - * @param reason Reason for the Target node loss. - */ - void (*lost_target)(struct bt_mesh_blob_cli *cli, - struct bt_mesh_blob_target *target, - enum bt_mesh_blob_status reason); + /** @brief Target node loss callback. + * + * Called whenever a Target node has been lost due to some error in the + * transfer. Losing a Target node is not considered a fatal error for + * the Client until all Target nodes have been lost. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that was lost. + * @param reason Reason for the Target node loss. + */ + void (*lost_target)(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + enum bt_mesh_blob_status reason); - /** @brief Transfer is suspended. - * - * Called when the transfer is suspended due to response timeout from all Target nodes. - * - * @param cli BLOB Transfer Client instance. - */ - void (*suspended)(struct bt_mesh_blob_cli *cli); + /** @brief Transfer is suspended. + * + * Called when the transfer is suspended due to response timeout from all Target nodes. + * + * @param cli BLOB Transfer Client instance. + */ + void (*suspended)(struct bt_mesh_blob_cli *cli); - /** @brief Transfer end callback. - * - * Called when the transfer ends. - * - * @param cli BLOB Transfer Client instance. - * @param xfer Completed transfer. - * @param success Status of the transfer. - * Is @c true if at least one Target - * node received the whole transfer. - */ - void (*end)(struct bt_mesh_blob_cli *cli, - const struct bt_mesh_blob_xfer *xfer, bool success); + /** @brief Transfer end callback. + * + * Called when the transfer ends. + * + * @param cli BLOB Transfer Client instance. + * @param xfer Completed transfer. + * @param success Status of the transfer. + * Is @c true if at least one Target + * node received the whole transfer. + */ + void (*end)(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_xfer *xfer, bool success); - /** @brief Transfer progress callback - * - * The content of @c info is invalidated upon exit from the callback. - * Therefore it needs to be copied if it is planned to be used later. - * - * @param cli BLOB Transfer Client instance. - * @param target Target node that responded to the request. - * @param info BLOB transfer information. - */ - void (*xfer_progress)(struct bt_mesh_blob_cli *cli, - struct bt_mesh_blob_target *target, - const struct bt_mesh_blob_xfer_info *info); + /** @brief Transfer progress callback + * + * The content of @c info is invalidated upon exit from the callback. + * Therefore it needs to be copied if it is planned to be used later. + * + * @param cli BLOB Transfer Client instance. + * @param target Target node that responded to the request. + * @param info BLOB transfer information. + */ + void (*xfer_progress)(struct bt_mesh_blob_cli *cli, + struct bt_mesh_blob_target *target, + const struct bt_mesh_blob_xfer_info *info); - /** @brief End of Get Transfer Progress procedure. - * - * Called when all Target nodes have responded or the procedure timed-out. - * - * @param cli BLOB Transfer Client instance. - */ - void (*xfer_progress_complete)(struct bt_mesh_blob_cli *cli); + /** @brief End of Get Transfer Progress procedure. + * + * Called when all Target nodes have responded or the procedure timed-out. + * + * @param cli BLOB Transfer Client instance. + */ + void (*xfer_progress_complete)(struct bt_mesh_blob_cli *cli); }; /** @cond INTERNAL_HIDDEN */ struct blob_cli_broadcast_ctx { - /** Called for every Target node in unicast mode, or once in case of multicast mode. */ - void (*send)(struct bt_mesh_blob_cli *cli, uint16_t dst); - /** Called after every @ref blob_cli_broadcast_ctx::send callback. */ - void (*send_complete)(struct bt_mesh_blob_cli *cli, uint16_t dst); - /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes - * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called - * after transmission has been completed. - */ - void (*next)(struct bt_mesh_blob_cli *cli); - /** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before - * @ref blob_cli_broadcast_ctx::next is called. - */ - bool acked; - /** If true, the message is always sent in a unicast way. */ - bool force_unicast; - /** If true, non-responsive Target nodes won't be dropped after transfer has timed out. */ - bool optional; - /** Set to true by the BLOB Transfer Client between blob_cli_broadcast - * and broadcast_complete calls. - */ - bool is_inited; - /* Defines a time in ms by which the broadcast API postpones sending the message to a next - * target or completing the broadcast. - */ - uint32_t post_send_delay_ms; + /** Called for every Target node in unicast mode, or once in case of multicast mode. */ + void (*send)(struct bt_mesh_blob_cli *cli, uint16_t dst); + /** Called after every @ref blob_cli_broadcast_ctx::send callback. */ + void (*send_complete)(struct bt_mesh_blob_cli *cli, uint16_t dst); + /** If @ref blob_cli_broadcast_ctx::acked is true, called after all Target nodes + * have confirmed reception by @ref blob_cli_broadcast_rsp. Otherwise, called + * after transmission has been completed. + */ + void (*next)(struct bt_mesh_blob_cli *cli); + /** If true, every transmission needs to be confirmed by @ref blob_cli_broadcast_rsp before + * @ref blob_cli_broadcast_ctx::next is called. + */ + bool acked; + /** If true, the message is always sent in a unicast way. */ + bool force_unicast; + /** If true, non-responsive Target nodes won't be dropped after transfer has timed out. */ + bool optional; + /** Set to true by the BLOB Transfer Client between blob_cli_broadcast + * and broadcast_complete calls. + */ + bool is_inited; + /* Defines a time in ms by which the broadcast API postpones sending the message to a next + * target or completing the broadcast. + */ + uint32_t post_send_delay_ms; }; /** INTERNAL_HIDDEN @endcond */ /** BLOB Transfer Client model instance. */ struct bt_mesh_blob_cli { - /** Event handler callbacks */ - const struct bt_mesh_blob_cli_cb *cb; + /** Event handler callbacks */ + const struct bt_mesh_blob_cli_cb *cb; - /* Runtime state */ - const struct bt_mesh_model *mod; + /* Runtime state */ + const struct bt_mesh_model *mod; - struct { - struct bt_mesh_blob_target *target; - struct blob_cli_broadcast_ctx ctx; - struct k_work_delayable retry; - /* Represents Client Timeout timer in a timestamp. Used in Pull mode only. */ - int64_t cli_timestamp; - struct k_work_delayable complete; - uint16_t pending; - uint8_t retries; - uint8_t sending : 1, - cancelled : 1; - } tx; + struct { + struct bt_mesh_blob_target *target; + struct blob_cli_broadcast_ctx ctx; + struct k_work_delayable retry; + /* Represents Client Timeout timer in a timestamp. Used in Pull mode only. */ + int64_t cli_timestamp; + struct k_work_delayable complete; + uint16_t pending; + uint8_t retries; + uint8_t sending : 1, + cancelled : 1; + } tx; - const struct bt_mesh_blob_io *io; - const struct bt_mesh_blob_cli_inputs *inputs; - const struct bt_mesh_blob_xfer *xfer; - uint32_t chunk_interval_ms; - uint16_t block_count; - uint16_t chunk_idx; - uint16_t mtu_size; - enum bt_mesh_blob_cli_state state; - struct bt_mesh_blob_block block; - struct bt_mesh_blob_cli_caps caps; + const struct bt_mesh_blob_io *io; + const struct bt_mesh_blob_cli_inputs *inputs; + const struct bt_mesh_blob_xfer *xfer; + uint32_t chunk_interval_ms; + uint16_t block_count; + uint16_t chunk_idx; + uint16_t mtu_size; + enum bt_mesh_blob_cli_state state; + struct bt_mesh_blob_block block; + struct bt_mesh_blob_cli_caps caps; }; /** @brief Retrieve transfer capabilities for a list of Target nodes. @@ -342,7 +352,7 @@ struct bt_mesh_blob_cli { * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_blob_cli_caps_get(struct bt_mesh_blob_cli *cli, - const struct bt_mesh_blob_cli_inputs *inputs); + const struct bt_mesh_blob_cli_inputs *inputs); /** @brief Perform a BLOB transfer. * @@ -366,9 +376,9 @@ int bt_mesh_blob_cli_caps_get(struct bt_mesh_blob_cli *cli, * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_blob_cli_send(struct bt_mesh_blob_cli *cli, - const struct bt_mesh_blob_cli_inputs *inputs, - const struct bt_mesh_blob_xfer *xfer, - const struct bt_mesh_blob_io *io); + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io *io); /** @brief Suspend the active transfer. * @@ -392,6 +402,9 @@ int bt_mesh_blob_cli_resume(struct bt_mesh_blob_cli *cli); */ void bt_mesh_blob_cli_cancel(struct bt_mesh_blob_cli *cli); +void bt_mesh_blob_cli_send_cancel(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_xfer *xfer); + /** @brief Get the progress of BLOB transfer. * * This function can only be used if the BLOB Transfer Client is currently @@ -405,7 +418,7 @@ void bt_mesh_blob_cli_cancel(struct bt_mesh_blob_cli *cli); * @return 0 on success, or (negative) error code otherwise. */ int bt_mesh_blob_cli_xfer_progress_get(struct bt_mesh_blob_cli *cli, - const struct bt_mesh_blob_cli_inputs *inputs); + const struct bt_mesh_blob_cli_inputs *inputs); /** @brief Get the current progress of the active transfer in percent. * @@ -451,4 +464,4 @@ extern const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb; } #endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_CLI_H_ */ +#endif /* _BLE_MESH_v11_BLOB_CLI_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h index 8a0c6b67a1..c2a6e48765 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/mbt/blob_srv.h @@ -1,14 +1,24 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_SRV_H_ -#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_SRV_H_ +#ifndef _BLE_MESH_v11_BLOB_SRV_H_ +#define _BLE_MESH_v11_BLOB_SRV_H_ -#include -#include +#include "mesh/access.h" +#include "mesh/utils.h" +#include "mesh_v1.1/mbt/blob.h" +#include "mesh.h" +#include "mesh/utils.h" +#include "mesh/access.h" +#include "mesh/atomic.h" +#include "mesh/timer.h" +#include "mesh/compiler.h" +#include "mesh/trace.h" +#include "transport.h" #ifdef __cplusplus extern "C" { @@ -26,10 +36,9 @@ struct bt_mesh_blob_srv; * * @brief Max number of blocks in a single transfer. */ -#if defined(CONFIG_BT_MESH_BLOB_SRV) -#define BT_MESH_BLOB_BLOCKS_MAX \ - (DIV_ROUND_UP(CONFIG_BT_MESH_BLOB_SIZE_MAX, \ - CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN)) +#if defined(CONFIG_BLE_MESH_BLOB_SRV) +#define BT_MESH_BLOB_BLOCKS_MAX \ + (DIV_ROUND_UP(CONFIG_BLE_MESH_BLOB_SIZE_MAX, CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MIN)) #else #define BT_MESH_BLOB_BLOCKS_MAX 1 #endif @@ -41,121 +50,121 @@ struct bt_mesh_blob_srv; * @param _srv Pointer to a @ref bt_mesh_blob_srv instance. */ #define BT_MESH_MODEL_BLOB_SRV(_srv) \ - BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_BLOB_SRV, _bt_mesh_blob_srv_op, \ - NULL, _srv, &_bt_mesh_blob_srv_cb) + BLE_MESH_MODEL_CB(BLE_MESH_MODEL_ID_BLOB_SRV, _bt_mesh_blob_srv_op, \ + NULL, _srv, &_bt_mesh_blob_srv_cb) /** @brief BLOB Transfer Server model event handlers. * * All callbacks are optional. */ struct bt_mesh_blob_srv_cb { - /** @brief Transfer start callback. - * - * Called when the transfer has started with the prepared BLOB ID. - * - * @param srv BLOB Transfer Server instance. - * @param ctx Message context for the incoming start message. The - * entire transfer will be sent from the same source - * address. - * @param xfer Transfer parameters. - * - * @return 0 on success, or (negative) error code to reject the - * transfer. - */ - int (*start)(struct bt_mesh_blob_srv *srv, struct bt_mesh_msg_ctx *ctx, - struct bt_mesh_blob_xfer *xfer); + /** @brief Transfer start callback. + * + * Called when the transfer has started with the prepared BLOB ID. + * + * @param srv BLOB Transfer Server instance. + * @param ctx Message context for the incoming start message. The + * entire transfer will be sent from the same source + * address. + * @param xfer Transfer parameters. + * + * @return 0 on success, or (negative) error code to reject the + * transfer. + */ + int (*start)(struct bt_mesh_blob_srv *srv, struct bt_mesh_msg_ctx *ctx, + struct bt_mesh_blob_xfer *xfer); - /** @brief Transfer end callback. - * - * Called when the transfer ends, either because it was cancelled, or - * because it finished successfully. A new transfer may be prepared. - * - * @note The transfer may end before it's started if the start - * parameters are invalid. - * - * @param srv BLOB Transfer Server instance. - * @param id BLOB ID of the cancelled transfer. - * @param success Whether the transfer was successful. - */ - void (*end)(struct bt_mesh_blob_srv *srv, uint64_t id, bool success); + /** @brief Transfer end callback. + * + * Called when the transfer ends, either because it was cancelled, or + * because it finished successfully. A new transfer may be prepared. + * + * @note The transfer may end before it's started if the start + * parameters are invalid. + * + * @param srv BLOB Transfer Server instance. + * @param id BLOB ID of the cancelled transfer. + * @param success Whether the transfer was successful. + */ + void (*end)(struct bt_mesh_blob_srv *srv, uint64_t id, bool success); - /** @brief Transfer suspended callback. - * - * Called if the Server timed out while waiting for a transfer packet. - * A suspended transfer may resume later from the start of the current - * block. Any received chunks in the current block should be discarded, - * they will be received again if the transfer resumes. - * - * The transfer will call @c resumed again when resuming. - * - * @note The BLOB Transfer Server does not run a timer in the suspended state, - * and it's up to the application to determine whether the - * transfer should be permanently cancelled. Without interaction, - * the transfer will be suspended indefinitely, and the BLOB Transfer - * Server will not accept any new transfers. - * - * @param srv BLOB Transfer Server instance. - */ - void (*suspended)(struct bt_mesh_blob_srv *srv); + /** @brief Transfer suspended callback. + * + * Called if the Server timed out while waiting for a transfer packet. + * A suspended transfer may resume later from the start of the current + * block. Any received chunks in the current block should be discarded, + * they will be received again if the transfer resumes. + * + * The transfer will call @c resumed again when resuming. + * + * @note The BLOB Transfer Server does not run a timer in the suspended state, + * and it's up to the application to determine whether the + * transfer should be permanently cancelled. Without interaction, + * the transfer will be suspended indefinitely, and the BLOB Transfer + * Server will not accept any new transfers. + * + * @param srv BLOB Transfer Server instance. + */ + void (*suspended)(struct bt_mesh_blob_srv *srv); - /** @brief Transfer resume callback. - * - * Called if the transfer is resumed after being suspended. - * - * @param srv BLOB Transfer Server instance. - */ - void (*resume)(struct bt_mesh_blob_srv *srv); + /** @brief Transfer resume callback. + * + * Called if the transfer is resumed after being suspended. + * + * @param srv BLOB Transfer Server instance. + */ + void (*resume)(struct bt_mesh_blob_srv *srv); - /** @brief Transfer recovery callback. - * - * Called when the Bluetooth Mesh subsystem is started if the device is rebooted - * in the middle of a transfer. - * - * Transfers will not be resumed after a reboot if this callback is not - * defined. - * - * @param srv BLOB Transfer Server instance. - * @param xfer Transfer to resume. - * @param io BLOB stream return parameter. Must be set to a valid - * BLOB stream by the callback. - * - * @return 0 on success, or (negative) error code to abandon the - * transfer. - */ - int (*recover)(struct bt_mesh_blob_srv *srv, - struct bt_mesh_blob_xfer *xfer, - const struct bt_mesh_blob_io **io); + /** @brief Transfer recovery callback. + * + * Called when the Bluetooth Mesh subsystem is started if the device is rebooted + * in the middle of a transfer. + * + * Transfers will not be resumed after a reboot if this callback is not + * defined. + * + * @param srv BLOB Transfer Server instance. + * @param xfer Transfer to resume. + * @param io BLOB stream return parameter. Must be set to a valid + * BLOB stream by the callback. + * + * @return 0 on success, or (negative) error code to abandon the + * transfer. + */ + int (*recover)(struct bt_mesh_blob_srv *srv, + struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io **io); }; /** @brief BLOB Transfer Server model instance. */ struct bt_mesh_blob_srv { - /** Event handler callbacks. */ - const struct bt_mesh_blob_srv_cb *cb; + /** Event handler callbacks. */ + const struct bt_mesh_blob_srv_cb *cb; - /* Runtime state: */ - const struct bt_mesh_blob_io *io; - struct k_work_delayable rx_timeout; - struct bt_mesh_blob_block block; - const struct bt_mesh_model *mod; - enum bt_mesh_blob_xfer_phase phase; + /* Runtime state: */ + const struct bt_mesh_blob_io *io; + struct k_work_delayable rx_timeout; + struct bt_mesh_blob_block block; + const struct bt_mesh_model *mod; + enum bt_mesh_blob_xfer_phase phase; - struct bt_mesh_blob_srv_state { - struct bt_mesh_blob_xfer xfer; - uint16_t cli; - uint16_t app_idx; - uint16_t timeout_base; - uint16_t mtu_size; - uint8_t ttl; + struct bt_mesh_blob_srv_state { + struct bt_mesh_blob_xfer xfer; + uint16_t cli; + uint16_t app_idx; + uint16_t timeout_base; + uint16_t mtu_size; + uint8_t ttl; - /* Bitfield of pending blocks. */ - ATOMIC_DEFINE(blocks, BT_MESH_BLOB_BLOCKS_MAX); - } state; + /* Bitfield of pending blocks. */ + BLE_MESH_ATOMIC_DEFINE(blocks, BT_MESH_BLOB_BLOCKS_MAX); + } state; - /* Pull mode (Pull BLOB Transfer Mode) behavior. */ - struct { - uint16_t chunk_idx; - struct k_work_delayable report; - } pull; + /* Pull mode (Pull BLOB Transfer Mode) behavior. */ + struct { + uint16_t chunk_idx; + struct k_work_delayable report; + } pull; }; /** @brief Prepare BLOB Transfer Server for an incoming transfer. @@ -174,8 +183,8 @@ struct bt_mesh_blob_srv { * @return 0 on success, or (negative) error code on failure. */ int bt_mesh_blob_srv_recv(struct bt_mesh_blob_srv *srv, uint64_t id, - const struct bt_mesh_blob_io *io, uint8_t ttl, - uint16_t timeout_base); + const struct bt_mesh_blob_io *io, uint8_t ttl, + uint16_t timeout_base); /** @brief Cancel the current BLOB transfer. * @@ -217,4 +226,4 @@ extern const struct bt_mesh_model_cb _bt_mesh_blob_srv_cb; } #endif -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_BLOB_SRV_H_ */ +#endif /* _BLE_MESH_v11_BLOB_SRV_H_ */ diff --git a/components/bt/esp_ble_mesh/v1.1/mbt/blob.h b/components/bt/esp_ble_mesh/v1.1/mbt/blob.h index 162725480e..c539219d9e 100644 --- a/components/bt/esp_ble_mesh/v1.1/mbt/blob.h +++ b/components/bt/esp_ble_mesh/v1.1/mbt/blob.h @@ -1,44 +1,51 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include -#include -#define BT_MESH_BLOB_OP_XFER_GET BT_MESH_MODEL_OP_2(0x83, 0x00) -#define BT_MESH_BLOB_OP_XFER_START BT_MESH_MODEL_OP_2(0x83, 0x01) -#define BT_MESH_BLOB_OP_XFER_CANCEL BT_MESH_MODEL_OP_2(0x83, 0x02) -#define BT_MESH_BLOB_OP_XFER_STATUS BT_MESH_MODEL_OP_2(0x83, 0x03) -#define BT_MESH_BLOB_OP_BLOCK_GET BT_MESH_MODEL_OP_2(0x83, 0x05) -#define BT_MESH_BLOB_OP_BLOCK_START BT_MESH_MODEL_OP_2(0x83, 0x04) -#define BT_MESH_BLOB_OP_CHUNK BT_MESH_MODEL_OP_1(0x66) -#define BT_MESH_BLOB_OP_BLOCK_STATUS BT_MESH_MODEL_OP_1(0x67) -#define BT_MESH_BLOB_OP_BLOCK_REPORT BT_MESH_MODEL_OP_1(0x68) -#define BT_MESH_BLOB_OP_INFO_GET BT_MESH_MODEL_OP_2(0x83, 0x06) -#define BT_MESH_BLOB_OP_INFO_STATUS BT_MESH_MODEL_OP_2(0x83, 0x07) +#if CONFIG_BLE_MESH_BLOB_CLI || CONFIG_BLE_MESH_BLOB_SRV + +#include "mesh/utils.h" +#include "mesh_v1.1/mbt/blob.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" + +#define BT_MESH_BLOB_OP_XFER_GET BLE_MESH_MODEL_OP_2(0x83, 0x00) +#define BT_MESH_BLOB_OP_XFER_START BLE_MESH_MODEL_OP_2(0x83, 0x01) +#define BT_MESH_BLOB_OP_XFER_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x02) +#define BT_MESH_BLOB_OP_XFER_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x03) +#define BT_MESH_BLOB_OP_BLOCK_GET BLE_MESH_MODEL_OP_2(0x83, 0x05) +#define BT_MESH_BLOB_OP_BLOCK_START BLE_MESH_MODEL_OP_2(0x83, 0x04) +#define BT_MESH_BLOB_OP_CHUNK BLE_MESH_MODEL_OP_1(0x66) +#define BT_MESH_BLOB_OP_BLOCK_STATUS BLE_MESH_MODEL_OP_1(0x67) +#define BT_MESH_BLOB_OP_BLOCK_REPORT BLE_MESH_MODEL_OP_1(0x68) +#define BT_MESH_BLOB_OP_INFO_GET BLE_MESH_MODEL_OP_2(0x83, 0x06) +#define BT_MESH_BLOB_OP_INFO_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x07) #define BLOB_BLOCK_NOT_SET 0xffff -#define BLOB_CHUNK_SDU_OVERHEAD \ - (BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK) + 2 + BT_MESH_MIC_SHORT) +#define BLOB_CHUNK_SDU_OVERHEAD \ + (BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK) + 2 + BLE_MESH_MIC_SHORT) #define BLOB_CHUNK_SIZE_MAX(sdu_max) ((sdu_max) - BLOB_CHUNK_SDU_OVERHEAD) #define BLOB_CHUNK_SDU_LEN(chunk_size) (BLOB_CHUNK_SDU_OVERHEAD + (chunk_size)) -#if CONFIG_BT_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT || \ - CONFIG_BT_MESH_RX_BLOB_CHUNK_SIZE > BLOB_CHUNK_SIZE_MAX(BT_MESH_RX_SDU_MAX) -#define BLOB_RX_CHUNK_SIZE BLOB_CHUNK_SIZE_MAX(BT_MESH_RX_SDU_MAX) +#if CONFIG_BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT || \ + CONFIG_BLE_MESH_RX_BLOB_CHUNK_SIZE > BLOB_CHUNK_SIZE_MAX(BLE_MESH_RX_SDU_MAX) +#define BLOB_RX_CHUNK_SIZE BLOB_CHUNK_SIZE_MAX(BLE_MESH_RX_SDU_MAX) #else -#define BLOB_RX_CHUNK_SIZE CONFIG_BT_MESH_RX_BLOB_CHUNK_SIZE +#define BLOB_RX_CHUNK_SIZE CONFIG_BLE_MESH_RX_BLOB_CHUNK_SIZE #endif -#if CONFIG_BT_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT || \ - CONFIG_BT_MESH_TX_BLOB_CHUNK_SIZE > BLOB_CHUNK_SIZE_MAX(BT_MESH_TX_SDU_MAX) -#define BLOB_TX_CHUNK_SIZE BLOB_CHUNK_SIZE_MAX(BT_MESH_TX_SDU_MAX) +#if CONFIG_BLE_MESH_ALIGN_CHUNK_SIZE_TO_MAX_SEGMENT || \ + CONFIG_BLE_MESH_TX_BLOB_CHUNK_SIZE > BLOB_CHUNK_SIZE_MAX(BLE_MESH_TX_SDU_MAX) +#define BLOB_TX_CHUNK_SIZE BLOB_CHUNK_SIZE_MAX(BLE_MESH_TX_SDU_MAX) #else -#define BLOB_TX_CHUNK_SIZE CONFIG_BT_MESH_TX_BLOB_CHUNK_SIZE +#define BLOB_TX_CHUNK_SIZE CONFIG_BLE_MESH_TX_BLOB_CHUNK_SIZE #endif /* Utility macros for calculating log2 of a number at compile time. @@ -57,17 +64,17 @@ #define BLOB_BLOCK_SIZE_LOG_FLOOR(x) (LISTIFY(20, _BLOB_LOG_2_FLOOR, (), x) 20) /* Log2 representation of the minimum block size */ -#define BLOB_BLOCK_SIZE_LOG_MIN BLOB_BLOCK_SIZE_LOG_CEIL(CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN) +#define BLOB_BLOCK_SIZE_LOG_MIN BLOB_BLOCK_SIZE_LOG_CEIL(CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MIN) /* Log2 representation of the maximum block size */ -#define BLOB_BLOCK_SIZE_LOG_MAX BLOB_BLOCK_SIZE_LOG_FLOOR(CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX) +#define BLOB_BLOCK_SIZE_LOG_MAX BLOB_BLOCK_SIZE_LOG_FLOOR(CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MAX) -#if defined(CONFIG_BT_MESH_BLOB_SRV) -#define BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN ( \ - MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \ - CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT * 3)) -#define BLOB_BLOCK_STATUS_MSG_MAXLEN (5 + \ - MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \ - CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT * 3)) +#if defined(CONFIG_BLE_MESH_BLOB_SRV) +#define BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN ( \ + MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \ + CONFIG_BLE_MESH_BLOB_SRV_PULL_REQ_COUNT * 3)) +#define BLOB_BLOCK_STATUS_MSG_MAXLEN (5 + \ + MAX(sizeof(((struct bt_mesh_blob_block *)0)->missing), \ + CONFIG_BLE_MESH_BLOB_SRV_PULL_REQ_COUNT * 3)) #else #define BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN sizeof(((struct bt_mesh_blob_srv *)0)->block.missing) #define BLOB_BLOCK_STATUS_MSG_MAXLEN (5 + sizeof(((struct bt_mesh_blob_srv *)0)->block.missing)) @@ -76,49 +83,50 @@ #define BLOB_XFER_STATUS_MSG_MAXLEN (17 + sizeof(((struct bt_mesh_blob_srv *)0)->state.blocks)) enum bt_mesh_blob_chunks_missing { - BT_MESH_BLOB_CHUNKS_MISSING_ALL, - BT_MESH_BLOB_CHUNKS_MISSING_NONE, - BT_MESH_BLOB_CHUNKS_MISSING_SOME, - BT_MESH_BLOB_CHUNKS_MISSING_ENCODED, + BT_MESH_BLOB_CHUNKS_MISSING_ALL, + BT_MESH_BLOB_CHUNKS_MISSING_NONE, + BT_MESH_BLOB_CHUNKS_MISSING_SOME, + BT_MESH_BLOB_CHUNKS_MISSING_ENCODED, }; static inline size_t blob_block_size(size_t xfer_size, uint8_t block_size_log, - uint32_t idx) + uint32_t idx) { - if (((idx + 1U) << block_size_log) <= xfer_size) { - return (1U << block_size_log); - } + if (((idx + 1U) << block_size_log) <= xfer_size) { + return (1U << block_size_log); + } - return xfer_size & BIT_MASK(block_size_log); + return xfer_size & BIT_MASK(block_size_log); } static inline void blob_chunk_missing_set(uint8_t *missing_chunks, - int idx, bool missing) + int idx, bool missing) { - WRITE_BIT(missing_chunks[idx / 8], idx % 8, missing); + WRITE_BIT(missing_chunks[idx / 8], idx % 8, missing); } static inline bool blob_chunk_missing_get(const uint8_t *missing_chunks, int idx) { - return !!(missing_chunks[idx / 8] & BIT(idx % 8)); + return !!(missing_chunks[idx / 8] & BIT(idx % 8)); } static inline void blob_chunk_missing_set_all(struct bt_mesh_blob_block *block) { - size_t bytes = block->chunk_count / 8; + size_t bytes = block->chunk_count / 8; - memset(block->missing, 0xff, bytes); - if (block->chunk_count % 8) { - block->missing[bytes] = BIT_MASK(block->chunk_count % 8); - } + memset(block->missing, 0xff, bytes); + if (block->chunk_count % 8) { + block->missing[bytes] = BIT_MASK(block->chunk_count % 8); + } } static inline void blob_chunk_missing_set_none(struct bt_mesh_blob_block *block) { - memset(block->missing, 0, sizeof(block->missing)); + memset(block->missing, 0, sizeof(block->missing)); } +#if CONFIG_BLE_MESH_BLOB_CLI /** @brief Perform a message broadcast to all BLOB Transfer Client Target nodes. * * Will send to a group or each Target node individually, repeating until @@ -128,7 +136,7 @@ static inline void blob_chunk_missing_set_none(struct bt_mesh_blob_block *block) * @param ctx Broadcast context */ void blob_cli_broadcast(struct bt_mesh_blob_cli *cli, - const struct blob_cli_broadcast_ctx *ctx); + const struct blob_cli_broadcast_ctx *ctx); /** @brief Register that a Target node responded to a broadcast. * @@ -136,7 +144,7 @@ void blob_cli_broadcast(struct bt_mesh_blob_cli *cli, * @param target Target node that responded. */ void blob_cli_broadcast_rsp(struct bt_mesh_blob_cli *cli, - struct bt_mesh_blob_target *target); + struct bt_mesh_blob_target *target); /** @brief Notify the BLOB Transfer Client that the requested transmission is complete. * @@ -152,3 +160,5 @@ void blob_cli_broadcast_tx_complete(struct bt_mesh_blob_cli *cli); * @param cli BLOB Transfer Client instance. */ void blob_cli_broadcast_abort(struct bt_mesh_blob_cli *cli); +#endif /* CONFIG_BLE_MESH_BLOB_CLI */ +#endif /* CONFIG_BLE_MESH_BLOB_CLI || CONFIG_BLE_MESH_BLOB_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c b/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c index 40d3d37a6c..9132829a23 100644 --- a/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c +++ b/components/bt/esp_ble_mesh/v1.1/mbt/blob_cli.c @@ -1,337 +1,341 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include -#include -#include -#include "mesh.h" + #include "blob.h" #include "net.h" #include "transport.h" +#include "mesh/common.h" +#include "mesh/slist.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" +#include "mesh_v1.1/mbt/blob.h" +#include "mesh/buf.h" -#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL -#include -LOG_MODULE_REGISTER(bt_mesh_blob_cli); +#if CONFIG_BLE_MESH_BLOB_CLI #define TARGETS_FOR_EACH(cli, target) \ - SYS_SLIST_FOR_EACH_CONTAINER((sys_slist_t *)&(cli)->inputs->targets, \ - target, n) + SYS_SLIST_FOR_EACH_CONTAINER((sys_slist_t *)&(cli)->inputs->targets, \ + target, n) /* The Maximum BLOB Poll Interval - T_MBPI */ #define BLOB_POLL_TIME_MAX_SECS 30 #define CLIENT_TIMEOUT_MSEC(cli) (10 * MSEC_PER_SEC * (cli->inputs->timeout_base + 2) + \ - 100 * cli->inputs->ttl) + 100 * cli->inputs->ttl) #define BLOCK_REPORT_TIME_MSEC ((BLOB_POLL_TIME_MAX_SECS * 2 + 7) * 1000) /* BLOB Client is running Send Data State Machine from section 6.2.4.2. */ #define SENDING_CHUNKS_IN_PULL_MODE(cli) ((cli)->state == BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && \ - (cli)->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) -#define UNICAST_MODE(cli) ((cli)->inputs->group == BT_MESH_ADDR_UNASSIGNED || \ - (cli)->tx.ctx.force_unicast) + (cli)->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) +#define UNICAST_MODE(cli) ((cli)->inputs->group == BLE_MESH_ADDR_UNASSIGNED || \ + (cli)->tx.ctx.force_unicast) -BUILD_ASSERT((BLOB_XFER_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_XFER_STATUS) + - BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, - "The BLOB Transfer Status message does not fit into the maximum incoming SDU size."); +_Static_assert((BLOB_XFER_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_XFER_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The BLOB Transfer Status message does not fit into the maximum incoming SDU size."); -BUILD_ASSERT((BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN + - BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_REPORT) + BT_MESH_MIC_SHORT) - <= BT_MESH_RX_SDU_MAX, - "The BLOB Partial Block Report message does not fit into the maximum incoming SDU " - "size."); +_Static_assert((BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN + + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_REPORT) + BLE_MESH_MIC_SHORT) + <= BLE_MESH_RX_SDU_MAX, + "The BLOB Partial Block Report message does not fit into the maximum incoming SDU " + "size."); -BUILD_ASSERT((BLOB_BLOCK_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_STATUS) + - BT_MESH_MIC_SHORT) <= BT_MESH_RX_SDU_MAX, - "The BLOB Block Status message does not fit into the maximum incoming SDU size."); +_Static_assert((BLOB_BLOCK_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, + "The BLOB Block Status message does not fit into the maximum incoming SDU size."); +NET_BUF_SIMPLE_DEFINE_STATIC(chunk_buf, BLE_MESH_TX_SDU_MAX); struct block_status { - enum bt_mesh_blob_status status; - enum bt_mesh_blob_chunks_missing missing; - struct bt_mesh_blob_block block; + enum bt_mesh_blob_status status; + enum bt_mesh_blob_chunks_missing missing; + struct bt_mesh_blob_block block; }; static struct bt_mesh_blob_target *next_target(struct bt_mesh_blob_cli *cli, - struct bt_mesh_blob_target **current); + struct bt_mesh_blob_target **current); static void transfer_cancel(struct bt_mesh_blob_cli *cli); static void start_retry_timer(struct bt_mesh_blob_cli *cli) { - k_timeout_t next_timeout; + k_timeout_t next_timeout; - if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { - int64_t next_timeout_ms = cli->tx.cli_timestamp; - struct bt_mesh_blob_target *target = NULL; + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + int64_t next_timeout_ms = cli->tx.cli_timestamp; + struct bt_mesh_blob_target *target = NULL; - TARGETS_FOR_EACH(cli, target) { - if (!target->procedure_complete && - target->status == BT_MESH_BLOB_SUCCESS && - target->pull->block_report_timestamp < next_timeout_ms) { - next_timeout_ms = target->pull->block_report_timestamp; - } - } + TARGETS_FOR_EACH(cli, target) { + if (!target->procedure_complete && + target->status == BT_MESH_BLOB_SUCCESS && + target->pull->block_report_timestamp < next_timeout_ms) { + next_timeout_ms = target->pull->block_report_timestamp; + } + } - /* cli_timestamp and block_report_timestamp represent absolute time, while - * k_work_* functions use relative time. - */ - next_timeout_ms -= k_uptime_get(); - next_timeout = next_timeout_ms <= 0 ? K_NO_WAIT : K_MSEC(next_timeout_ms); - } else { - next_timeout = K_MSEC(CLIENT_TIMEOUT_MSEC(cli) / - CONFIG_BT_MESH_BLOB_CLI_BLOCK_RETRIES); - } + /* cli_timestamp and block_report_timestamp represent absolute time, while + * k_work_* functions use relative time. + */ + next_timeout_ms -= k_uptime_get(); + next_timeout = next_timeout_ms <= 0 ? K_NO_WAIT : K_MSEC(next_timeout_ms); + } else { + next_timeout = K_MSEC(CLIENT_TIMEOUT_MSEC(cli) / + CONFIG_BLE_MESH_BLOB_CLI_BLOCK_RETRIES); + } - (void)k_work_reschedule(&cli->tx.retry, next_timeout); + (void)k_work_reschedule(&cli->tx.retry, next_timeout); } static void cli_state_reset(struct bt_mesh_blob_cli *cli) { - k_work_cancel_delayable(&cli->tx.retry); - cli->xfer = NULL; - cli->state = BT_MESH_BLOB_CLI_STATE_NONE; - cli->tx.ctx.is_inited = 0; - cli->tx.cli_timestamp = 0ll; - cli->tx.sending = 0; + k_work_cancel_delayable(&cli->tx.retry); + cli->xfer = NULL; + cli->state = BT_MESH_BLOB_CLI_STATE_NONE; + cli->tx.ctx.is_inited = 0; + cli->tx.cli_timestamp = 0ll; + cli->tx.sending = 0; } static struct bt_mesh_blob_target *target_get(struct bt_mesh_blob_cli *cli, - uint16_t addr) + uint16_t addr) { - struct bt_mesh_blob_target *target; + struct bt_mesh_blob_target *target; - TARGETS_FOR_EACH(cli, target) { - if (target->addr == addr) { - return target; - } - } + TARGETS_FOR_EACH(cli, target) { + if (target->addr == addr) { + return target; + } + } - LOG_ERR("Unknown target 0x%04x", addr); - return NULL; + BT_ERR("Unknown target 0x%04x", addr); + return NULL; } static void target_drop(struct bt_mesh_blob_cli *cli, - struct bt_mesh_blob_target *target, - enum bt_mesh_blob_status reason) + struct bt_mesh_blob_target *target, + enum bt_mesh_blob_status reason) { - LOG_WRN("Dropping 0x%04x: %u", target->addr, reason); + BT_WARN("Dropping 0x%04x: %u", target->addr, reason); - target->status = reason; - if (cli->cb && cli->cb->lost_target) { - cli->cb->lost_target(cli, target, reason); - } + target->status = reason; + if (cli->cb && cli->cb->lost_target) { + cli->cb->lost_target(cli, target, reason); + } } static uint32_t targets_reset(struct bt_mesh_blob_cli *cli) { - struct bt_mesh_blob_target *target; - uint32_t count = 0; + struct bt_mesh_blob_target *target; + uint32_t count = 0; - TARGETS_FOR_EACH(cli, target) { - if (target->status == BT_MESH_BLOB_SUCCESS) { - target->acked = 0U; - count++; - } - } + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_BLOB_SUCCESS) { + target->acked = 0U; + count++; + } + } - return count; + return count; } static bool targets_active(struct bt_mesh_blob_cli *cli) { - struct bt_mesh_blob_target *target; + struct bt_mesh_blob_target *target; - TARGETS_FOR_EACH(cli, target) { - if (target->status == BT_MESH_BLOB_SUCCESS) { - return true; - } - } + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_BLOB_SUCCESS) { + return true; + } + } - return false; + return false; } static bool targets_timedout(struct bt_mesh_blob_cli *cli) { - struct bt_mesh_blob_target *target; + struct bt_mesh_blob_target *target; - TARGETS_FOR_EACH(cli, target) { - if (!!target->timedout) { - return true; - } - } + TARGETS_FOR_EACH(cli, target) { + if (!!target->timedout) { + return true; + } + } - return false; + return false; } static int io_open(struct bt_mesh_blob_cli *cli) { - if (!cli->io->open) { - return 0; - } + if (!cli->io->open) { + return 0; + } - return cli->io->open(cli->io, cli->xfer, BT_MESH_BLOB_READ); + return cli->io->open(cli->io, cli->xfer, BT_MESH_BLOB_READ); } static void io_close(struct bt_mesh_blob_cli *cli) { - if (!cli->io->close) { - return; - } + if (!cli->io->close) { + return; + } - cli->io->close(cli->io, cli->xfer); + cli->io->close(cli->io, cli->xfer); } static uint16_t next_missing_chunk(struct bt_mesh_blob_cli *cli, - const uint8_t *missing_chunks, - uint16_t idx) + const uint8_t *missing_chunks, + uint16_t idx) { - do { - if (blob_chunk_missing_get(missing_chunks, idx)) { - break; - } - } while (++idx < cli->block.chunk_count); + do { + if (blob_chunk_missing_get(missing_chunks, idx)) { + break; + } + } while (++idx < cli->block.chunk_count); - return idx; + return idx; } /* Used in Pull mode to collect all missing chunks from each target in cli->block.missing. */ static void update_missing_chunks(struct bt_mesh_blob_cli *cli) { - struct bt_mesh_blob_target *target; + struct bt_mesh_blob_target *target; - memset(cli->block.missing, 0, sizeof(cli->block.missing)); + memset(cli->block.missing, 0, sizeof(cli->block.missing)); - TARGETS_FOR_EACH(cli, target) { - if (target->procedure_complete || target->timedout) { - continue; - } + TARGETS_FOR_EACH(cli, target) { + if (target->procedure_complete || target->timedout) { + continue; + } - for (size_t idx = 0; idx < cli->block.chunk_count; idx++) { - bool missing = blob_chunk_missing_get(cli->block.missing, idx) || - blob_chunk_missing_get(target->pull->missing, idx); - blob_chunk_missing_set(cli->block.missing, idx, missing); - } - } + for (size_t idx = 0; idx < cli->block.chunk_count; idx++) { + bool missing = blob_chunk_missing_get(cli->block.missing, idx) || + blob_chunk_missing_get(target->pull->missing, idx); + blob_chunk_missing_set(cli->block.missing, idx, missing); + } + } } static inline size_t chunk_size(const struct bt_mesh_blob_xfer *xfer, - const struct bt_mesh_blob_block *block, - uint16_t chunk_idx) + const struct bt_mesh_blob_block *block, + uint16_t chunk_idx) { - if ((chunk_idx == block->chunk_count - 1) && - (block->size % xfer->chunk_size)) { - return block->size % xfer->chunk_size; - } + if ((chunk_idx == block->chunk_count - 1) && + (block->size % xfer->chunk_size)) { + return block->size % xfer->chunk_size; + } - return xfer->chunk_size; + return xfer->chunk_size; } static int chunk_idx_decode(struct net_buf_simple *buf) { - uint16_t data; - uint8_t byte; + uint16_t data; + uint8_t byte; - if (buf->len == 0) { - return -EINVAL; - } + if (buf->len == 0) { + return -EINVAL; + } - byte = net_buf_simple_pull_u8(buf); + byte = net_buf_simple_pull_u8(buf); - /* utf-8 decoding */ - if ((byte & 0xf0) == 0xe0) { /* 0x800 - 0xffff */ - if (buf->len < 2) { - return -EINVAL; - } + /* utf-8 decoding */ + if ((byte & 0xf0) == 0xe0) { /* 0x800 - 0xffff */ + if (buf->len < 2) { + return -EINVAL; + } - data = (byte & 0x0f) << 12; - data |= (net_buf_simple_pull_u8(buf) & 0x3f) << 6; - data |= (net_buf_simple_pull_u8(buf) & 0x3f); - } else if ((byte & 0xe0) == 0xc0) { /* 0x80 - 0x7ff */ - if (buf->len < 1) { - return -EINVAL; - } + data = (byte & 0x0f) << 12; + data |= (net_buf_simple_pull_u8(buf) & 0x3f) << 6; + data |= (net_buf_simple_pull_u8(buf) & 0x3f); + } else if ((byte & 0xe0) == 0xc0) { /* 0x80 - 0x7ff */ + if (buf->len < 1) { + return -EINVAL; + } - data = (byte & 0x1f) << 6; - data |= (net_buf_simple_pull_u8(buf) & 0x3f); - } else { /* 0x00 - 0x7f */ - data = byte & 0x7f; - } + data = (byte & 0x1f) << 6; + data |= (net_buf_simple_pull_u8(buf) & 0x3f); + } else { /* 0x00 - 0x7f */ + data = byte & 0x7f; + } - return data; + return data; } static void block_set(struct bt_mesh_blob_cli *cli, uint16_t block_idx) { - cli->block.number = block_idx; - cli->block.offset = block_idx * (1UL << cli->xfer->block_size_log); - cli->block.size = blob_block_size(cli->xfer->size, cli->xfer->block_size_log, - block_idx); - cli->block.chunk_count = - DIV_ROUND_UP(cli->block.size, cli->xfer->chunk_size); + cli->block.number = block_idx; + cli->block.offset = block_idx * (1UL << cli->xfer->block_size_log); + cli->block.size = blob_block_size(cli->xfer->size, cli->xfer->block_size_log, + block_idx); + cli->block.chunk_count = + DIV_ROUND_UP(cli->block.size, cli->xfer->chunk_size); - if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { - blob_chunk_missing_set_all(&cli->block); - } else { - struct bt_mesh_blob_target *target; + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + blob_chunk_missing_set_all(&cli->block); + } else { + struct bt_mesh_blob_target *target; - /* In pull mode, the server will tell us which blocks are missing. */ - memset(cli->block.missing, 0, sizeof(cli->block.missing)); + /* In pull mode, the server will tell us which blocks are missing. */ + memset(cli->block.missing, 0, sizeof(cli->block.missing)); - TARGETS_FOR_EACH(cli, target) { - memset(target->pull->missing, 0, sizeof(target->pull->missing)); - } - } + TARGETS_FOR_EACH(cli, target) { + memset(target->pull->missing, 0, sizeof(target->pull->missing)); + } + } - LOG_DBG("%u size: %u chunks: %u", block_idx, cli->block.size, - cli->block.chunk_count); + BT_DBG("%u size: %u chunks: %u", block_idx, cli->block.size, + cli->block.chunk_count); } static void suspend(struct bt_mesh_blob_cli *cli) { - cli->state = BT_MESH_BLOB_CLI_STATE_SUSPENDED; + cli->state = BT_MESH_BLOB_CLI_STATE_SUSPENDED; - if (cli->cb && cli->cb->suspended) { - cli->cb->suspended(cli); - } + if (cli->cb && cli->cb->suspended) { + cli->cb->suspended(cli); + } } static void end(struct bt_mesh_blob_cli *cli, bool success) { - const struct bt_mesh_blob_xfer *xfer = cli->xfer; + const struct bt_mesh_blob_xfer *xfer = cli->xfer; - LOG_DBG("%u", success); + BT_DBG("%u", success); - io_close(cli); - cli_state_reset(cli); - if (cli->cb && cli->cb->end) { - cli->cb->end(cli, xfer, success); - } + io_close(cli); + cli_state_reset(cli); + if (cli->cb && cli->cb->end) { + cli->cb->end(cli, xfer, success); + } } static enum bt_mesh_blob_status caps_adjust(struct bt_mesh_blob_cli *cli, - const struct bt_mesh_blob_cli_caps *in) + const struct bt_mesh_blob_cli_caps *in) { - if (!(in->modes & cli->caps.modes)) { - return BT_MESH_BLOB_ERR_UNSUPPORTED_MODE; - } + if (!(in->modes & cli->caps.modes)) { + return BT_MESH_BLOB_ERR_UNSUPPORTED_MODE; + } - if ((in->min_block_size_log > cli->caps.max_block_size_log) || - (in->max_block_size_log < cli->caps.min_block_size_log)) { - return BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE; - } + if ((in->min_block_size_log > cli->caps.max_block_size_log) || + (in->max_block_size_log < cli->caps.min_block_size_log)) { + return BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE; + } - cli->caps.min_block_size_log = - MAX(cli->caps.min_block_size_log, in->min_block_size_log); - cli->caps.max_block_size_log = - MIN(cli->caps.max_block_size_log, in->max_block_size_log); - cli->caps.max_chunks = MIN(cli->caps.max_chunks, in->max_chunks); - cli->caps.mtu_size = MIN(cli->caps.mtu_size, in->mtu_size); - cli->caps.max_chunk_size = MIN(cli->caps.max_chunk_size, in->max_chunk_size); - cli->caps.modes &= in->modes; - cli->caps.max_size = MIN(cli->caps.max_size, in->max_size); + cli->caps.min_block_size_log = + MAX(cli->caps.min_block_size_log, in->min_block_size_log); + cli->caps.max_block_size_log = + MIN(cli->caps.max_block_size_log, in->max_block_size_log); + cli->caps.max_chunks = MIN(cli->caps.max_chunks, in->max_chunks); + cli->caps.mtu_size = MIN(cli->caps.mtu_size, in->mtu_size); + cli->caps.max_chunk_size = MIN(cli->caps.max_chunk_size, in->max_chunk_size); + cli->caps.modes &= in->modes; + cli->caps.max_size = MIN(cli->caps.max_size, in->max_size); - return BT_MESH_BLOB_SUCCESS; + return BT_MESH_BLOB_SUCCESS; } /******************************************************************************* @@ -346,276 +350,276 @@ static enum bt_mesh_blob_status caps_adjust(struct bt_mesh_blob_cli *cli, ******************************************************************************/ static struct bt_mesh_blob_target *next_target(struct bt_mesh_blob_cli *cli, - struct bt_mesh_blob_target **current) + struct bt_mesh_blob_target **current) { - if (*current) { - *current = SYS_SLIST_PEEK_NEXT_CONTAINER(*current, n); - } else { - *current = SYS_SLIST_PEEK_HEAD_CONTAINER( - (sys_slist_t *)&cli->inputs->targets, *current, n); - } + if (*current) { + *current = SYS_SLIST_PEEK_NEXT_CONTAINER(*current, n); + } else { + *current = SYS_SLIST_PEEK_HEAD_CONTAINER( + (sys_slist_t *)&cli->inputs->targets, *current, n); + } - while (*current) { - if ((*current)->acked || (*current)->procedure_complete || - (*current)->status != BT_MESH_BLOB_SUCCESS || (*current)->timedout || - (*current)->skip) { - goto next; - } + while (*current) { + if ((*current)->acked || (*current)->procedure_complete || + (*current)->status != BT_MESH_BLOB_SUCCESS || (*current)->timedout || + (*current)->skip) { + goto next; + } - if (SENDING_CHUNKS_IN_PULL_MODE(cli) && - (k_uptime_get() < (*current)->pull->block_report_timestamp || - !blob_chunk_missing_get((*current)->pull->missing, cli->chunk_idx))) { - /* Skip targets that didn't time out or timed out, but confirmed - * the currently transmitted chunk (cli->chunk_idx). - */ - goto next; - } + if (SENDING_CHUNKS_IN_PULL_MODE(cli) && + (k_uptime_get() < (*current)->pull->block_report_timestamp || + !blob_chunk_missing_get((*current)->pull->missing, cli->chunk_idx))) { + /* Skip targets that didn't time out or timed out, but confirmed + * the currently transmitted chunk (cli->chunk_idx). + */ + goto next; + } - break; + break; next: - *current = SYS_SLIST_PEEK_NEXT_CONTAINER(*current, n); - } + *current = SYS_SLIST_PEEK_NEXT_CONTAINER(*current, n); + } - return *current; + return *current; } static void send(struct bt_mesh_blob_cli *cli) { - cli->tx.sending = 1U; - if (UNICAST_MODE(cli)) { - cli->tx.ctx.send(cli, cli->tx.target->addr); - } else { - cli->tx.ctx.send(cli, cli->inputs->group); - } + cli->tx.sending = 1U; + if (UNICAST_MODE(cli)) { + cli->tx.ctx.send(cli, cli->tx.target->addr); + } else { + cli->tx.ctx.send(cli, cli->inputs->group); + } } static void broadcast_complete(struct bt_mesh_blob_cli *cli) { - LOG_DBG("%s", cli->tx.cancelled ? "cancelling" : "continuing"); + BT_DBG("%s", cli->tx.cancelled ? "cancelling" : "continuing"); - cli->tx.ctx.is_inited = 0; - k_work_cancel_delayable(&cli->tx.retry); + cli->tx.ctx.is_inited = 0; + k_work_cancel_delayable(&cli->tx.retry); - if (cli->tx.cancelled) { - transfer_cancel(cli); - } else { - __ASSERT(cli->tx.ctx.next, "No next callback"); - cli->tx.ctx.next(cli); - } + if (cli->tx.cancelled) { + transfer_cancel(cli); + } else { + __ASSERT(cli->tx.ctx.next, "No next callback"); + cli->tx.ctx.next(cli); + } } static void tx_complete(struct k_work *work) { - struct k_work_delayable *dwork = k_work_delayable_from_work(work); - struct bt_mesh_blob_cli *cli = CONTAINER_OF(dwork, struct bt_mesh_blob_cli, tx.complete); + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct bt_mesh_blob_cli *cli = CONTAINER_OF(dwork, struct bt_mesh_blob_cli, tx.complete); - if (!cli->tx.ctx.is_inited || !cli->tx.sending) { - return; - } + if (!cli->tx.ctx.is_inited || !cli->tx.sending) { + return; + } - cli->tx.sending = 0U; + cli->tx.sending = 0U; - if (cli->tx.cancelled) { - broadcast_complete(cli); - return; - } + if (cli->tx.cancelled) { + broadcast_complete(cli); + return; + } - if (cli->tx.ctx.send_complete) { - cli->tx.ctx.send_complete(cli, cli->tx.target->addr); - } + if (cli->tx.ctx.send_complete) { + cli->tx.ctx.send_complete(cli, cli->tx.target->addr); + } - if (UNICAST_MODE(cli) && next_target(cli, &cli->tx.target)) { - send(cli); - return; - } + if (UNICAST_MODE(cli) && next_target(cli, &cli->tx.target)) { + send(cli); + return; + } - if (cli->tx.ctx.acked && cli->tx.pending) { - start_retry_timer(cli); - return; - } + if (cli->tx.ctx.acked && cli->tx.pending) { + start_retry_timer(cli); + return; + } - broadcast_complete(cli); + broadcast_complete(cli); } static void drop_remaining_targets(struct bt_mesh_blob_cli *cli) { - struct bt_mesh_blob_target *target; + struct bt_mesh_blob_target *target; - LOG_DBG(""); + BT_DBG(""); - cli->tx.pending = 0; + cli->tx.pending = 0; - TARGETS_FOR_EACH(cli, target) { - if (!target->acked && !target->timedout && !target->procedure_complete && - !target->skip) { - target->timedout = 1U; - target_drop(cli, target, BT_MESH_BLOB_ERR_INTERNAL); - } - } + TARGETS_FOR_EACH(cli, target) { + if (!target->acked && !target->timedout && !target->procedure_complete && + !target->skip) { + target->timedout = 1U; + target_drop(cli, target, BT_MESH_BLOB_ERR_INTERNAL); + } + } - /* Update missing chunks to exclude chunks from dropped targets. */ - if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { - update_missing_chunks(cli); - } + /* Update missing chunks to exclude chunks from dropped targets. */ + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + update_missing_chunks(cli); + } } static void retry_timeout(struct k_work *work) { - struct bt_mesh_blob_cli *cli = - CONTAINER_OF(work, struct bt_mesh_blob_cli, tx.retry.work); + struct bt_mesh_blob_cli *cli = + CONTAINER_OF(work, struct bt_mesh_blob_cli, tx.retry.work); - /* When sending chunks in Pull mode, timeout is handled differently. Client will drop all - * non-responsive servers by cli_timestamp. By calling broadcast_complete(), client will - * either retransmit the missing chunks (if any), or proceed to the next block, or suspend - * the transfer if all targets timed out. All this is handled in block_check_end(). - * Retry logic for all other procedures in Pull mode is handled as in Push mode. - */ - if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { - if (k_uptime_get() >= cli->tx.cli_timestamp) { - LOG_DBG("Transfer timed out."); + /* When sending chunks in Pull mode, timeout is handled differently. Client will drop all + * non-responsive servers by cli_timestamp. By calling broadcast_complete(), client will + * either retransmit the missing chunks (if any), or proceed to the next block, or suspend + * the transfer if all targets timed out. All this is handled in block_check_end(). + * Retry logic for all other procedures in Pull mode is handled as in Push mode. + */ + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + if (k_uptime_get() >= cli->tx.cli_timestamp) { + BT_DBG("Transfer timed out."); - if (!cli->tx.ctx.optional) { - drop_remaining_targets(cli); - } - } + if (!cli->tx.ctx.optional) { + drop_remaining_targets(cli); + } + } - broadcast_complete(cli); - return; - } + broadcast_complete(cli); + return; + } - LOG_DBG("%u", cli->tx.retries); + BT_DBG("%u", cli->tx.retries); - cli->tx.retries--; - cli->tx.target = NULL; + cli->tx.retries--; + cli->tx.target = NULL; - __ASSERT(!cli->tx.sending, "still sending"); - __ASSERT(cli->tx.ctx.is_inited, "ctx is not initialized"); + __ASSERT(!cli->tx.sending, "still sending"); + __ASSERT(cli->tx.ctx.is_inited, "ctx is not initialized"); - if (!cli->tx.retries) { - LOG_DBG("Transfer timed out."); + if (!cli->tx.retries) { + BT_DBG("Transfer timed out."); - if (!cli->tx.ctx.optional) { - drop_remaining_targets(cli); - } + if (!cli->tx.ctx.optional) { + drop_remaining_targets(cli); + } - broadcast_complete(cli); - return; - } + broadcast_complete(cli); + return; + } - if (!cli->tx.ctx.acked || !next_target(cli, &cli->tx.target) || cli->tx.cancelled) { - broadcast_complete(cli); - return; - } + if (!cli->tx.ctx.acked || !next_target(cli, &cli->tx.target) || cli->tx.cancelled) { + broadcast_complete(cli); + return; + } - send(cli); + send(cli); } void blob_cli_broadcast(struct bt_mesh_blob_cli *cli, - const struct blob_cli_broadcast_ctx *ctx) + const struct blob_cli_broadcast_ctx *ctx) { - if (cli->tx.ctx.is_inited || cli->tx.sending) { - LOG_ERR("BLOB cli busy"); - return; - } + if (cli->tx.ctx.is_inited || cli->tx.sending) { + BT_ERR("BLOB cli busy"); + return; + } - cli->tx.cancelled = 0U; - cli->tx.retries = CONFIG_BT_MESH_BLOB_CLI_BLOCK_RETRIES; - cli->tx.ctx = *ctx; - cli->tx.ctx.is_inited = 1U; + cli->tx.cancelled = 0U; + cli->tx.retries = CONFIG_BLE_MESH_BLOB_CLI_BLOCK_RETRIES; + cli->tx.ctx = *ctx; + cli->tx.ctx.is_inited = 1U; - cli->tx.pending = targets_reset(cli); + cli->tx.pending = targets_reset(cli); - LOG_DBG("%u targets", cli->tx.pending); + BT_DBG("%u targets", cli->tx.pending); - cli->tx.target = NULL; - if (!next_target(cli, &cli->tx.target)) { - LOG_DBG("No active targets"); - broadcast_complete(cli); - return; - } + cli->tx.target = NULL; + if (!next_target(cli, &cli->tx.target)) { + BT_DBG("No active targets"); + broadcast_complete(cli); + return; + } - send(cli); + send(cli); } void blob_cli_broadcast_tx_complete(struct bt_mesh_blob_cli *cli) { - k_work_schedule(&cli->tx.complete, K_MSEC(cli->tx.ctx.post_send_delay_ms)); + k_work_schedule(&cli->tx.complete, K_MSEC(cli->tx.ctx.post_send_delay_ms)); } void blob_cli_broadcast_rsp(struct bt_mesh_blob_cli *cli, - struct bt_mesh_blob_target *target) + struct bt_mesh_blob_target *target) { - if (target->acked) { - return; - } + if (target->acked) { + return; + } - LOG_DBG("0x%04x, pending: %d", target->addr, cli->tx.pending); + BT_DBG("0x%04x, pending: %d", target->addr, cli->tx.pending); - target->acked = 1U; + target->acked = 1U; - if (!--cli->tx.pending && !cli->tx.sending) { - broadcast_complete(cli); - } + if (!--cli->tx.pending && !cli->tx.sending) { + broadcast_complete(cli); + } } void blob_cli_broadcast_abort(struct bt_mesh_blob_cli *cli) { - if (!cli->tx.ctx.is_inited) { - return; - } + if (!cli->tx.ctx.is_inited) { + return; + } - if ((cli)->state >= BT_MESH_BLOB_CLI_STATE_START) { - io_close(cli); - } + if ((cli)->state >= BT_MESH_BLOB_CLI_STATE_START) { + io_close(cli); + } - cli_state_reset(cli); + cli_state_reset(cli); } static void send_start(uint16_t duration, int err, void *cb_data); static void send_end(int err, void *user_data); static int tx(struct bt_mesh_blob_cli *cli, uint16_t addr, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - static const struct bt_mesh_send_cb end_cb = { - .start = send_start, - .end = send_end, - }; - struct bt_mesh_msg_ctx ctx = { - .app_idx = cli->inputs->app_idx, - .addr = addr, - .send_ttl = cli->inputs->ttl, - }; - int err; + static const struct bt_mesh_send_cb end_cb = { + .start = send_start, + .end = send_end, + }; + struct bt_mesh_msg_ctx ctx = { + .app_idx = cli->inputs->app_idx, + .addr = addr, + .send_ttl = cli->inputs->ttl, + }; + int err; - err = bt_mesh_model_send(cli->mod, &ctx, buf, &end_cb, cli); - if (err) { - LOG_ERR("Send err: %d", err); - send_end(err, cli); - return err; - } + err = bt_mesh_model_send((struct bt_mesh_model *)cli->mod, &ctx, buf, &end_cb, cli); + if (err) { + BT_ERR("Send err: %d", err); + send_end(err, cli); + return err; + } - return 0; + return 0; } static void send_start(uint16_t duration, int err, void *cb_data) { - if (err) { - LOG_ERR("TX Start failed: %d", err); - send_end(err, cb_data); - } + if (err) { + BT_ERR("TX Start failed: %d", err); + send_end(err, cb_data); + } } static void send_end(int err, void *user_data) { - struct bt_mesh_blob_cli *cli = user_data; + struct bt_mesh_blob_cli *cli = user_data; - if (!cli->tx.ctx.is_inited) { - return; - } + if (!cli->tx.ctx.is_inited) { + return; + } - blob_cli_broadcast_tx_complete(cli); + blob_cli_broadcast_tx_complete(cli); } /******************************************************************************* @@ -624,80 +628,83 @@ static void send_end(int err, void *user_data) static void info_get_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_INFO_GET, 0); - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_INFO_GET); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_INFO_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_INFO_GET); - tx(cli, dst, &buf); + tx(cli, dst, &buf); } static void xfer_start_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_START, 16); - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_START); - net_buf_simple_add_u8(&buf, cli->xfer->mode << 6); - net_buf_simple_add_le64(&buf, cli->xfer->id); - net_buf_simple_add_le32(&buf, cli->xfer->size); - net_buf_simple_add_u8(&buf, cli->xfer->block_size_log); - net_buf_simple_add_le16(&buf, BT_MESH_TX_SDU_MAX); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_START, 16); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_START); + net_buf_simple_add_u8(&buf, cli->xfer->mode << 6); + net_buf_simple_add_le64(&buf, cli->xfer->id); + net_buf_simple_add_le32(&buf, cli->xfer->size); + net_buf_simple_add_u8(&buf, cli->xfer->block_size_log); + net_buf_simple_add_le16(&buf, BLE_MESH_TX_SDU_MAX); - tx(cli, dst, &buf); + tx(cli, dst, &buf); } static void xfer_get_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_GET, 0); - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_GET); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_GET); - tx(cli, dst, &buf); + tx(cli, dst, &buf); } static void xfer_cancel_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_CANCEL, 8); - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_CANCEL); - net_buf_simple_add_le64(&buf, cli->xfer->id); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_CANCEL, 8); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_CANCEL); + net_buf_simple_add_le64(&buf, cli->xfer->id); - tx(cli, dst, &buf); + tx(cli, dst, &buf); } static void block_start_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_START, 4); - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_START); - net_buf_simple_add_le16(&buf, cli->block.number); - net_buf_simple_add_le16(&buf, cli->xfer->chunk_size); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_START, 4); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_START); + net_buf_simple_add_le16(&buf, cli->block.number); + net_buf_simple_add_le16(&buf, cli->xfer->chunk_size); - tx(cli, dst, &buf); + tx(cli, dst, &buf); } static void chunk_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) { - NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_TX_SDU_MAX); - struct bt_mesh_blob_chunk chunk; - int err; + struct bt_mesh_blob_chunk chunk; + int err; - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_CHUNK); - net_buf_simple_add_le16(&buf, cli->chunk_idx); + BT_DBG("Chunk will send to 0x%04x", dst); - chunk.size = chunk_size(cli->xfer, &cli->block, cli->chunk_idx); - chunk.offset = cli->xfer->chunk_size * cli->chunk_idx; - chunk.data = net_buf_simple_add(&buf, chunk.size); + /* Changed by Espressif: + * Use static chunk buf to avoid taking up large stack space */ + bt_mesh_model_msg_init(&chunk_buf, BT_MESH_BLOB_OP_CHUNK); + net_buf_simple_add_le16(&chunk_buf, cli->chunk_idx); - err = cli->io->rd(cli->io, cli->xfer, &cli->block, &chunk); - if (err || cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { - bt_mesh_blob_cli_cancel(cli); - return; - } + chunk.size = chunk_size(cli->xfer, &cli->block, cli->chunk_idx); + chunk.offset = cli->xfer->chunk_size * cli->chunk_idx; + chunk.data = net_buf_simple_add(&chunk_buf, chunk.size); - tx(cli, dst, &buf); + err = cli->io->rd(cli->io, cli->xfer, &cli->block, &chunk); + if (err || cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { + bt_mesh_blob_cli_cancel(cli); + return; + } + + tx(cli, dst, &chunk_buf); } static void block_get_tx(struct bt_mesh_blob_cli *cli, uint16_t dst) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_GET, 0); - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_GET); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_GET, 0); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_GET); - tx(cli, dst, &buf); + tx(cli, dst, &buf); } /************************************************************************************************** @@ -786,197 +793,199 @@ static void transfer_complete(struct bt_mesh_blob_cli *cli); static void caps_get(struct bt_mesh_blob_cli *cli) { - const struct blob_cli_broadcast_ctx ctx = { - .send = info_get_tx, - .next = caps_collected, - .acked = true, - }; + const struct blob_cli_broadcast_ctx ctx = { + .send = info_get_tx, + .next = caps_collected, + .acked = true, + }; - cli->state = BT_MESH_BLOB_CLI_STATE_CAPS_GET; - blob_cli_broadcast(cli, &ctx); + cli->state = BT_MESH_BLOB_CLI_STATE_CAPS_GET; + blob_cli_broadcast(cli, &ctx); } static void caps_collected(struct bt_mesh_blob_cli *cli) { - struct bt_mesh_blob_target *target; - bool success = false; + struct bt_mesh_blob_target *target; + bool success = false; - cli->state = BT_MESH_BLOB_CLI_STATE_NONE; + cli->state = BT_MESH_BLOB_CLI_STATE_NONE; - cli_state_reset(cli); + cli_state_reset(cli); - TARGETS_FOR_EACH(cli, target) { - if (target->status == BT_MESH_BLOB_SUCCESS) { - success = true; - break; - } - } + TARGETS_FOR_EACH(cli, target) { + if (target->status == BT_MESH_BLOB_SUCCESS) { + success = true; + break; + } + } - while (success && - (1UL << cli->caps.max_block_size_log) > - (cli->caps.max_chunk_size * cli->caps.max_chunks)) { - cli->caps.max_block_size_log--; - } + while (success && + (1UL << cli->caps.max_block_size_log) > + (cli->caps.max_chunk_size * cli->caps.max_chunks)) { + cli->caps.max_block_size_log--; + } - if (cli->cb && cli->cb->caps) { - cli->cb->caps(cli, success ? &cli->caps : NULL); - } + if (cli->cb && cli->cb->caps) { + cli->cb->caps(cli, success ? &cli->caps : NULL); + } } static int xfer_start(struct bt_mesh_blob_cli *cli) { - const struct blob_cli_broadcast_ctx ctx = { - .send = xfer_start_tx, - .next = block_start, - .acked = true, - }; - int err; + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_start_tx, + .next = block_start, + .acked = true, + }; + int err; - err = io_open(cli); - if (err) { - return -EIO; - } + err = io_open(cli); + if (err) { + return -EIO; + } - cli->state = BT_MESH_BLOB_CLI_STATE_START; + cli->state = BT_MESH_BLOB_CLI_STATE_START; - blob_cli_broadcast(cli, &ctx); - return 0; + blob_cli_broadcast(cli, &ctx); + return 0; } static void block_start(struct bt_mesh_blob_cli *cli) { - const struct blob_cli_broadcast_ctx ctx = { - .send = block_start_tx, - .next = chunk_send, - .acked = true, - }; - struct bt_mesh_blob_target *target; + const struct blob_cli_broadcast_ctx ctx = { + .send = block_start_tx, + .next = chunk_send, + .acked = true, + }; + struct bt_mesh_blob_target *target; + if (!targets_active(cli)) { + if (targets_timedout(cli)) { + suspend(cli); + return; + } - if (!targets_active(cli)) { - if (targets_timedout(cli)) { - suspend(cli); - return; - } + end(cli, false); + return; + } - end(cli, false); - return; - } + BT_DBG("%u (%u chunks, %u/%u)", cli->block.number, + cli->block.chunk_count, cli->block.number + 1, cli->block_count); - LOG_DBG("%u (%u chunks, %u/%u)", cli->block.number, - cli->block.chunk_count, cli->block.number + 1, cli->block_count); + cli->chunk_idx = 0; + cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_START; + /* Client Timeout Timer in Send Data State Machine is initialized initially after + * transmitting the first bunch of chunks (see block_report_wait()). Next time it will be + * updated after every Partial Block Report message. + */ + cli->tx.cli_timestamp = 0ll; - cli->chunk_idx = 0; - cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_START; - /* Client Timeout Timer in Send Data State Machine is initialized initially after - * transmitting the first bunch of chunks (see block_report_wait()). Next time it will be - * updated after every Partial Block Report message. - */ - cli->tx.cli_timestamp = 0ll; + TARGETS_FOR_EACH(cli, target) { + target->procedure_complete = 0U; - TARGETS_FOR_EACH(cli, target) { - target->procedure_complete = 0U; + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + target->pull->block_report_timestamp = 0ll; + } + } - if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { - target->pull->block_report_timestamp = 0ll; - } - } + if (cli->io->block_start) { + cli->io->block_start(cli->io, cli->xfer, &cli->block); + if (cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { + return; + } + } - if (cli->io->block_start) { - cli->io->block_start(cli->io, cli->xfer, &cli->block); - if (cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { - return; - } - } - - blob_cli_broadcast(cli, &ctx); + blob_cli_broadcast(cli, &ctx); } static void chunk_tx_complete(struct bt_mesh_blob_cli *cli, uint16_t dst) { - if (cli->xfer->mode != BT_MESH_BLOB_XFER_MODE_PULL) { - return; - } + if (cli->xfer->mode != BT_MESH_BLOB_XFER_MODE_PULL) { + return; + } - /* Update Block Report Timer individually for each target after sending out the last chunk - * in current iteration. - */ - uint16_t chunk_idx = next_missing_chunk(cli, cli->tx.target->pull->missing, - cli->chunk_idx + 1); - if (chunk_idx < cli->block.chunk_count) { - /* Will send more chunks to this target in this iteration. */ - return; - } + /* Update Block Report Timer individually for each target after sending out the last chunk + * in current iteration. + */ + uint16_t chunk_idx = next_missing_chunk(cli, cli->tx.target->pull->missing, + cli->chunk_idx + 1); + if (chunk_idx < cli->block.chunk_count) { + /* Will send more chunks to this target in this iteration. */ + return; + } - /* This was the last chunk sent for this target. Now start the Block Report Timeout Timer. - */ - struct bt_mesh_blob_target *target; - int64_t timestamp = k_uptime_get() + BLOCK_REPORT_TIME_MSEC; + /* This was the last chunk sent for this target. Now start the Block Report Timeout Timer. + */ + struct bt_mesh_blob_target *target; + int64_t timestamp = k_uptime_get() + BLOCK_REPORT_TIME_MSEC; - if (!UNICAST_MODE(cli)) { - /* If using group addressing, reset timestamp for all targets after all chunks are - * sent to the group address - */ - TARGETS_FOR_EACH(cli, target) { - target->pull->block_report_timestamp = timestamp; - } - return; - } + if (!UNICAST_MODE(cli)) { + /* If using group addressing, reset timestamp for all targets after all chunks are + * sent to the group address + */ + TARGETS_FOR_EACH(cli, target) { + target->pull->block_report_timestamp = timestamp; + } + return; + } - cli->tx.target->pull->block_report_timestamp = timestamp; + cli->tx.target->pull->block_report_timestamp = timestamp; } static void chunk_send(struct bt_mesh_blob_cli *cli) { - struct blob_cli_broadcast_ctx ctx = { - .send = chunk_tx, - .next = chunk_send_end, - .acked = false, - .post_send_delay_ms = cli->chunk_interval_ms, - }; + struct blob_cli_broadcast_ctx ctx = { + .send = chunk_tx, + .next = chunk_send_end, + .acked = false, + .post_send_delay_ms = cli->chunk_interval_ms, + }; - if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { - ctx.send_complete = chunk_tx_complete; - } + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + ctx.send_complete = chunk_tx_complete; + } - if (!targets_active(cli)) { - if (targets_timedout(cli)) { - suspend(cli); - return; - } + if (!targets_active(cli)) { + if (targets_timedout(cli)) { + suspend(cli); + return; + } - end(cli, false); - return; - } + end(cli, false); + return; + } - LOG_DBG("%u / %u size: %u", cli->chunk_idx + 1, cli->block.chunk_count, - chunk_size(cli->xfer, &cli->block, cli->chunk_idx)); + BT_DBG("%u / %u size: %u", cli->chunk_idx + 1, cli->block.chunk_count, + chunk_size(cli->xfer, &cli->block, cli->chunk_idx)); - cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_SEND; - blob_cli_broadcast(cli, &ctx); + cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_SEND; + blob_cli_broadcast(cli, &ctx); } static void chunk_send_end(struct bt_mesh_blob_cli *cli) { - /* In pull mode, the partial block reports are used to confirm which - * chunks have been received, while in push mode, we just assume that a - * sent chunk has been received. - */ - if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { - blob_chunk_missing_set(cli->block.missing, cli->chunk_idx, false); - } + /* In pull mode, the partial block reports are used to confirm which + * chunks have been received, while in push mode, we just assume that a + * sent chunk has been received. + */ - cli->chunk_idx = next_missing_chunk(cli, cli->block.missing, cli->chunk_idx + 1); - if (cli->chunk_idx < cli->block.chunk_count) { - chunk_send(cli); - return; - } + BT_DBG("A Chunk sent finished"); - if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { - block_check(cli); - } else { - block_report_wait(cli); - } + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + blob_chunk_missing_set(cli->block.missing, cli->chunk_idx, false); + } + + cli->chunk_idx = next_missing_chunk(cli, cli->block.missing, cli->chunk_idx + 1); + if (cli->chunk_idx < cli->block.chunk_count) { + chunk_send(cli); + return; + } + + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + block_check(cli); + } else { + block_report_wait(cli); + } } /* The block checking pair(block_check - block_check_end) @@ -984,149 +993,149 @@ static void chunk_send_end(struct bt_mesh_blob_cli *cli) */ static void block_check(struct bt_mesh_blob_cli *cli) { - const struct blob_cli_broadcast_ctx ctx = { - .send = block_get_tx, - .next = block_check_end, - .acked = true, - }; + const struct blob_cli_broadcast_ctx ctx = { + .send = block_get_tx, + .next = block_check_end, + .acked = true, + }; - cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK; + cli->state = BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK; - LOG_DBG(""); + BT_DBG(""); - blob_cli_broadcast(cli, &ctx); + blob_cli_broadcast(cli, &ctx); } static void block_report_wait(struct bt_mesh_blob_cli *cli) { - const struct blob_cli_broadcast_ctx ctx = { - .next = block_check_end, - .acked = false, - }; + const struct blob_cli_broadcast_ctx ctx = { + .next = block_check_end, + .acked = false, + }; - /* Check if all servers already confirmed all chunks during the transmission. */ - if (next_missing_chunk(cli, cli->block.missing, 0) >= cli->block.chunk_count) { - block_check_end(cli); - return; - } + /* Check if all servers already confirmed all chunks during the transmission. */ + if (next_missing_chunk(cli, cli->block.missing, 0) >= cli->block.chunk_count) { + block_check_end(cli); + return; + } - LOG_DBG("Waiting for partial block report..."); - cli->tx.ctx = ctx; + BT_DBG("Waiting for partial block report..."); + cli->tx.ctx = ctx; - /* Start Client Timeout Timer in Send Data sub-procedure for the first time. */ - if (!cli->tx.cli_timestamp) { - cli->tx.cli_timestamp = k_uptime_get() + CLIENT_TIMEOUT_MSEC(cli); - } + /* Start Client Timeout Timer in Send Data sub-procedure for the first time. */ + if (!cli->tx.cli_timestamp) { + cli->tx.cli_timestamp = k_uptime_get() + CLIENT_TIMEOUT_MSEC(cli); + } - start_retry_timer(cli); + start_retry_timer(cli); } static void block_check_end(struct bt_mesh_blob_cli *cli) { - LOG_DBG(""); + BT_DBG(""); - if (!targets_active(cli)) { - if (targets_timedout(cli)) { - suspend(cli); - return; - } + if (!targets_active(cli)) { + if (targets_timedout(cli)) { + suspend(cli); + return; + } - end(cli, false); - return; - } + end(cli, false); + return; + } - cli->chunk_idx = next_missing_chunk(cli, cli->block.missing, 0); - if (cli->chunk_idx < cli->block.chunk_count) { - chunk_send(cli); - return; - } + cli->chunk_idx = next_missing_chunk(cli, cli->block.missing, 0); + if (cli->chunk_idx < cli->block.chunk_count) { + chunk_send(cli); + return; + } - LOG_DBG("No more missing chunks for block %u", cli->block.number); + BT_DBG("No more missing chunks for block %u", cli->block.number); - if (cli->io->block_end) { - cli->io->block_end(cli->io, cli->xfer, &cli->block); - if (cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { - return; - } - } + if (cli->io->block_end) { + cli->io->block_end(cli->io, cli->xfer, &cli->block); + if (cli->state == BT_MESH_BLOB_CLI_STATE_NONE) { + return; + } + } - if (cli->block.number == cli->block_count - 1) { - struct bt_mesh_blob_target *target; + if (cli->block.number == cli->block_count - 1) { + struct bt_mesh_blob_target *target; - TARGETS_FOR_EACH(cli, target) { - target->procedure_complete = 0U; - } + TARGETS_FOR_EACH(cli, target) { + target->procedure_complete = 0U; + } - confirm_transfer(cli); - return; - } + confirm_transfer(cli); + return; + } - block_set(cli, cli->block.number + 1); - block_start(cli); + block_set(cli, cli->block.number + 1); + block_start(cli); } static void confirm_transfer(struct bt_mesh_blob_cli *cli) { - const struct blob_cli_broadcast_ctx ctx = { - .send = xfer_get_tx, - .next = transfer_complete, - .acked = true, - }; + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_get_tx, + .next = transfer_complete, + .acked = true, + }; - LOG_DBG(""); + BT_DBG(""); - cli->state = BT_MESH_BLOB_CLI_STATE_XFER_CHECK; + cli->state = BT_MESH_BLOB_CLI_STATE_XFER_CHECK; - blob_cli_broadcast(cli, &ctx); + blob_cli_broadcast(cli, &ctx); } static void progress_checked(struct bt_mesh_blob_cli *cli) { - LOG_DBG(""); + BT_DBG(""); - cli->state = BT_MESH_BLOB_CLI_STATE_NONE; + cli->state = BT_MESH_BLOB_CLI_STATE_NONE; - if (cli->cb && cli->cb->end) { - cli->cb->xfer_progress_complete(cli); - } + if (cli->cb && cli->cb->end) { + cli->cb->xfer_progress_complete(cli); + } } static void check_transfer(struct bt_mesh_blob_cli *cli) { - const struct blob_cli_broadcast_ctx ctx = { - .send = xfer_get_tx, - .next = progress_checked, - .acked = true, - }; + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_get_tx, + .next = progress_checked, + .acked = true, + }; - LOG_DBG(""); + BT_DBG(""); - cli->state = BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET; + cli->state = BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET; - blob_cli_broadcast(cli, &ctx); + blob_cli_broadcast(cli, &ctx); } static void transfer_cancel(struct bt_mesh_blob_cli *cli) { - const struct blob_cli_broadcast_ctx ctx = { - .send = xfer_cancel_tx, - .next = transfer_complete, - .acked = true, - }; + const struct blob_cli_broadcast_ctx ctx = { + .send = xfer_cancel_tx, + .next = transfer_complete, + .acked = true, + }; - LOG_DBG(""); + BT_DBG(""); - cli->state = BT_MESH_BLOB_CLI_STATE_CANCEL; + cli->state = BT_MESH_BLOB_CLI_STATE_CANCEL; - blob_cli_broadcast(cli, &ctx); + blob_cli_broadcast(cli, &ctx); } static void transfer_complete(struct bt_mesh_blob_cli *cli) { - bool success = targets_active(cli) && - cli->state == BT_MESH_BLOB_CLI_STATE_XFER_CHECK; + bool success = targets_active(cli) && + cli->state == BT_MESH_BLOB_CLI_STATE_XFER_CHECK; - end(cli, success); + end(cli, success); } /******************************************************************************* @@ -1134,525 +1143,551 @@ static void transfer_complete(struct bt_mesh_blob_cli *cli) ******************************************************************************/ static void rx_block_status(struct bt_mesh_blob_cli *cli, - struct bt_mesh_blob_target *target, - struct block_status *block) + struct bt_mesh_blob_target *target, + struct block_status *block) { - if (cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_START && - cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && - cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK) { - LOG_WRN("Invalid state %u", cli->state); - return; - } + if (cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_START && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK) { + BT_WARN("Invalid state %u", cli->state); + return; + } - LOG_DBG("0x%04x: block: %u status: %u", target->addr, block->block.number, block->status); + BT_WARN("0x%04x: block: %u status: %u", target->addr, block->block.number, block->status); - if (block->status != BT_MESH_BLOB_SUCCESS) { - target_drop(cli, target, block->status); - blob_cli_broadcast_rsp(cli, target); - return; - } + if (block->status != BT_MESH_BLOB_SUCCESS && + /** + * Changed by Espressif. + * This behavior is not allowed by spec! + * + * BT_MESH_BLOB_ERR_INFO_UNAVAILABLE will caused + * by blob server suspend, and the suspend state + * will be resume in most scenes. + * + * so let blob client try to resume blob server. + */ + block->status != BT_MESH_BLOB_ERR_INFO_UNAVAILABLE) { + target_drop(cli, target, block->status); + blob_cli_broadcast_rsp(cli, target); + return; + } - if (block->block.number != cli->block.number) { - LOG_DBG("Invalid block num (expected %u)", cli->block.number); - return; - } + if (block->block.number != cli->block.number) { + BT_DBG("Invalid block num (expected %u)", cli->block.number); + return; + } - if (block->missing == BT_MESH_BLOB_CHUNKS_MISSING_NONE) { - target->procedure_complete = 1U; + if (block->missing == BT_MESH_BLOB_CHUNKS_MISSING_NONE) { + target->procedure_complete = 1U; - if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { - memset(target->pull->missing, 0, sizeof(target->pull->missing)); - update_missing_chunks(cli); - } + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + memset(target->pull->missing, 0, sizeof(target->pull->missing)); + update_missing_chunks(cli); + } - LOG_DBG("Target 0x%04x received all chunks", target->addr); - } else if (block->missing == BT_MESH_BLOB_CHUNKS_MISSING_ALL) { - blob_chunk_missing_set_all(&cli->block); - } else if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { - memcpy(target->pull->missing, block->block.missing, sizeof(block->block.missing)); + BT_DBG("Target 0x%04x received all chunks", target->addr); + } else if (block->missing == BT_MESH_BLOB_CHUNKS_MISSING_ALL) { + blob_chunk_missing_set_all(&cli->block); + } else if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PULL) { + memcpy(target->pull->missing, block->block.missing, sizeof(block->block.missing)); - LOG_DBG("Missing: %s", bt_hex(target->pull->missing, cli->block.chunk_count)); + BT_DBG("Missing: %s", bt_hex(target->pull->missing, cli->block.chunk_count)); - update_missing_chunks(cli); + update_missing_chunks(cli); - /* Target has responded. Reset the timestamp so that client can start transmitting - * missing chunks to it. - */ - target->pull->block_report_timestamp = 0ll; - } else { - for (int i = 0; i < ARRAY_SIZE(block->block.missing); ++i) { - cli->block.missing[i] |= block->block.missing[i]; - } - } + /* Target has responded. Reset the timestamp so that client can start transmitting + * missing chunks to it. + */ + target->pull->block_report_timestamp = 0ll; + } else { + for (int i = 0; i < ARRAY_SIZE(block->block.missing); ++i) { + cli->block.missing[i] |= block->block.missing[i]; + } + } - if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { - if (!cli->tx.sending) { - /* If not sending, then the retry timer is running. Call - * broadcast_complete() to proceed to block_check_end() and start - * transmitting missing chunks. - */ - broadcast_complete(cli); - } + if (SENDING_CHUNKS_IN_PULL_MODE(cli)) { + if (!cli->tx.sending) { + /* If not sending, then the retry timer is running. Call + * broadcast_complete() to proceed to block_check_end() and start + * transmitting missing chunks. + */ + broadcast_complete(cli); + } - /* When sending chunks in Pull mode, we don't confirm transaction when receiving - * Partial Block Report message. - */ - return; - } + /* When sending chunks in Pull mode, we don't confirm transaction when receiving + * Partial Block Report message. + */ + return; + } - blob_cli_broadcast_rsp(cli, target); + blob_cli_broadcast_rsp(cli, target); } static int handle_xfer_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = mod->rt->user_data; - enum bt_mesh_blob_xfer_phase expected_phase; - struct bt_mesh_blob_target *target; - struct bt_mesh_blob_xfer_info info = { 0 }; - uint8_t status_and_mode; + struct bt_mesh_blob_cli *cli = mod->user_data; + enum bt_mesh_blob_xfer_phase expected_phase; + struct bt_mesh_blob_target *target; + struct bt_mesh_blob_xfer_info info = { 0 }; + uint8_t status_and_mode; - status_and_mode = net_buf_simple_pull_u8(buf); - info.status = status_and_mode & BIT_MASK(4); - info.mode = status_and_mode >> 6; - info.phase = net_buf_simple_pull_u8(buf); + status_and_mode = net_buf_simple_pull_u8(buf); + info.status = status_and_mode & BIT_MASK(4); + info.mode = status_and_mode >> 6; + info.phase = net_buf_simple_pull_u8(buf); - if (buf->len) { - info.id = net_buf_simple_pull_le64(buf); - } + if (buf->len) { + info.id = net_buf_simple_pull_le64(buf); + } - if (buf->len >= 7) { - info.size = net_buf_simple_pull_le32(buf); - info.block_size_log = net_buf_simple_pull_u8(buf); - info.mtu_size = net_buf_simple_pull_le16(buf); - info.missing_blocks = net_buf_simple_pull(buf, buf->len); - } + if (buf->len >= 7) { + info.size = net_buf_simple_pull_le32(buf); + info.block_size_log = net_buf_simple_pull_u8(buf); + info.mtu_size = net_buf_simple_pull_le16(buf); + info.missing_blocks = net_buf_simple_pull(buf, buf->len); + } - LOG_DBG("status: %u %s phase: %u %s", info.status, - info.mode == BT_MESH_BLOB_XFER_MODE_PUSH ? "push" : "pull", - info.phase, bt_hex(&info.id, 8)); + BT_DBG("status: %u %s phase: %u %s", info.status, + info.mode == BT_MESH_BLOB_XFER_MODE_PUSH ? "push" : "pull", + info.phase, bt_hex(&info.id, 8)); + if (cli->state != BT_MESH_BLOB_CLI_STATE_START && + cli->state != BT_MESH_BLOB_CLI_STATE_XFER_CHECK && + cli->state != BT_MESH_BLOB_CLI_STATE_CANCEL && + cli->state != BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET) { + BT_WARN("Wrong state: %d", cli->state); + return -EBUSY; + } - if (cli->state != BT_MESH_BLOB_CLI_STATE_START && - cli->state != BT_MESH_BLOB_CLI_STATE_XFER_CHECK && - cli->state != BT_MESH_BLOB_CLI_STATE_CANCEL && - cli->state != BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET) { - LOG_WRN("Wrong state: %d", cli->state); - return -EBUSY; - } + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } - target = target_get(cli, ctx->addr); - if (!target) { - return -ENOENT; - } + if (cli->state == BT_MESH_BLOB_CLI_STATE_START) { + expected_phase = BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK; + } else if (cli->state == BT_MESH_BLOB_CLI_STATE_XFER_CHECK) { + expected_phase = BT_MESH_BLOB_XFER_PHASE_COMPLETE; + } else if (cli->state != BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET) { + expected_phase = BT_MESH_BLOB_XFER_PHASE_INACTIVE; + } else { /* cli->state == BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET */ + blob_cli_broadcast_rsp(cli, target); + if (cli->cb && cli->cb->xfer_progress) { + cli->cb->xfer_progress(cli, target, &info); + } + return 0; + } - if (cli->state == BT_MESH_BLOB_CLI_STATE_START) { - expected_phase = BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK; - } else if (cli->state == BT_MESH_BLOB_CLI_STATE_XFER_CHECK) { - expected_phase = BT_MESH_BLOB_XFER_PHASE_COMPLETE; - } else if (cli->state != BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET) { - expected_phase = BT_MESH_BLOB_XFER_PHASE_INACTIVE; - } else { /* cli->state == BT_MESH_BLOB_CLI_STATE_XFER_PROGRESS_GET */ - blob_cli_broadcast_rsp(cli, target); - if (cli->cb && cli->cb->xfer_progress) { - cli->cb->xfer_progress(cli, target, &info); - } - return 0; - } + if (info.status != BT_MESH_BLOB_SUCCESS) { + target_drop(cli, target, info.status); + } else if (info.phase != expected_phase) { + BT_WARN("Wrong phase: %u != %u", expected_phase, info.phase); + return -EINVAL; + } else if (info.phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE && + info.id != cli->xfer->id) { + target_drop(cli, target, BT_MESH_BLOB_ERR_WRONG_BLOB_ID); + } - if (info.status != BT_MESH_BLOB_SUCCESS) { - target_drop(cli, target, info.status); - } else if (info.phase != expected_phase) { - LOG_WRN("Wrong phase: %u != %u", expected_phase, info.phase); - return -EINVAL; - } else if (info.phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE && - info.id != cli->xfer->id) { - target_drop(cli, target, BT_MESH_BLOB_ERR_WRONG_BLOB_ID); - } + blob_cli_broadcast_rsp(cli, target); - blob_cli_broadcast_rsp(cli, target); - - return 0; + return 0; } static int handle_block_report(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = mod->rt->user_data; - struct block_status status = { - .status = BT_MESH_BLOB_SUCCESS, - .block.number = cli->block.number, - .missing = (buf->len ? BT_MESH_BLOB_CHUNKS_MISSING_ENCODED : - BT_MESH_BLOB_CHUNKS_MISSING_NONE), - }; - struct bt_mesh_blob_target *target; + struct bt_mesh_blob_cli *cli = mod->user_data; + struct block_status status = { + .status = BT_MESH_BLOB_SUCCESS, + .block.number = cli->block.number, + .missing = (buf->len ? BT_MESH_BLOB_CHUNKS_MISSING_ENCODED : + BT_MESH_BLOB_CHUNKS_MISSING_NONE), + }; + struct bt_mesh_blob_target *target; - if (!cli->xfer) { - return -EINVAL; - } + if (!cli->xfer) { + return -EINVAL; + } - if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { - LOG_WRN("Unexpected encoded block report in push mode"); - return -EINVAL; - } + if (cli->xfer->mode == BT_MESH_BLOB_XFER_MODE_PUSH) { + BT_WARN("Unexpected encoded block report in push mode"); + return -EINVAL; + } - LOG_DBG(""); + BT_DBG(""); - target = target_get(cli, ctx->addr); - if (!target) { - return -ENOENT; - } + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } - while (buf->len) { - int idx; + while (buf->len) { + int idx; - idx = chunk_idx_decode(buf); - if (idx < 0) { - return idx; - } + idx = chunk_idx_decode(buf); + if (idx < 0) { + return idx; + } - blob_chunk_missing_set(status.block.missing, idx, true); - } + blob_chunk_missing_set(status.block.missing, idx, true); + } - /* If all chunks were already confirmed by this target, Send Data State Machine is in Final - * state for this target. Therefore, the message should be ignored. - */ - if (next_missing_chunk(cli, target->pull->missing, 0) >= cli->block.chunk_count) { - LOG_DBG("All chunks already confirmed"); - return 0; - } + /* If all chunks were already confirmed by this target, Send Data State Machine is in Final + * state for this target. Therefore, the message should be ignored. + */ + if (next_missing_chunk(cli, target->pull->missing, 0) >= cli->block.chunk_count) { + BT_DBG("All chunks already confirmed"); + return 0; + } - cli->tx.cli_timestamp = k_uptime_get() + CLIENT_TIMEOUT_MSEC(cli); + cli->tx.cli_timestamp = k_uptime_get() + CLIENT_TIMEOUT_MSEC(cli); - rx_block_status(cli, target, &status); + rx_block_status(cli, target, &status); - return 0; + return 0; } static int handle_block_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = mod->rt->user_data; - struct bt_mesh_blob_target *target; - struct block_status status = { 0 }; - uint8_t status_and_format; - uint16_t chunk_size; - size_t len; - int idx; + struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_target *target; + struct block_status status = { 0 }; + uint8_t status_and_format; + uint16_t chunk_size; + size_t len; + int idx; - target = target_get(cli, ctx->addr); - if (!target) { - return -ENOENT; - } + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } - status_and_format = net_buf_simple_pull_u8(buf); - status.status = status_and_format & BIT_MASK(4); - status.missing = status_and_format >> 6; - status.block.number = net_buf_simple_pull_le16(buf); - chunk_size = net_buf_simple_pull_le16(buf); - status.block.chunk_count = - DIV_ROUND_UP(cli->block.size, chunk_size); + status_and_format = net_buf_simple_pull_u8(buf); + status.status = status_and_format & BIT_MASK(4); + status.missing = status_and_format >> 6; + status.block.number = net_buf_simple_pull_le16(buf); + chunk_size = net_buf_simple_pull_le16(buf); + status.block.chunk_count = + DIV_ROUND_UP(cli->block.size, chunk_size); - LOG_DBG("status: %u block: %u encoding: %u", status.status, - status.block.number, status.missing); + BT_DBG("status: %u block: %u encoding: %u", status.status, + status.block.number, status.missing); - switch (status.missing) { - case BT_MESH_BLOB_CHUNKS_MISSING_ALL: - blob_chunk_missing_set_all(&status.block); - break; - case BT_MESH_BLOB_CHUNKS_MISSING_NONE: - break; - case BT_MESH_BLOB_CHUNKS_MISSING_SOME: - if (buf->len > sizeof(status.block.missing)) { - return -EINVAL; - } + switch (status.missing) { + case BT_MESH_BLOB_CHUNKS_MISSING_ALL: + blob_chunk_missing_set_all(&status.block); + break; + case BT_MESH_BLOB_CHUNKS_MISSING_NONE: + break; + case BT_MESH_BLOB_CHUNKS_MISSING_SOME: + if (buf->len > sizeof(status.block.missing)) { + return -EINVAL; + } - len = buf->len; - memcpy(status.block.missing, net_buf_simple_pull_mem(buf, len), - len); + len = buf->len; + memcpy(status.block.missing, net_buf_simple_pull_mem(buf, len), + len); - LOG_DBG("Missing: %s", bt_hex(status.block.missing, len)); - break; - case BT_MESH_BLOB_CHUNKS_MISSING_ENCODED: - /** MshMBTv1.0: 5.3.8: An empty Missing Chunks field entails that there are no - * missing chunks for this block. - */ - if (!buf->len) { - status.missing = BT_MESH_BLOB_CHUNKS_MISSING_NONE; - } + BT_DBG("Missing: %s", bt_hex(status.block.missing, len)); + break; + case BT_MESH_BLOB_CHUNKS_MISSING_ENCODED: + /** MshMBTv1.0: 5.3.8: An empty Missing Chunks field entails that there are no + * missing chunks for this block. + */ + if (!buf->len) { + status.missing = BT_MESH_BLOB_CHUNKS_MISSING_NONE; + } - while (buf->len) { - idx = chunk_idx_decode(buf); - if (idx < 0 || idx >= status.block.chunk_count) { - LOG_ERR("Invalid encoding"); - return -EINVAL; - } + while (buf->len) { + idx = chunk_idx_decode(buf); + if (idx < 0 || idx >= status.block.chunk_count) { + BT_ERR("Invalid encoding"); + return -EINVAL; + } - LOG_DBG("Missing %d", idx); + BT_DBG("Missing %d", idx); - blob_chunk_missing_set(status.block.missing, idx, true); - } - break; - } + blob_chunk_missing_set(status.block.missing, idx, true); + } + break; + } - rx_block_status(cli, target, &status); + rx_block_status(cli, target, &status); - return 0; + return 0; } static int handle_info_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_blob_cli *cli = mod->rt->user_data; - struct bt_mesh_blob_cli_caps caps; - enum bt_mesh_blob_status status; - struct bt_mesh_blob_target *target; + struct bt_mesh_blob_cli *cli = mod->user_data; + struct bt_mesh_blob_cli_caps caps; + enum bt_mesh_blob_status status; + struct bt_mesh_blob_target *target; - if (cli->state != BT_MESH_BLOB_CLI_STATE_CAPS_GET) { - return -EBUSY; - } + if (cli->state != BT_MESH_BLOB_CLI_STATE_CAPS_GET) { + return -EBUSY; + } - caps.min_block_size_log = net_buf_simple_pull_u8(buf); - caps.max_block_size_log = net_buf_simple_pull_u8(buf); - caps.max_chunks = net_buf_simple_pull_le16(buf); - caps.max_chunk_size = net_buf_simple_pull_le16(buf); - caps.max_size = net_buf_simple_pull_le32(buf); - caps.mtu_size = net_buf_simple_pull_le16(buf); - caps.modes = net_buf_simple_pull_u8(buf); + caps.min_block_size_log = net_buf_simple_pull_u8(buf); + caps.max_block_size_log = net_buf_simple_pull_u8(buf); + caps.max_chunks = net_buf_simple_pull_le16(buf); + caps.max_chunk_size = net_buf_simple_pull_le16(buf); + caps.max_size = net_buf_simple_pull_le32(buf); + caps.mtu_size = net_buf_simple_pull_le16(buf); + caps.modes = net_buf_simple_pull_u8(buf); - if (caps.min_block_size_log < 0x06 || - caps.max_block_size_log > 0x20 || - caps.max_block_size_log < caps.min_block_size_log || - caps.max_chunks == 0 || caps.max_chunk_size < 8 || - caps.max_size == 0 || caps.mtu_size < 0x14) { - return -EINVAL; - } + if (caps.min_block_size_log < 0x06 || + caps.max_block_size_log > 0x20 || + caps.max_block_size_log < caps.min_block_size_log || + caps.max_chunks == 0 || caps.max_chunk_size < 8 || + caps.max_size == 0 || caps.mtu_size < 0x14) { + return -EINVAL; + } - LOG_DBG("0x%04x\n\tblock size: %u - %u\n\tchunks: %u\n\tchunk size: %u\n" - "\tblob size: %u\n\tmtu size: %u\n\tmodes: %x", - ctx->addr, caps.min_block_size_log, caps.max_block_size_log, - caps.max_chunks, caps.max_chunk_size, caps.max_size, - caps.mtu_size, caps.modes); + BT_DBG("0x%04x\n\tblock size: %u - %u\n\tchunks: %u\n\tchunk size: %u\n" + "\tblob size: %u\n\tmtu size: %u\n\tmodes: %x", + ctx->addr, caps.min_block_size_log, caps.max_block_size_log, + caps.max_chunks, caps.max_chunk_size, caps.max_size, + caps.mtu_size, caps.modes); - target = target_get(cli, ctx->addr); - if (!target) { - return -ENOENT; - } + target = target_get(cli, ctx->addr); + if (!target) { + return -ENOENT; + } - status = caps_adjust(cli, &caps); - if (status != BT_MESH_BLOB_SUCCESS) { - target_drop(cli, target, status); - } + status = caps_adjust(cli, &caps); + if (status != BT_MESH_BLOB_SUCCESS) { + target_drop(cli, target, status); + } - blob_cli_broadcast_rsp(cli, target); + blob_cli_broadcast_rsp(cli, target); - return 0; + return 0; } const struct bt_mesh_model_op _bt_mesh_blob_cli_op[] = { - { BT_MESH_BLOB_OP_XFER_STATUS, BT_MESH_LEN_MIN(2), handle_xfer_status }, - { BT_MESH_BLOB_OP_BLOCK_REPORT, BT_MESH_LEN_MIN(0), handle_block_report }, - { BT_MESH_BLOB_OP_BLOCK_STATUS, BT_MESH_LEN_MIN(5), handle_block_status }, - { BT_MESH_BLOB_OP_INFO_STATUS, BT_MESH_LEN_EXACT(13), handle_info_status }, - BT_MESH_MODEL_OP_END, + { BT_MESH_BLOB_OP_XFER_STATUS, 2, (void *)handle_xfer_status }, + { BT_MESH_BLOB_OP_BLOCK_REPORT, 0, (void *)handle_block_report }, + { BT_MESH_BLOB_OP_BLOCK_STATUS, 5, (void *)handle_block_status }, + { BT_MESH_BLOB_OP_INFO_STATUS, 13, (void *)handle_info_status }, + BLE_MESH_MODEL_OP_END, }; -static int blob_cli_init(const struct bt_mesh_model *mod) +static int blob_cli_init(struct bt_mesh_model *mod) { - struct bt_mesh_blob_cli *cli = mod->rt->user_data; + struct bt_mesh_blob_cli *cli = mod->user_data; - cli->mod = mod; + cli->mod = mod; - bt_mesh_blob_cli_set_chunk_interval_ms(cli, CONFIG_BT_MESH_TX_BLOB_CHUNK_SEND_INTERVAL); - cli->tx.cli_timestamp = 0ll; - k_work_init_delayable(&cli->tx.retry, retry_timeout); - k_work_init_delayable(&cli->tx.complete, tx_complete); + bt_mesh_blob_cli_set_chunk_interval_ms(cli, CONFIG_BLE_MESH_TX_BLOB_CHUNK_SEND_INTERVAL); + cli->tx.cli_timestamp = 0ll; + k_work_init_delayable(&cli->tx.retry, retry_timeout); + k_work_init_delayable(&cli->tx.complete, tx_complete); - return 0; + return 0; } -static void blob_cli_reset(const struct bt_mesh_model *mod) +static void blob_cli_reset(struct bt_mesh_model *mod) { - struct bt_mesh_blob_cli *cli = mod->rt->user_data; + struct bt_mesh_blob_cli *cli = mod->user_data; - cli_state_reset(cli); + cli_state_reset(cli); +} + +static int blob_cli_deinit(struct bt_mesh_model *mod) +{ + blob_cli_reset(mod); + return 0; } const struct bt_mesh_model_cb _bt_mesh_blob_cli_cb = { - .init = blob_cli_init, - .reset = blob_cli_reset, + .init = blob_cli_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = blob_cli_deinit, +#endif }; - int bt_mesh_blob_cli_caps_get(struct bt_mesh_blob_cli *cli, - const struct bt_mesh_blob_cli_inputs *inputs) + const struct bt_mesh_blob_cli_inputs *inputs) { - if (bt_mesh_blob_cli_is_busy(cli)) { - return -EBUSY; - } + if (bt_mesh_blob_cli_is_busy(cli)) { + return -EBUSY; + } - cli->inputs = inputs; + cli->inputs = inputs; - cli->caps.min_block_size_log = 0x06; - cli->caps.max_block_size_log = 0x20; - cli->caps.max_chunks = CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX; - cli->caps.max_chunk_size = BLOB_TX_CHUNK_SIZE; - cli->caps.max_size = 0xffffffff; - cli->caps.mtu_size = 0xffff; - cli->caps.modes = BT_MESH_BLOB_XFER_MODE_ALL; + cli->caps.min_block_size_log = 0x06; + cli->caps.max_block_size_log = 0x20; + cli->caps.max_chunks = CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX; + cli->caps.max_chunk_size = BLOB_TX_CHUNK_SIZE; + cli->caps.max_size = 0xffffffff; + cli->caps.mtu_size = 0xffff; + cli->caps.modes = BT_MESH_BLOB_XFER_MODE_ALL; - if (!targets_reset(cli)) { - LOG_ERR("No valid targets"); - return -ENODEV; - } + if (!targets_reset(cli)) { + BT_ERR("No valid targets"); + return -ENODEV; + } - caps_get(cli); + caps_get(cli); - return 0; + return 0; } int bt_mesh_blob_cli_send(struct bt_mesh_blob_cli *cli, - const struct bt_mesh_blob_cli_inputs *inputs, - const struct bt_mesh_blob_xfer *xfer, - const struct bt_mesh_blob_io *io) + const struct bt_mesh_blob_cli_inputs *inputs, + const struct bt_mesh_blob_xfer *xfer, + const struct bt_mesh_blob_io *io) { - if (bt_mesh_blob_cli_is_busy(cli)) { - LOG_ERR("BLOB Client is busy"); - return -EBUSY; - } + if (bt_mesh_blob_cli_is_busy(cli)) { + BT_ERR("BLOB Client is busy"); + return -EBUSY; + } - if (!(xfer->mode & BT_MESH_BLOB_XFER_MODE_ALL) || xfer->block_size_log < 0x06 || - xfer->block_size_log > 0x20 || xfer->chunk_size < 8 || - xfer->chunk_size > BLOB_TX_CHUNK_SIZE) { - LOG_ERR("Incompatible transfer parameters"); - return -EINVAL; - } + if (!(xfer->mode & BT_MESH_BLOB_XFER_MODE_ALL) || xfer->block_size_log < 0x06 || + xfer->block_size_log > 0x20 || xfer->chunk_size < 8 || + xfer->chunk_size > BLOB_TX_CHUNK_SIZE) { + BT_ERR("Incompatible transfer parameters"); + return -EINVAL; + } - cli->xfer = xfer; - cli->inputs = inputs; - cli->io = io; + cli->xfer = xfer; + cli->inputs = inputs; + cli->io = io; - if (cli->xfer->block_size_log == 0x20) { - cli->block_count = 1; - } else { - cli->block_count = DIV_ROUND_UP(cli->xfer->size, (1U << cli->xfer->block_size_log)); - } + if (cli->xfer->block_size_log == 0x20) { + cli->block_count = 1; + } else { + cli->block_count = DIV_ROUND_UP(cli->xfer->size, (1U << cli->xfer->block_size_log)); + } - block_set(cli, 0); + block_set(cli, 0); - if (cli->block.chunk_count > CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX) { - LOG_ERR("Too many chunks"); - return -EINVAL; - } + if (cli->block.chunk_count > CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX) { + BT_ERR("Too many chunks"); + return -EINVAL; + } - if (!targets_reset(cli)) { - LOG_ERR("No valid targets"); - return -ENODEV; - } + if (!targets_reset(cli)) { + BT_ERR("No valid targets"); + return -ENODEV; + } - LOG_DBG("\n\tblock size log: %u\n\tchunk size: %u\n" - "\tblob size: %u\n\tmode: %x", - cli->xfer->block_size_log, cli->xfer->chunk_size, - cli->xfer->size, cli->xfer->mode); + BT_INFO("block size log: %u chunk size: %u blob size: %u tmode: %x", + cli->xfer->block_size_log, cli->xfer->chunk_size, + cli->xfer->size, cli->xfer->mode); - return xfer_start(cli); + return xfer_start(cli); } int bt_mesh_blob_cli_suspend(struct bt_mesh_blob_cli *cli) { - if (cli->state == BT_MESH_BLOB_CLI_STATE_SUSPENDED) { - return 0; - } + if (cli->state == BT_MESH_BLOB_CLI_STATE_SUSPENDED) { + return 0; + } - if (cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_START && - cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && - cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK) { - LOG_WRN("BLOB xfer not started: %d", cli->state); - return -EINVAL; - } + if (cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_START && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_SEND && + cli->state != BT_MESH_BLOB_CLI_STATE_BLOCK_CHECK) { + BT_WARN("BLOB xfer not started: %d", cli->state); + return -EINVAL; + } - cli->state = BT_MESH_BLOB_CLI_STATE_SUSPENDED; - (void)k_work_cancel_delayable(&cli->tx.retry); - cli->tx.ctx.is_inited = 0; - cli->tx.sending = 0; - cli->tx.cli_timestamp = 0ll; - return 0; + cli->state = BT_MESH_BLOB_CLI_STATE_SUSPENDED; + (void)k_work_cancel_delayable(&cli->tx.retry); + cli->tx.ctx.is_inited = 0; + cli->tx.sending = 0; + cli->tx.cli_timestamp = 0ll; + return 0; } int bt_mesh_blob_cli_resume(struct bt_mesh_blob_cli *cli) { - struct bt_mesh_blob_target *target; + struct bt_mesh_blob_target *target; - if (cli->state != BT_MESH_BLOB_CLI_STATE_SUSPENDED) { - LOG_WRN("Not suspended"); - return -EINVAL; - } + if (cli->state != BT_MESH_BLOB_CLI_STATE_SUSPENDED) { + BT_WARN("Not suspended"); + return -EINVAL; + } - /* Restore timed out targets. */ - TARGETS_FOR_EACH(cli, target) { - if (!!target->timedout) { - target->status = BT_MESH_BLOB_SUCCESS; - target->timedout = 0U; - } - } + /* Restore timed out targets. */ + TARGETS_FOR_EACH(cli, target) { + if (!!target->timedout) { + target->status = BT_MESH_BLOB_SUCCESS; + target->timedout = 0U; + } + } - if (!targets_reset(cli)) { - LOG_ERR("No valid targets"); - return -ENODEV; - } + if (!targets_reset(cli)) { + BT_ERR("No valid targets"); + return -ENODEV; + } - block_set(cli, 0); - return xfer_start(cli); + block_set(cli, 0); + return xfer_start(cli); } void bt_mesh_blob_cli_cancel(struct bt_mesh_blob_cli *cli) { - if (!bt_mesh_blob_cli_is_busy(cli)) { - LOG_WRN("BLOB xfer already cancelled"); - return; - } + if (!bt_mesh_blob_cli_is_busy(cli)) { + BT_WARN("BLOB xfer already cancelled"); + return; + } - LOG_DBG(""); + BT_DBG(""); - if (cli->state == BT_MESH_BLOB_CLI_STATE_CAPS_GET || - cli->state == BT_MESH_BLOB_CLI_STATE_SUSPENDED) { - cli_state_reset(cli); - return; - } + if (cli->state == BT_MESH_BLOB_CLI_STATE_CAPS_GET || + cli->state == BT_MESH_BLOB_CLI_STATE_SUSPENDED) { + cli_state_reset(cli); + return; + } - cli->tx.cancelled = 1U; - cli->state = BT_MESH_BLOB_CLI_STATE_CANCEL; + cli->tx.cancelled = 1U; + cli->state = BT_MESH_BLOB_CLI_STATE_CANCEL; +} + +void bt_mesh_blob_cli_send_cancel(struct bt_mesh_blob_cli *cli, + const struct bt_mesh_blob_xfer *xfer) +{ + cli->xfer = xfer; + + transfer_cancel(cli); } int bt_mesh_blob_cli_xfer_progress_get(struct bt_mesh_blob_cli *cli, - const struct bt_mesh_blob_cli_inputs *inputs) + const struct bt_mesh_blob_cli_inputs *inputs) { - if (bt_mesh_blob_cli_is_busy(cli)) { - return -EBUSY; - } + if (bt_mesh_blob_cli_is_busy(cli)) { + return -EBUSY; + } - cli->inputs = inputs; + cli->inputs = inputs; - check_transfer(cli); + check_transfer(cli); - return 0; + return 0; } uint8_t bt_mesh_blob_cli_xfer_progress_active_get(struct bt_mesh_blob_cli *cli) { - if (cli->state < BT_MESH_BLOB_CLI_STATE_START) { - return 0; - } + if (cli->state < BT_MESH_BLOB_CLI_STATE_START) { + return 0; + } - return (100U * cli->block.number) / cli->block_count; + return (100U * cli->block.number) / cli->block_count; } bool bt_mesh_blob_cli_is_busy(struct bt_mesh_blob_cli *cli) { - return cli->state != BT_MESH_BLOB_CLI_STATE_NONE; + return cli->state != BT_MESH_BLOB_CLI_STATE_NONE; } void bt_mesh_blob_cli_set_chunk_interval_ms(struct bt_mesh_blob_cli *cli, uint32_t interval_ms) { - cli->chunk_interval_ms = interval_ms; + cli->chunk_interval_ms = interval_ms; } + +#endif /* CONFIG_BLE_MESH_BLOB_CLI */ diff --git a/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c b/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c index 2d4ec561f8..3540a6abea 100644 --- a/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c +++ b/components/bt/esp_ble_mesh/v1.1/mbt/blob_srv.c @@ -1,315 +1,321 @@ /* - * Copyright (c) 2020 Nordic Semiconductor ASA + * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA + * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include -#include -#include + #include "net.h" #include "access.h" #include "transport.h" #include "lpn.h" +#include "mesh/main.h" +#include "mesh/utils.h" +#include "mesh/common.h" +#include "mesh/slist.h" #include "blob.h" +#include "mesh_v1.1/mbt/blob.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" -#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL -#include -LOG_MODULE_REGISTER(bt_mesh_blob_srv); +#if CONFIG_BLE_MESH_SETTINGS +#include "settings.h" +#endif -#define MTU_SIZE_MAX (BT_MESH_RX_SDU_MAX - BT_MESH_MIC_SHORT) +#if CONFIG_BLE_MESH_BLOB_SRV + +#define MTU_SIZE_MAX (BLE_MESH_RX_SDU_MAX - BLE_MESH_MIC_SHORT) /* The Receive BLOB Timeout Timer */ #define SERVER_TIMEOUT_SECS(srv) (10 * (1 + (srv)->state.timeout_base)) /* The initial timer value used by an instance of the Pull BLOB State machine - T_BPI */ -#define REPORT_TIMER_TIMEOUT K_SECONDS(CONFIG_BT_MESH_BLOB_REPORT_TIMEOUT) +#define REPORT_TIMER_TIMEOUT K_SECONDS(CONFIG_BLE_MESH_BLOB_REPORT_TIMEOUT) -BUILD_ASSERT(BLOB_BLOCK_SIZE_LOG_MIN <= BLOB_BLOCK_SIZE_LOG_MAX, - "The must be at least one number between the min and " - "max block size that is the power of two."); +_Static_assert(BLOB_BLOCK_SIZE_LOG_MIN <= BLOB_BLOCK_SIZE_LOG_MAX, + "The must be at least one number between the min and " + "max block size that is the power of two."); -BUILD_ASSERT((BLOB_XFER_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_XFER_STATUS) + - BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, - "The BLOB Transfer Status message does not fit into the maximum outgoing SDU size."); +_Static_assert((BLOB_XFER_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_XFER_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The BLOB Transfer Status message does not fit into the maximum outgoing SDU size."); -BUILD_ASSERT((BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN + - BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_REPORT) + BT_MESH_MIC_SHORT) - <= BT_MESH_TX_SDU_MAX, - "The BLOB Partial Block Report message does not fit into the maximum outgoing SDU " - "size."); +_Static_assert((BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN + + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_REPORT) + BLE_MESH_MIC_SHORT) + <= BLE_MESH_TX_SDU_MAX, + "The BLOB Partial Block Report message does not fit into the maximum outgoing SDU " + "size."); -BUILD_ASSERT((BLOB_BLOCK_STATUS_MSG_MAXLEN + BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_STATUS) + - BT_MESH_MIC_SHORT) <= BT_MESH_TX_SDU_MAX, - "The BLOB Block Status message does not fit into the maximum outgoing SDU size."); +_Static_assert((BLOB_BLOCK_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_BLOCK_STATUS) + + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, + "The BLOB Block Status message does not fit into the maximum outgoing SDU size."); static void cancel(struct bt_mesh_blob_srv *srv); static void suspend(struct bt_mesh_blob_srv *srv); static inline uint32_t block_count_get(const struct bt_mesh_blob_srv *srv) { - return DIV_ROUND_UP(srv->state.xfer.size, - (1U << srv->state.xfer.block_size_log)); + return DIV_ROUND_UP(srv->state.xfer.size, + (1U << srv->state.xfer.block_size_log)); } static inline uint32_t max_chunk_size(const struct bt_mesh_blob_srv *srv) { - return MIN((srv->state.mtu_size - 2 - BT_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK)), - BLOB_RX_CHUNK_SIZE); + return MIN((srv->state.mtu_size - 2 - BLE_MESH_MODEL_OP_LEN(BT_MESH_BLOB_OP_CHUNK)), + BLOB_RX_CHUNK_SIZE); } static inline uint32_t max_chunk_count(const struct bt_mesh_blob_srv *srv) { - return MIN(8 * (srv->state.mtu_size - 6), - CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX); + return MIN(8 * (srv->state.mtu_size - 6), + CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX); } static inline uint32_t missing_chunks(const struct bt_mesh_blob_block *block) { - int i; - uint32_t count = 0; + int i; + uint32_t count = 0; - for (i = 0; i < ARRAY_SIZE(block->missing); ++i) { - count += POPCOUNT(block->missing[i]); - } + for (i = 0; i < ARRAY_SIZE(block->missing); ++i) { + count += popcount(block->missing[i]); + } - return count; + return count; } static void store_state(const struct bt_mesh_blob_srv *srv) { - if (!IS_ENABLED(CONFIG_BT_SETTINGS)) { - return; - } +#if CONFIG_BLE_MESH_SETTINGS + /* Convert bit count to byte count: */ + uint32_t block_len = DIV_ROUND_UP(block_count_get(srv), 8); - /* Convert bit count to byte count: */ - uint32_t block_len = DIV_ROUND_UP(block_count_get(srv), 8); - - bt_mesh_model_data_store( - srv->mod, false, NULL, &srv->state, - offsetof(struct bt_mesh_blob_srv_state, blocks) + block_len); + bt_mesh_model_data_store( + srv->mod, false, NULL, &srv->state, + offsetof(struct bt_mesh_blob_srv_state, blocks) + block_len); +#endif } static void erase_state(struct bt_mesh_blob_srv *srv) { - if (!IS_ENABLED(CONFIG_BT_SETTINGS)) { - return; - } - - bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0); +#if CONFIG_BLE_MESH_SETTINGS + bt_mesh_model_data_store(srv->mod, false, NULL, NULL, 0); +#endif } static int io_open(struct bt_mesh_blob_srv *srv) { - if (!srv->io->open) { - return 0; - } + if (!srv->io->open) { + return 0; + } - return srv->io->open(srv->io, &srv->state.xfer, BT_MESH_BLOB_WRITE); + return srv->io->open(srv->io, &srv->state.xfer, BT_MESH_BLOB_WRITE); } static void io_close(struct bt_mesh_blob_srv *srv) { - if (!srv->io->close) { - return; - } + if (!srv->io->close) { + return; + } - srv->io->close(srv->io, &srv->state.xfer); + srv->io->close(srv->io, &srv->state.xfer); } static void reset_timer(struct bt_mesh_blob_srv *srv) { - uint32_t timeout_secs = - srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL ? - MAX(SERVER_TIMEOUT_SECS(srv), - CONFIG_BT_MESH_BLOB_REPORT_TIMEOUT + 1) : - SERVER_TIMEOUT_SECS(srv); - k_work_reschedule(&srv->rx_timeout, K_SECONDS(timeout_secs)); + uint32_t timeout_secs = + srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL ? + MAX(SERVER_TIMEOUT_SECS(srv), + CONFIG_BLE_MESH_BLOB_REPORT_TIMEOUT + 1) : + SERVER_TIMEOUT_SECS(srv); + BT_DBG("Next Msg should be arrive in %ds", timeout_secs); + k_work_reschedule(&srv->rx_timeout, K_SECONDS(timeout_secs)); } static void buf_chunk_index_add(struct net_buf_simple *buf, uint16_t chunk) { - /* utf-8 encoded: */ - if (chunk < 0x80) { - net_buf_simple_add_u8(buf, chunk); - } else if (chunk < 0x8000) { - net_buf_simple_add_u8(buf, 0xc0 | chunk >> 6); - net_buf_simple_add_u8(buf, 0x80 | (chunk & BIT_MASK(6))); - } else { - net_buf_simple_add_u8(buf, 0xe0 | chunk >> 12); - net_buf_simple_add_u8(buf, 0x80 | ((chunk >> 6) & BIT_MASK(6))); - net_buf_simple_add_u8(buf, 0x80 | (chunk & BIT_MASK(6))); - } + /* utf-8 encoded: */ + if (chunk < 0x80) { + net_buf_simple_add_u8(buf, chunk); + } else if (chunk < 0x8000) { + net_buf_simple_add_u8(buf, 0xc0 | chunk >> 6); + net_buf_simple_add_u8(buf, 0x80 | (chunk & BIT_MASK(6))); + } else { + net_buf_simple_add_u8(buf, 0xe0 | chunk >> 12); + net_buf_simple_add_u8(buf, 0x80 | ((chunk >> 6) & BIT_MASK(6))); + net_buf_simple_add_u8(buf, 0x80 | (chunk & BIT_MASK(6))); + } } static int pull_req_max(const struct bt_mesh_blob_srv *srv) { - int count = CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT; + int count = CONFIG_BLE_MESH_BLOB_SRV_PULL_REQ_COUNT; -#if defined(CONFIG_BT_MESH_LOW_POWER) - /* No point in requesting more than the friend node can hold: */ - if (bt_mesh_lpn_established()) { - uint32_t segments_per_chunk = DIV_ROUND_UP( - BLOB_CHUNK_SDU_LEN(srv->state.xfer.chunk_size), - BT_MESH_APP_SEG_SDU_MAX); +#if defined(CONFIG_BLE_MESH_LOW_POWER) + /* No point in requesting more than the friend node can hold: */ + if (bt_mesh_lpn_established()) { + uint32_t segments_per_chunk = DIV_ROUND_UP( + BLOB_CHUNK_SDU_LEN(srv->state.xfer.chunk_size), + BLE_MESH_APP_SEG_SDU_MAX); - count = MIN(CONFIG_BT_MESH_BLOB_SRV_PULL_REQ_COUNT, - bt_mesh.lpn.queue_size / segments_per_chunk); - } + count = MIN(CONFIG_BLE_MESH_BLOB_SRV_PULL_REQ_COUNT, + bt_mesh.lpn.queue_size / segments_per_chunk); + } #endif - return MIN(count, missing_chunks(&srv->block)); + return MIN(count, missing_chunks(&srv->block)); } static void report_sent(int err, void *cb_data) { - struct bt_mesh_blob_srv *srv = cb_data; + struct bt_mesh_blob_srv *srv = cb_data; - LOG_DBG(""); + BT_DBG(""); - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && bt_mesh_lpn_established()) { - bt_mesh_lpn_poll(); - } + if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && bt_mesh_lpn_established()) { + bt_mesh_lpn_poll(); + } - if (k_work_delayable_is_pending(&srv->rx_timeout)) { - k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); - } + if (k_work_delayable_is_pending(&srv->rx_timeout)) { + k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); + } } static void block_report(struct bt_mesh_blob_srv *srv) { - static const struct bt_mesh_send_cb report_cb = { .end = report_sent }; - struct bt_mesh_msg_ctx ctx = { - .app_idx = srv->state.app_idx, - .send_ttl = srv->state.ttl, - .addr = srv->state.cli, - }; - int count; - int i; + static const struct bt_mesh_send_cb report_cb = { .end = report_sent }; + struct bt_mesh_msg_ctx ctx = { + .app_idx = srv->state.app_idx, + .send_ttl = srv->state.ttl, + .addr = srv->state.cli, + }; + int count; + int i; - LOG_DBG("rx BLOB Timeout Timer: %i", k_work_delayable_is_pending(&srv->rx_timeout)); + BT_DBG("rx BLOB Timeout Timer: %i", k_work_delayable_is_pending(&srv->rx_timeout)); - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_REPORT, - BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN); - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_REPORT); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_REPORT, + BLOB_BLOCK_REPORT_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_REPORT); - count = pull_req_max(srv); + count = pull_req_max(srv); - for (i = 0; i < srv->block.chunk_count && count; ++i) { - if (blob_chunk_missing_get(srv->block.missing, i)) { - buf_chunk_index_add(&buf, i); - count--; - } - } + for (i = 0; i < srv->block.chunk_count && count; ++i) { + if (blob_chunk_missing_get(srv->block.missing, i)) { + buf_chunk_index_add(&buf, i); + count--; + } + } - (void)bt_mesh_model_send(srv->mod, &ctx, &buf, &report_cb, srv); + (void)bt_mesh_model_send(srv->mod, &ctx, &buf, &report_cb, srv); } static void phase_set(struct bt_mesh_blob_srv *srv, - enum bt_mesh_blob_xfer_phase phase) + enum bt_mesh_blob_xfer_phase phase) { - srv->phase = phase; - LOG_DBG("Phase: %u", phase); + srv->phase = phase; + BT_INFO("Phase: %u", phase); } static void cancel(struct bt_mesh_blob_srv *srv) { - /* TODO: Could this state be preserved instead somehow? Wiping the - * entire transfer state is a bit overkill - */ - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); - srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; - srv->state.ttl = BT_MESH_TTL_DEFAULT; - srv->block.number = 0xffff; - memset(srv->block.missing, 0, sizeof(srv->block.missing)); - srv->state.xfer.chunk_size = 0xffff; - k_work_cancel_delayable(&srv->rx_timeout); - k_work_cancel_delayable(&srv->pull.report); - io_close(srv); - erase_state(srv); + /* TODO: Could this state be preserved instead somehow? Wiping the + * entire transfer state is a bit overkill + */ + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); + srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; + srv->state.ttl = BLE_MESH_TTL_DEFAULT; + srv->block.number = 0xffff; + memset(srv->block.missing, 0, sizeof(srv->block.missing)); + srv->state.xfer.chunk_size = 0xffff; + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + io_close(srv); + erase_state(srv); - if (srv->cb && srv->cb->end) { - srv->cb->end(srv, srv->state.xfer.id, false); - } + if (srv->cb && srv->cb->end) { + srv->cb->end(srv, srv->state.xfer.id, false); + } } static void suspend(struct bt_mesh_blob_srv *srv) { - LOG_DBG(""); - k_work_cancel_delayable(&srv->rx_timeout); - k_work_cancel_delayable(&srv->pull.report); - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_SUSPENDED); - if (srv->cb && srv->cb->suspended) { - srv->cb->suspended(srv); - } + BT_DBG("%s", __func__); + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_SUSPENDED); + if (srv->cb && srv->cb->suspended) { + srv->cb->suspended(srv); + } } static void resume(struct bt_mesh_blob_srv *srv) { - LOG_DBG("Resuming"); + BT_DBG("%s", __func__); - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); - reset_timer(srv); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); + reset_timer(srv); } static void end(struct bt_mesh_blob_srv *srv) { - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_COMPLETE); - k_work_cancel_delayable(&srv->rx_timeout); - k_work_cancel_delayable(&srv->pull.report); - io_close(srv); - erase_state(srv); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_COMPLETE); + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + io_close(srv); + erase_state(srv); - if (srv->cb && srv->cb->end) { - srv->cb->end(srv, srv->state.xfer.id, true); - } + if (srv->cb && srv->cb->end) { + srv->cb->end(srv, srv->state.xfer.id, true); + } } static bool all_blocks_received(struct bt_mesh_blob_srv *srv) { - for (int i = 0; i < ARRAY_SIZE(srv->state.blocks); ++i) { - if (srv->state.blocks[i]) { - return false; - } - } + for (int i = 0; i < ARRAY_SIZE(srv->state.blocks); ++i) { + if (srv->state.blocks[i]) { + return false; + } + } - return true; + return true; } static bool pull_mode_xfer_complete(struct bt_mesh_blob_srv *srv) { - return srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL && - srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK && - all_blocks_received(srv); + return srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL && + srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK && + all_blocks_received(srv); } static void timeout(struct k_work *work) { - struct bt_mesh_blob_srv *srv = - CONTAINER_OF(work, struct bt_mesh_blob_srv, rx_timeout.work); + struct bt_mesh_blob_srv *srv = + CONTAINER_OF(work, struct bt_mesh_blob_srv, rx_timeout.work); - LOG_DBG(""); + BT_DBG("phase %d", srv->phase); - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { - cancel(srv); - } else if (pull_mode_xfer_complete(srv)) { - end(srv); - } else { - suspend(srv); - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + cancel(srv); + } else if (pull_mode_xfer_complete(srv)) { + end(srv); + } else { + suspend(srv); + } } static void report_timeout(struct k_work *work) { - struct bt_mesh_blob_srv *srv = - CONTAINER_OF(work, struct bt_mesh_blob_srv, pull.report.work); + struct bt_mesh_blob_srv *srv = + CONTAINER_OF(work, struct bt_mesh_blob_srv, pull.report.work); - LOG_DBG(""); + BT_DBG(""); - if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK && - srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { - return; - } + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK && + srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { + return; + } - block_report(srv); + block_report(srv); } /******************************************************************************* @@ -317,697 +323,751 @@ static void report_timeout(struct k_work *work) ******************************************************************************/ static void xfer_status_rsp(struct bt_mesh_blob_srv *srv, - struct bt_mesh_msg_ctx *ctx, - enum bt_mesh_blob_status status) + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_blob_status status) { - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_STATUS, - BLOB_XFER_STATUS_MSG_MAXLEN); - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_XFER_STATUS, + BLOB_XFER_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_XFER_STATUS); - net_buf_simple_add_u8(&buf, ((status & BIT_MASK(4)) | - (srv->state.xfer.mode << 6))); - net_buf_simple_add_u8(&buf, srv->phase); + net_buf_simple_add_u8(&buf, ((status & BIT_MASK(4)) | + (srv->state.xfer.mode << 6))); + net_buf_simple_add_u8(&buf, srv->phase); - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { - goto send; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + goto send; + } - net_buf_simple_add_le64(&buf, srv->state.xfer.id); + net_buf_simple_add_le64(&buf, srv->state.xfer.id); - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { - goto send; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + goto send; + } - net_buf_simple_add_le32(&buf, srv->state.xfer.size); - net_buf_simple_add_u8(&buf, srv->state.xfer.block_size_log); - net_buf_simple_add_le16(&buf, srv->state.mtu_size); - net_buf_simple_add_mem(&buf, srv->state.blocks, - DIV_ROUND_UP(block_count_get(srv), 8)); + net_buf_simple_add_le32(&buf, srv->state.xfer.size); + net_buf_simple_add_u8(&buf, srv->state.xfer.block_size_log); + net_buf_simple_add_le16(&buf, srv->state.mtu_size); + net_buf_simple_add_mem(&buf, srv->state.blocks, + DIV_ROUND_UP(block_count_get(srv), 8)); send: - ctx->send_ttl = srv->state.ttl; - (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); + ctx->send_ttl = srv->state.ttl; + (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); } static void block_status_rsp(struct bt_mesh_blob_srv *srv, - struct bt_mesh_msg_ctx *ctx, - enum bt_mesh_blob_status status) + struct bt_mesh_msg_ctx *ctx, + enum bt_mesh_blob_status status) { - enum bt_mesh_blob_chunks_missing format; - uint32_t missing; - int i; + enum bt_mesh_blob_chunks_missing format; + uint32_t missing; + int i; - BT_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_STATUS, - BLOB_BLOCK_STATUS_MSG_MAXLEN); - bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_BLOB_OP_BLOCK_STATUS, + BLOB_BLOCK_STATUS_MSG_MAXLEN); + bt_mesh_model_msg_init(&buf, BT_MESH_BLOB_OP_BLOCK_STATUS); - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || - srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { - missing = srv->block.chunk_count; - } else if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE) { - missing = 0U; - } else { - missing = missing_chunks(&srv->block); - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || + srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + missing = srv->block.chunk_count; + } else if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE) { + missing = 0U; + } else { + missing = missing_chunks(&srv->block); + } - if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { - format = BT_MESH_BLOB_CHUNKS_MISSING_ENCODED; - } else if (missing == srv->block.chunk_count) { - format = BT_MESH_BLOB_CHUNKS_MISSING_ALL; - } else if (missing == 0) { - format = BT_MESH_BLOB_CHUNKS_MISSING_NONE; - } else { - format = BT_MESH_BLOB_CHUNKS_MISSING_SOME; - } + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + format = BT_MESH_BLOB_CHUNKS_MISSING_ENCODED; + } else if (missing == srv->block.chunk_count) { + format = BT_MESH_BLOB_CHUNKS_MISSING_ALL; + } else if (missing == 0) { + format = BT_MESH_BLOB_CHUNKS_MISSING_NONE; + } else { + format = BT_MESH_BLOB_CHUNKS_MISSING_SOME; + } - LOG_DBG("Status: %u, missing: %u/%u", status, missing, srv->block.chunk_count); + BT_DBG("Status: %u, missing: %u/%u", status, missing, srv->block.chunk_count); - net_buf_simple_add_u8(&buf, (status & BIT_MASK(4)) | (format << 6)); - net_buf_simple_add_le16(&buf, srv->block.number); - net_buf_simple_add_le16(&buf, srv->state.xfer.chunk_size); + net_buf_simple_add_u8(&buf, (status & BIT_MASK(4)) | (format << 6)); + net_buf_simple_add_le16(&buf, srv->block.number); + net_buf_simple_add_le16(&buf, srv->state.xfer.chunk_size); - if (format == BT_MESH_BLOB_CHUNKS_MISSING_SOME) { - net_buf_simple_add_mem(&buf, srv->block.missing, - DIV_ROUND_UP(srv->block.chunk_count, - 8)); + if (format == BT_MESH_BLOB_CHUNKS_MISSING_SOME) { + net_buf_simple_add_mem(&buf, srv->block.missing, + DIV_ROUND_UP(srv->block.chunk_count, + 8)); - LOG_DBG("Bits: %s", - bt_hex(srv->block.missing, - DIV_ROUND_UP(srv->block.chunk_count, 8))); + BT_DBG("Bits: %s", + bt_hex(srv->block.missing, + DIV_ROUND_UP(srv->block.chunk_count, 8))); - } else if (format == BT_MESH_BLOB_CHUNKS_MISSING_ENCODED) { - int count = pull_req_max(srv); + } else if (format == BT_MESH_BLOB_CHUNKS_MISSING_ENCODED) { + int count = pull_req_max(srv); - for (i = 0; (i < srv->block.chunk_count) && count; ++i) { - if (blob_chunk_missing_get(srv->block.missing, i)) { - LOG_DBG("Missing %u", i); - buf_chunk_index_add(&buf, i); - count--; - } - } - } + for (i = 0; (i < srv->block.chunk_count) && count; ++i) { + if (blob_chunk_missing_get(srv->block.missing, i)) { + BT_DBG("Missing %u", i); + buf_chunk_index_add(&buf, i); + count--; + } + } + } - if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { - ctx->send_ttl = srv->state.ttl; - } + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + ctx->send_ttl = srv->state.ttl; + } - (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); + (void)bt_mesh_model_send(srv->mod, ctx, &buf, NULL, NULL); } -static int handle_xfer_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) +static int handle_xfer_get(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->rt->user_data; + struct bt_mesh_blob_srv *srv = mod->user_data; - LOG_DBG(""); + BT_DBG(""); - if (pull_mode_xfer_complete(srv)) { - /* The client requested transfer. If we are in Pull mode and all blocks were - * received, we should change the Transfer state here to Complete so that the client - * receives the correct state. - */ - end(srv); - } + if (pull_mode_xfer_complete(srv)) { + /* The client requested transfer. If we are in Pull mode and all blocks were + * received, we should change the Transfer state here to Complete so that the client + * receives the correct state. + */ + end(srv); + } - xfer_status_rsp(srv, ctx, BT_MESH_BLOB_SUCCESS); + xfer_status_rsp(srv, ctx, BT_MESH_BLOB_SUCCESS); - return 0; + return 0; } static int handle_xfer_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->rt->user_data; - enum bt_mesh_blob_status status; - enum bt_mesh_blob_xfer_mode mode; - uint64_t id; - size_t size; - uint8_t block_size_log; - uint32_t block_count; - uint16_t mtu_size; - int err; + struct bt_mesh_blob_srv *srv = mod->user_data; + enum bt_mesh_blob_status status; + enum bt_mesh_blob_xfer_mode mode; + uint64_t id; + size_t size; + uint8_t block_size_log; + uint32_t block_count; + uint16_t mtu_size; + int err; - mode = (net_buf_simple_pull_u8(buf) >> 6); - id = net_buf_simple_pull_le64(buf); - size = net_buf_simple_pull_le32(buf); - block_size_log = net_buf_simple_pull_u8(buf); - mtu_size = net_buf_simple_pull_le16(buf); + mode = (net_buf_simple_pull_u8(buf) >> 6); + id = net_buf_simple_pull_le64(buf); + size = net_buf_simple_pull_le32(buf); + block_size_log = net_buf_simple_pull_u8(buf); + mtu_size = net_buf_simple_pull_le16(buf); - LOG_DBG("\n\tsize: %u block size: %u\n\tmtu_size: %u\n\tmode: %s", - size, (1U << block_size_log), mtu_size, - mode == BT_MESH_BLOB_XFER_MODE_PUSH ? "push" : "pull"); + BT_INFO("size: %u block size: %u mtu_size: %u mode: %s", + size, (1U << block_size_log), mtu_size, + mode == BT_MESH_BLOB_XFER_MODE_PUSH ? "push" : "pull"); - if (mode != BT_MESH_BLOB_XFER_MODE_PULL && - mode != BT_MESH_BLOB_XFER_MODE_PUSH) { - LOG_WRN("Invalid mode 0x%x", mode); - return -EINVAL; - } + if (mode != BT_MESH_BLOB_XFER_MODE_PULL && + mode != BT_MESH_BLOB_XFER_MODE_PUSH) { + BT_WARN("Invalid mode 0x%x", mode); + return -EINVAL; + } - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { - status = BT_MESH_BLOB_ERR_WRONG_PHASE; - LOG_WRN("Uninitialized"); - goto rsp; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + BT_WARN("Uninitialized"); + goto rsp; + } - if (srv->state.xfer.id != id) { - status = BT_MESH_BLOB_ERR_WRONG_BLOB_ID; - /* bt_hex uses static array for the resulting hex string. - * Not possible to use bt_hex in the same logging function twice. - */ - LOG_WRN("Invalid ID: %s", bt_hex(&id, sizeof(uint64_t))); - LOG_WRN("Expected ID: %s", bt_hex(&srv->state.xfer.id, sizeof(uint64_t))); - goto rsp; - } +#if 0 /* For case DFU/SR/FD/BV-59-C, workaround */ + srv->state.xfer.id = id; +#endif - if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { - if (srv->state.xfer.mode != mode || - srv->state.xfer.size != size || - srv->state.xfer.block_size_log != block_size_log || - srv->state.mtu_size > mtu_size) { - status = BT_MESH_BLOB_ERR_WRONG_PHASE; - LOG_WRN("Busy"); - goto rsp; - } + if (srv->state.xfer.id != id) { + status = BT_MESH_BLOB_ERR_WRONG_BLOB_ID; + /* bt_hex uses static array for the resulting hex string. + * Not possible to use bt_hex in the same logging function twice. + */ + BT_WARN("Invalid ID: %s", bt_hex(&id, sizeof(uint64_t))); + BT_WARN("Expected ID: %s", bt_hex(&srv->state.xfer.id, sizeof(uint64_t))); + goto rsp; + } - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) { - resume(srv); - store_state(srv); - } else { - LOG_DBG("Duplicate"); - } + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + if (srv->state.xfer.mode != mode || + srv->state.xfer.size != size || + srv->state.xfer.block_size_log != block_size_log || + srv->state.mtu_size > mtu_size) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + BT_WARN("Busy"); + goto rsp; + } - status = BT_MESH_BLOB_SUCCESS; - goto rsp; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) { + resume(srv); + store_state(srv); + } else { + BT_DBG("Duplicate"); + } - if (size > CONFIG_BT_MESH_BLOB_SIZE_MAX) { - LOG_WRN("Too large"); - status = BT_MESH_BLOB_ERR_BLOB_TOO_LARGE; - goto rsp; - } + status = BT_MESH_BLOB_SUCCESS; + goto rsp; + } - if (((1U << block_size_log) < CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MIN) || - ((1U << block_size_log) > CONFIG_BT_MESH_BLOB_BLOCK_SIZE_MAX)) { - LOG_WRN("Invalid block size: %u", block_size_log); - status = BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE; - goto rsp; - } + if (size > CONFIG_BLE_MESH_BLOB_SIZE_MAX) { + BT_WARN("Too large"); + status = BT_MESH_BLOB_ERR_BLOB_TOO_LARGE; + goto rsp; + } - srv->state.cli = ctx->addr; - srv->state.app_idx = ctx->app_idx; - srv->state.mtu_size = MIN(mtu_size, MTU_SIZE_MAX); - srv->state.xfer.id = id; - srv->state.xfer.size = size; - srv->state.xfer.mode = mode; - srv->state.xfer.block_size_log = block_size_log; - srv->state.xfer.chunk_size = 0xffff; - srv->block.number = 0xffff; + if (((1U << block_size_log) < CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MIN) || + ((1U << block_size_log) > CONFIG_BLE_MESH_BLOB_BLOCK_SIZE_MAX)) { + BT_WARN("Invalid block size: %u", block_size_log); + status = BT_MESH_BLOB_ERR_INVALID_BLOCK_SIZE; + goto rsp; + } - block_count = block_count_get(srv); - if (block_count > BT_MESH_BLOB_BLOCKS_MAX) { - LOG_WRN("Invalid block count (%u)", block_count); - status = BT_MESH_BLOB_ERR_INVALID_PARAM; - cancel(srv); - goto rsp; - } + srv->state.cli = ctx->addr; + srv->state.app_idx = ctx->app_idx; + srv->state.mtu_size = MIN(mtu_size, MTU_SIZE_MAX); + srv->state.xfer.id = id; + srv->state.xfer.size = size; + srv->state.xfer.mode = mode; + srv->state.xfer.block_size_log = block_size_log; + srv->state.xfer.chunk_size = 0xffff; + srv->block.number = 0xffff; - memset(srv->state.blocks, 0, sizeof(srv->state.blocks)); - for (int i = 0; i < block_count; i++) { - atomic_set_bit(srv->state.blocks, i); - } + block_count = block_count_get(srv); + if (block_count > BT_MESH_BLOB_BLOCKS_MAX) { + BT_WARN("Invalid block count (%u)", block_count); + status = BT_MESH_BLOB_ERR_INVALID_PARAM; + cancel(srv); + goto rsp; + } - err = io_open(srv); - if (err) { - LOG_ERR("Couldn't open stream (err: %d)", err); - status = BT_MESH_BLOB_ERR_INTERNAL; - cancel(srv); - goto rsp; - } + memset(srv->state.blocks, 0, sizeof(srv->state.blocks)); + for (int i = 0; i < block_count; i++) { + bt_mesh_atomic_set_bit(srv->state.blocks, i); + } - if (srv->cb && srv->cb->start) { - err = srv->cb->start(srv, ctx, &srv->state.xfer); - if (err) { - LOG_ERR("Couldn't start transfer (err: %d)", err); - status = BT_MESH_BLOB_ERR_INTERNAL; - cancel(srv); - goto rsp; - } - } + err = io_open(srv); + if (err) { + BT_ERR("Couldn't open stream (err: %d)", err); + status = BT_MESH_BLOB_ERR_INTERNAL; + cancel(srv); + goto rsp; + } - reset_timer(srv); - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); - store_state(srv); - status = BT_MESH_BLOB_SUCCESS; + if (srv->cb && srv->cb->start) { + err = srv->cb->start(srv, ctx, &srv->state.xfer); + if (err) { + BT_ERR("Couldn't start transfer (err: %d)", err); + status = BT_MESH_BLOB_ERR_INTERNAL; + cancel(srv); + goto rsp; + } + } + + reset_timer(srv); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); + store_state(srv); + status = BT_MESH_BLOB_SUCCESS; rsp: - xfer_status_rsp(srv, ctx, status); + xfer_status_rsp(srv, ctx, status); - return 0; + return 0; } static int handle_xfer_cancel(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - enum bt_mesh_blob_status status = BT_MESH_BLOB_SUCCESS; - struct bt_mesh_blob_srv *srv = mod->rt->user_data; - uint64_t id; + enum bt_mesh_blob_status status = BT_MESH_BLOB_SUCCESS; + struct bt_mesh_blob_srv *srv = mod->user_data; + uint64_t id; - id = net_buf_simple_pull_le64(buf); + id = net_buf_simple_pull_le64(buf); - LOG_DBG("%u", (uint32_t)id); + BT_DBG("%u", (uint32_t)id); - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { - goto rsp; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + goto rsp; + } - if (srv->state.xfer.id != id) { - status = BT_MESH_BLOB_ERR_WRONG_BLOB_ID; - goto rsp; - } + if (srv->state.xfer.id != id) { + status = BT_MESH_BLOB_ERR_WRONG_BLOB_ID; + goto rsp; + } - cancel(srv); + cancel(srv); rsp: - xfer_status_rsp(srv, ctx, status); + xfer_status_rsp(srv, ctx, status); - return 0; + return 0; } static int handle_block_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - enum bt_mesh_blob_status status; - struct bt_mesh_blob_srv *srv = mod->rt->user_data; + enum bt_mesh_blob_status status; + struct bt_mesh_blob_srv *srv = mod->user_data; - switch (srv->phase) { - case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK: - case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK: - case BT_MESH_BLOB_XFER_PHASE_COMPLETE: - status = BT_MESH_BLOB_SUCCESS; - break; - case BT_MESH_BLOB_XFER_PHASE_SUSPENDED: - status = BT_MESH_BLOB_ERR_INFO_UNAVAILABLE; - break; - case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START: - case BT_MESH_BLOB_XFER_PHASE_INACTIVE: - status = BT_MESH_BLOB_ERR_WRONG_PHASE; - break; - default: - status = BT_MESH_BLOB_ERR_INTERNAL; - break; - } + switch (srv->phase) { + case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK: + case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK: + case BT_MESH_BLOB_XFER_PHASE_COMPLETE: + status = BT_MESH_BLOB_SUCCESS; + break; + case BT_MESH_BLOB_XFER_PHASE_SUSPENDED: + status = BT_MESH_BLOB_ERR_INFO_UNAVAILABLE; + break; + case BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START: + case BT_MESH_BLOB_XFER_PHASE_INACTIVE: + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + break; + default: + status = BT_MESH_BLOB_ERR_INTERNAL; + break; + } - LOG_DBG(""); + BT_DBG(""); - block_status_rsp(srv, ctx, status); + block_status_rsp(srv, ctx, status); - return 0; + return 0; } static int handle_block_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->rt->user_data; - enum bt_mesh_blob_status status; - uint16_t block_number, chunk_size; - int err; + struct bt_mesh_blob_srv *srv = mod->user_data; + enum bt_mesh_blob_status status; + uint16_t block_number, chunk_size; + int err; - block_number = net_buf_simple_pull_le16(buf); - chunk_size = net_buf_simple_pull_le16(buf); + block_number = net_buf_simple_pull_le16(buf); + chunk_size = net_buf_simple_pull_le16(buf); - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START || - srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { - status = BT_MESH_BLOB_ERR_WRONG_PHASE; - goto rsp; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START || + srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + goto rsp; + } - reset_timer(srv); + reset_timer(srv); - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { - if (block_number != srv->block.number || - chunk_size != srv->state.xfer.chunk_size) { - status = BT_MESH_BLOB_ERR_WRONG_PHASE; - } else { - status = BT_MESH_BLOB_SUCCESS; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK) { + if (block_number != srv->block.number || + chunk_size != srv->state.xfer.chunk_size) { + status = BT_MESH_BLOB_ERR_WRONG_PHASE; + } else { + status = BT_MESH_BLOB_SUCCESS; + } - goto rsp; - } + goto rsp; + } - if (block_number >= block_count_get(srv)) { - status = BT_MESH_BLOB_ERR_INVALID_BLOCK_NUM; - goto rsp; - } + if (block_number >= block_count_get(srv)) { + status = BT_MESH_BLOB_ERR_INVALID_BLOCK_NUM; + goto rsp; + } - if (!chunk_size || chunk_size > max_chunk_size(srv) || - (DIV_ROUND_UP((1 << srv->state.xfer.block_size_log), chunk_size) > - max_chunk_count(srv))) { - LOG_WRN("Invalid chunk size: (chunk size: %u, max: %u, block log: %u, count: %u)", - chunk_size, max_chunk_size(srv), - srv->state.xfer.block_size_log, - max_chunk_count(srv)); - status = BT_MESH_BLOB_ERR_INVALID_CHUNK_SIZE; - goto rsp; - } + if (!chunk_size || chunk_size > max_chunk_size(srv) || + (DIV_ROUND_UP((1 << srv->state.xfer.block_size_log), chunk_size) > + max_chunk_count(srv))) { + BT_WARN("Invalid chunk size: (chunk size: %u, max: %u, block log: %u, count: %u)", + chunk_size, max_chunk_size(srv), + srv->state.xfer.block_size_log, + max_chunk_count(srv)); + status = BT_MESH_BLOB_ERR_INVALID_CHUNK_SIZE; + goto rsp; + } - srv->block.size = blob_block_size( - srv->state.xfer.size, srv->state.xfer.block_size_log, block_number); - srv->block.number = block_number; - srv->block.chunk_count = DIV_ROUND_UP(srv->block.size, chunk_size); - srv->state.xfer.chunk_size = chunk_size; - srv->block.offset = block_number * (1UL << srv->state.xfer.block_size_log); + srv->block.size = blob_block_size( + srv->state.xfer.size, srv->state.xfer.block_size_log, block_number); + srv->block.number = block_number; + srv->block.chunk_count = DIV_ROUND_UP(srv->block.size, chunk_size); + srv->state.xfer.chunk_size = chunk_size; + srv->block.offset = block_number * (1UL << srv->state.xfer.block_size_log); - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE || - !atomic_test_bit(srv->state.blocks, block_number)) { - memset(srv->block.missing, 0, sizeof(srv->block.missing)); - status = BT_MESH_BLOB_SUCCESS; - goto rsp; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE || + !bt_mesh_atomic_test_bit(srv->state.blocks, block_number)) { + memset(srv->block.missing, 0, sizeof(srv->block.missing)); + status = BT_MESH_BLOB_SUCCESS; + goto rsp; + } - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED && srv->cb && - srv->cb->resume) { - srv->cb->resume(srv); - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED && srv->cb && + srv->cb->resume) { + srv->cb->resume(srv); + } - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK); - blob_chunk_missing_set_all(&srv->block); + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) { + BT_INFO("Waiting nxt chunk to resume blob srv"); + } - LOG_DBG("%u: (%u/%u)\n\tsize: %u\n\tchunk size: %u\n\tchunk count: %u", - srv->block.number, srv->block.number + 1, block_count_get(srv), - srv->block.size, chunk_size, srv->block.chunk_count); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK); + blob_chunk_missing_set_all(&srv->block); - if (srv->io->block_start) { - err = srv->io->block_start(srv->io, &srv->state.xfer, - &srv->block); - if (err) { - cancel(srv); - status = BT_MESH_BLOB_ERR_INTERNAL; - goto rsp; - } - } + BT_WARN("%u: (%u/%u)\n\tsize: %u\n\tchunk size: %u\n\tchunk count: %u", + srv->block.number, srv->block.number + 1, block_count_get(srv), + srv->block.size, chunk_size, srv->block.chunk_count); - if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { - /* Wait for the client to send the first chunk */ - k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); - } + if (srv->io->block_start) { + err = srv->io->block_start(srv->io, &srv->state.xfer, + &srv->block); + if (err) { + cancel(srv); + status = BT_MESH_BLOB_ERR_INTERNAL; + goto rsp; + } + } - status = BT_MESH_BLOB_SUCCESS; + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + /* Wait for the client to send the first chunk */ + k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); + } + + status = BT_MESH_BLOB_SUCCESS; rsp: - block_status_rsp(srv, ctx, status); + block_status_rsp(srv, ctx, status); - return 0; + return 0; } -static int handle_chunk(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) +static int handle_chunk(struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->rt->user_data; - struct bt_mesh_blob_chunk chunk; - size_t expected_size = 0; - uint16_t idx; - int err; + struct bt_mesh_blob_srv *srv = mod->user_data; + struct bt_mesh_blob_chunk chunk; + size_t expected_size = 0; + uint16_t idx; + int err; - idx = net_buf_simple_pull_le16(buf); - chunk.size = buf->len; - chunk.data = net_buf_simple_pull_mem(buf, chunk.size); - chunk.offset = idx * srv->state.xfer.chunk_size; + idx = net_buf_simple_pull_le16(buf); + chunk.size = buf->len; + chunk.data = net_buf_simple_pull_mem(buf, chunk.size); + chunk.offset = idx * srv->state.xfer.chunk_size; - if (srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK || - idx >= srv->block.chunk_count) { - LOG_ERR("Invalid phase or index (%u %u)", srv->phase, - idx); - return -EINVAL; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK || + srv->phase == BT_MESH_BLOB_XFER_PHASE_COMPLETE) { + // This Block is already complete received. + BT_INFO("Discord chunk(%d), because the block is already received", idx); + return -EINVAL; + } + /** + * Changed by Espressif. + * This behavior is not allowed by spec! + * + * Change resason: + * If the former chunk lost and the following received chunks + * all will be drop, so this change is therefore used to + * avoid such waste. + * + */ + if ((srv->phase != BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK && + srv->phase != BT_MESH_BLOB_XFER_PHASE_SUSPENDED) || + idx >= srv->block.chunk_count) { + BT_ERR("Invalid phase or index (%u %u)", srv->phase, + idx); + return -EINVAL; + } - if (idx == srv->block.chunk_count - 1) { - expected_size = srv->block.size % srv->state.xfer.chunk_size; - } + if (idx == srv->block.chunk_count - 1) { + expected_size = srv->block.size % srv->state.xfer.chunk_size; + } - if (expected_size == 0) { - expected_size = srv->state.xfer.chunk_size; - } + if (expected_size == 0) { + expected_size = srv->state.xfer.chunk_size; + } - if (chunk.size != expected_size) { - LOG_ERR("Unexpected size: %u != %u", expected_size, chunk.size); - return -EINVAL; - } + if (chunk.size != expected_size) { + BT_ERR("Unexpected size: %u != %u", expected_size, chunk.size); + return -EINVAL; + } - LOG_DBG("%u/%u (%u bytes)", idx + 1, srv->block.chunk_count, - chunk.size); + /** + * Changed By Espressif. + * + * The blob server should resume if received a new chunk + * after suspend (that's behavior is not required by spec). + * + * Change resason: + * The blob server will be suspend after a chunk missed + * and resume at next block start received. + * but a block get will be received before a block start + * sent, the blob server which in suspend state will response + * a err state to blob client,and the blob client will drop + * that blob server, causing the server couldn't receive + * complete. + */ + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_SUSPENDED) { + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_CHUNK); + } - reset_timer(srv); - if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { - k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); - } + BT_INFO("%u/%u (%u bytes)", idx + 1, srv->block.chunk_count, + chunk.size); - if (!blob_chunk_missing_get(srv->block.missing, idx)) { - LOG_DBG("Duplicate chunk %u", idx); - return -EALREADY; - } + reset_timer(srv); + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + k_work_reschedule(&srv->pull.report, REPORT_TIMER_TIMEOUT); + } - err = srv->io->wr(srv->io, &srv->state.xfer, &srv->block, &chunk); - if (err) { - return err; - } + if (!blob_chunk_missing_get(srv->block.missing, idx)) { + BT_DBG("Duplicate chunk %u", idx); + return -EALREADY; + } - blob_chunk_missing_set(srv->block.missing, idx, false); - if (missing_chunks(&srv->block)) { - return 0; - } + err = srv->io->wr(srv->io, &srv->state.xfer, &srv->block, &chunk); + if (err) { + return err; + } - if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { - block_report(srv); - } + blob_chunk_missing_set(srv->block.missing, idx, false); + if (missing_chunks(&srv->block)) { + return 0; + } - if (srv->io->block_end) { - srv->io->block_end(srv->io, &srv->state.xfer, &srv->block); - } + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + block_report(srv); + } - atomic_clear_bit(srv->state.blocks, srv->block.number); + if (srv->io->block_end) { + srv->io->block_end(srv->io, &srv->state.xfer, &srv->block); + } - if (!all_blocks_received(srv)) { - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); - store_state(srv); - return 0; - } + bt_mesh_atomic_clear_bit(srv->state.blocks, srv->block.number); - if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { - /* By spec (section 5.2.4), the BLOB Server stops sending BLOB Partial Block Report - * messages "If the current block is the last block, then the server determines that - * the client knows the transfer is complete. For example, a higher-layer model may - * indicate that the client considers the transfer complete." - * - * We don't have any way for higher-layer model to indicate that the transfer is - * complete. Therefore we need to keep sending Partial Block Report messages until - * the client sends BLOB Transfer Get message or the Block Timer expires. - */ - return 0; - } + if (!all_blocks_received(srv)) { + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_BLOCK); + store_state(srv); + return 0; + } - end(srv); - return 0; + if (srv->state.xfer.mode == BT_MESH_BLOB_XFER_MODE_PULL) { + /* By spec (section 5.2.4), the BLOB Server stops sending BLOB Partial Block Report + * messages "If the current block is the last block, then the server determines that + * the client knows the transfer is complete. For example, a higher-layer model may + * indicate that the client considers the transfer complete." + * + * We don't have any way for higher-layer model to indicate that the transfer is + * complete. Therefore we need to keep sending Partial Block Report messages until + * the client sends BLOB Transfer Get message or the Block Timer expires. + */ + return 0; + } + + end(srv); + return 0; } static int handle_info_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf) + struct net_buf_simple *buf) { - struct bt_mesh_blob_srv *srv = mod->rt->user_data; + struct bt_mesh_blob_srv *srv = mod->user_data; - LOG_DBG(""); + BT_DBG(""); - BT_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_BLOB_OP_INFO_STATUS, 15); - bt_mesh_model_msg_init(&rsp, BT_MESH_BLOB_OP_INFO_STATUS); - net_buf_simple_add_u8(&rsp, BLOB_BLOCK_SIZE_LOG_MIN); - net_buf_simple_add_u8(&rsp, BLOB_BLOCK_SIZE_LOG_MAX); - net_buf_simple_add_le16(&rsp, CONFIG_BT_MESH_BLOB_CHUNK_COUNT_MAX); - net_buf_simple_add_le16(&rsp, BLOB_RX_CHUNK_SIZE); - net_buf_simple_add_le32(&rsp, CONFIG_BT_MESH_BLOB_SIZE_MAX); - net_buf_simple_add_le16(&rsp, MTU_SIZE_MAX); - net_buf_simple_add_u8(&rsp, BT_MESH_BLOB_XFER_MODE_ALL); + BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_BLOB_OP_INFO_STATUS, 15); + bt_mesh_model_msg_init(&rsp, BT_MESH_BLOB_OP_INFO_STATUS); + net_buf_simple_add_u8(&rsp, BLOB_BLOCK_SIZE_LOG_MIN); + net_buf_simple_add_u8(&rsp, BLOB_BLOCK_SIZE_LOG_MAX); + net_buf_simple_add_le16(&rsp, CONFIG_BLE_MESH_BLOB_CHUNK_COUNT_MAX); + net_buf_simple_add_le16(&rsp, BLOB_RX_CHUNK_SIZE); + net_buf_simple_add_le32(&rsp, CONFIG_BLE_MESH_BLOB_SIZE_MAX); + net_buf_simple_add_le16(&rsp, MTU_SIZE_MAX); + net_buf_simple_add_u8(&rsp, BT_MESH_BLOB_XFER_MODE_ALL); - if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { - ctx->send_ttl = srv->state.ttl; - } + if (srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + ctx->send_ttl = srv->state.ttl; + } - (void)bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); + (void)bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); - return 0; + return 0; } const struct bt_mesh_model_op _bt_mesh_blob_srv_op[] = { - { BT_MESH_BLOB_OP_XFER_GET, BT_MESH_LEN_EXACT(0), handle_xfer_get }, - { BT_MESH_BLOB_OP_XFER_START, BT_MESH_LEN_EXACT(16), handle_xfer_start }, - { BT_MESH_BLOB_OP_XFER_CANCEL, BT_MESH_LEN_EXACT(8), handle_xfer_cancel }, - { BT_MESH_BLOB_OP_BLOCK_GET, BT_MESH_LEN_EXACT(0), handle_block_get }, - { BT_MESH_BLOB_OP_BLOCK_START, BT_MESH_LEN_EXACT(4), handle_block_start }, - { BT_MESH_BLOB_OP_CHUNK, BT_MESH_LEN_MIN(2), handle_chunk }, - { BT_MESH_BLOB_OP_INFO_GET, BT_MESH_LEN_EXACT(0), handle_info_get }, - BT_MESH_MODEL_OP_END, + { BT_MESH_BLOB_OP_XFER_GET, 0, (void *)handle_xfer_get }, + { BT_MESH_BLOB_OP_XFER_START, 16, (void *)handle_xfer_start }, + { BT_MESH_BLOB_OP_XFER_CANCEL, 8, (void *)handle_xfer_cancel }, + { BT_MESH_BLOB_OP_BLOCK_GET, 0, (void *)handle_block_get }, + { BT_MESH_BLOB_OP_BLOCK_START, 4, (void *)handle_block_start }, + { BT_MESH_BLOB_OP_CHUNK, 2, (void *)handle_chunk }, + { BT_MESH_BLOB_OP_INFO_GET, 0, (void *)handle_info_get }, + BLE_MESH_MODEL_OP_END, }; -static int blob_srv_init(const struct bt_mesh_model *mod) +static int blob_srv_init(struct bt_mesh_model *mod) { - struct bt_mesh_blob_srv *srv = mod->rt->user_data; + struct bt_mesh_blob_srv *srv = mod->user_data; - srv->mod = mod; - srv->state.ttl = BT_MESH_TTL_DEFAULT; - srv->block.number = 0xffff; - srv->state.xfer.chunk_size = 0xffff; - k_work_init_delayable(&srv->rx_timeout, timeout); - k_work_init_delayable(&srv->pull.report, report_timeout); + srv->mod = mod; + srv->state.ttl = BLE_MESH_TTL_DEFAULT; + srv->block.number = 0xffff; + srv->state.xfer.chunk_size = 0xffff; + k_work_init_delayable(&srv->rx_timeout, timeout); + k_work_init_delayable(&srv->pull.report, report_timeout); - return 0; + return 0; } +__attribute__((unused)) static int blob_srv_settings_set(const struct bt_mesh_model *mod, const char *name, - size_t len_rd, settings_read_cb read_cb, - void *cb_arg) + size_t len_rd, settings_read_cb read_cb, + void *cb_arg) { - struct bt_mesh_blob_srv *srv = mod->rt->user_data; - ssize_t len; + struct bt_mesh_blob_srv *srv = mod->user_data; + ssize_t len; - if (len_rd < offsetof(struct bt_mesh_blob_srv_state, blocks)) { - return -EINVAL; - } + if (len_rd < offsetof(struct bt_mesh_blob_srv_state, blocks)) { + return -EINVAL; + } - len = read_cb(cb_arg, &srv->state, sizeof(srv->state)); - if (len < 0) { - return len; - } + len = read_cb(cb_arg, &srv->state, sizeof(srv->state)); + if (len < 0) { + return len; + } - srv->block.number = 0xffff; - srv->state.xfer.chunk_size = 0xffff; + srv->block.number = 0xffff; + srv->state.xfer.chunk_size = 0xffff; - if (block_count_get(srv) > BT_MESH_BLOB_BLOCKS_MAX) { - LOG_WRN("Loaded block count too high (%u, max: %u)", - block_count_get(srv), BT_MESH_BLOB_BLOCKS_MAX); - return 0; - } + if (block_count_get(srv) > BT_MESH_BLOB_BLOCKS_MAX) { + BT_WARN("Loaded block count too high (%u, max: %u)", + block_count_get(srv), BT_MESH_BLOB_BLOCKS_MAX); + return 0; + } - /* If device restarted before it handled `XFER_START` server we restore state into - * BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START phase, so `XFER_START` can be accepted - * as it would before reboot - */ - if (srv->state.cli == BT_MESH_ADDR_UNASSIGNED) { - LOG_DBG("Transfer (id=%llu) waiting for start", srv->state.xfer.id); - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START); - } else { - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_SUSPENDED); + /* If device restarted before it handled `XFER_START` server we restore state into + * BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START phase, so `XFER_START` can be accepted + * as it would before reboot + */ + if (srv->state.cli == BLE_MESH_ADDR_UNASSIGNED) { + BT_DBG("Transfer (id=%llu) waiting for start", srv->state.xfer.id); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START); + } else { + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_SUSPENDED); - LOG_DBG("Recovered transfer from 0x%04x (%llu)", srv->state.cli, - srv->state.xfer.id); - } + BT_DBG("Recovered transfer from 0x%04x (%llu)", srv->state.cli, + srv->state.xfer.id); + } - return 0; + return 0; } +__attribute__((unused)) static int blob_srv_start(const struct bt_mesh_model *mod) { - struct bt_mesh_blob_srv *srv = mod->rt->user_data; - int err = -ENOTSUP; + struct bt_mesh_blob_srv *srv = mod->user_data; + int err = -ENOTSUP; - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { - return 0; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE) { + return 0; + } - if (srv->cb && srv->cb->recover) { - srv->io = NULL; - err = srv->cb->recover(srv, &srv->state.xfer, &srv->io); - if (!err && srv->io) { - err = io_open(srv); - } - } + if (srv->cb && srv->cb->recover) { + srv->io = NULL; + err = srv->cb->recover(srv, &srv->state.xfer, &srv->io); + if (!err && srv->io) { + err = io_open(srv); + } + } - if (err || !srv->io) { - LOG_WRN("Abandoning transfer."); - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); - srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; - srv->state.ttl = BT_MESH_TTL_DEFAULT; - erase_state(srv); - } + if (err || !srv->io) { + BT_WARN("Abandoning transfer."); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); + srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; + srv->state.ttl = BLE_MESH_TTL_DEFAULT; + erase_state(srv); + } - return 0; + return 0; } -static void blob_srv_reset(const struct bt_mesh_model *mod) +static void blob_srv_reset(struct bt_mesh_model *mod) { - struct bt_mesh_blob_srv *srv = mod->rt->user_data; + struct bt_mesh_blob_srv *srv = mod->user_data; - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); - srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; - k_work_cancel_delayable(&srv->rx_timeout); - k_work_cancel_delayable(&srv->pull.report); - erase_state(srv); + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_INACTIVE); + srv->state.xfer.mode = BT_MESH_BLOB_XFER_MODE_NONE; + k_work_cancel_delayable(&srv->rx_timeout); + k_work_cancel_delayable(&srv->pull.report); + erase_state(srv); +} + +static int blob_srv_deinit(struct bt_mesh_model *mod) +{ + blob_srv_reset(mod); + return 0; } const struct bt_mesh_model_cb _bt_mesh_blob_srv_cb = { - .init = blob_srv_init, - .settings_set = blob_srv_settings_set, - .start = blob_srv_start, - .reset = blob_srv_reset, + .init = blob_srv_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = blob_srv_deinit, +#endif }; int bt_mesh_blob_srv_recv(struct bt_mesh_blob_srv *srv, uint64_t id, - const struct bt_mesh_blob_io *io, uint8_t ttl, - uint16_t timeout_base) + const struct bt_mesh_blob_io *io, uint8_t ttl, + uint16_t timeout_base) { - if (bt_mesh_blob_srv_is_busy(srv)) { - return -EBUSY; - } + if (bt_mesh_blob_srv_is_busy(srv)) { + return -EBUSY; + } - if (!io || !io->wr) { - return -EINVAL; - } + if (!io || !io->wr) { + return -EINVAL; + } - srv->state.xfer.id = id; - srv->state.ttl = ttl; - srv->state.timeout_base = timeout_base; - srv->io = io; - srv->block.number = 0xffff; - srv->state.xfer.chunk_size = 0xffff; - phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START); - store_state(srv); + srv->state.xfer.id = id; + srv->state.ttl = ttl; + srv->state.timeout_base = timeout_base; + srv->io = io; + srv->block.number = 0xffff; + srv->state.xfer.chunk_size = 0xffff; + phase_set(srv, BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START); + store_state(srv); - return 0; + return 0; } int bt_mesh_blob_srv_cancel(struct bt_mesh_blob_srv *srv) { - if (!bt_mesh_blob_srv_is_busy(srv)) { - return -EALREADY; - } + if (!bt_mesh_blob_srv_is_busy(srv)) { + return -EALREADY; + } - cancel(srv); + cancel(srv); - return 0; + return 0; } bool bt_mesh_blob_srv_is_busy(const struct bt_mesh_blob_srv *srv) { - return srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE && - srv->phase != BT_MESH_BLOB_XFER_PHASE_SUSPENDED && - srv->phase != BT_MESH_BLOB_XFER_PHASE_COMPLETE; + return srv->phase != BT_MESH_BLOB_XFER_PHASE_INACTIVE && + srv->phase != BT_MESH_BLOB_XFER_PHASE_SUSPENDED && + srv->phase != BT_MESH_BLOB_XFER_PHASE_COMPLETE; } uint8_t bt_mesh_blob_srv_progress(const struct bt_mesh_blob_srv *srv) { - uint32_t total; - uint32_t received; + uint32_t total; + uint32_t received; - if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || - srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { - return 0; - } + if (srv->phase == BT_MESH_BLOB_XFER_PHASE_INACTIVE || + srv->phase == BT_MESH_BLOB_XFER_PHASE_WAITING_FOR_START) { + return 0; + } - total = block_count_get(srv); + total = block_count_get(srv); - received = 0; - for (int i = 0; i < total; ++i) { - if (!atomic_test_bit(srv->state.blocks, i)) { - received++; - } - } + received = 0; + for (int i = 0; i < total; ++i) { + if (!bt_mesh_atomic_test_bit(srv->state.blocks, i)) { + received++; + } + } - return (100U * received) / total; + return (100U * received) / total; } + +#endif /* CONFIG_BLE_MESH_BLOB_SRV */ diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index a81b73bb74..49f700f026 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -46,6 +46,8 @@ INPUT = \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_rpr_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_sar_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/core/include/esp_ble_mesh_srpl_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h \ + $(PROJECT_PATH)/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_slot_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_config_model_api.h \ $(PROJECT_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_generic_model_api.h \ diff --git a/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst b/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst index 5955646296..b83b6059ff 100644 --- a/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst +++ b/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst @@ -29,6 +29,7 @@ Mesh Core * Private Beacon * Subnet Bridge * Minor Enhancements + * Device Firmware Update (Preview) * Multiple Client Models Run Simultaneously * Support multiple client models send packets to different nodes simultaneously @@ -132,6 +133,14 @@ Mesh Models * Light LC Server * Light LC Setup Server +* Device Firmware Update Client models + * Firmware Update Client model (Preview) + * Firmware Distribution Client model (coming soon) +* Device Firmware Update Server models + * Firmware Update Server model (Preview) + * Firmware Distribution Server model (coming soon) + + Mesh Examples """"""""""""" diff --git a/docs/en/api-reference/bluetooth/esp-ble-mesh.rst b/docs/en/api-reference/bluetooth/esp-ble-mesh.rst index 35de1143e5..03e522c3bf 100644 --- a/docs/en/api-reference/bluetooth/esp-ble-mesh.rst +++ b/docs/en/api-reference/bluetooth/esp-ble-mesh.rst @@ -228,3 +228,12 @@ Composition and Metadata ^^^^^^^^^^^^^^^^^^^^^^^^ .. include-build-file:: inc/esp_ble_mesh_cm_data_api.inc + +Device Firmware Update + +.. include-build-file:: inc/esp_ble_mesh_dfu_model_api.inc + +Device Firmware Slots + +.. include-build-file:: inc/esp_ble_mesh_dfu_slot_api.inc + From e71a79f6798426d5dfba7ac0bf7382de296d895c Mon Sep 17 00:00:00 2001 From: luoxu Date: Mon, 11 Aug 2025 15:17:55 +0800 Subject: [PATCH 139/156] fix(bt): Fixed the issue of duplicate MAX macro definitions --- components/bt/common/include/bt_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/bt/common/include/bt_common.h b/components/bt/common/include/bt_common.h index d8fb107878..f687e3afe7 100644 --- a/components/bt/common/include/bt_common.h +++ b/components/bt/common/include/bt_common.h @@ -141,7 +141,9 @@ #define LOG_LOCAL_LEVEL_MAPPING LOG_LOCAL_LEVEL #endif +#ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif #define BT_LOG_LEVEL_CHECK(LAYER, LEVEL) (MAX(LAYER##_INITIAL_TRACE_LEVEL, LOG_LOCAL_LEVEL_MAPPING) >= BT_TRACE_LEVEL_##LEVEL) From 16d9fcf4605cf77a6e3b48322fc1298aa895ca8c Mon Sep 17 00:00:00 2001 From: luoxu Date: Sun, 30 Nov 2025 17:15:01 +0800 Subject: [PATCH 140/156] feat(ble_mesh): dfd client/server supported --- components/bt/CMakeLists.txt | 2 + components/bt/common/btc/core/btc_task.c | 3 + .../bt/common/btc/include/btc/btc_task.h | 2 + components/bt/esp_ble_mesh/Kconfig.in | 47 + .../bt/esp_ble_mesh/api/esp_ble_mesh_defs.h | 3 +- .../bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c | 26 + .../btc/include/btc_ble_mesh_model_common.h | 68 +- .../api/models/esp_ble_mesh_dfu_model_api.c | 101 ++ .../include/esp_ble_mesh_dfu_model_api.h | 1055 ++++++++++++++++- .../v1.1/btc/btc_ble_mesh_dfu_model.c | 810 ++++++++++++- .../v1.1/btc/include/btc_ble_mesh_dfu_model.h | 49 + components/bt/esp_ble_mesh/v1.1/dfu/dfd.h | 35 - components/bt/esp_ble_mesh/v1.1/dfu/dfd_cli.c | 699 +++++++++++ components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c | 333 +++--- components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c | 6 +- .../v1.1/include/mesh_v1.1/dfu/dfd.h | 76 +- .../v1.1/include/mesh_v1.1/dfu/dfd_cli.h | 472 ++++++++ .../v1.1/include/mesh_v1.1/dfu/dfd_srv.h | 51 +- .../esp-ble-mesh/ble-mesh-feature-list.rst | 6 +- .../esp-ble-mesh/ble-mesh-feature-list.rst | 8 + 20 files changed, 3526 insertions(+), 326 deletions(-) delete mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfd.h create mode 100644 components/bt/esp_ble_mesh/v1.1/dfu/dfd_cli.c create mode 100644 components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_cli.h diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 7d4cc40fd3..cfd8eef05d 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -646,6 +646,8 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/v1.1/dfu/dfu_srv.c" "esp_ble_mesh/v1.1/dfu/dfu_slot.c" "esp_ble_mesh/v1.1/dfu/dfu_metadata.c" + "esp_ble_mesh/v1.1/dfu/dfd_srv.c" + "esp_ble_mesh/v1.1/dfu/dfd_cli.c" "esp_ble_mesh/lib/ext.c") if(CONFIG_BLE_MESH_SAR_ENHANCEMENT) list(APPEND srcs "esp_ble_mesh/core/transport.enh.c") diff --git a/components/bt/common/btc/core/btc_task.c b/components/bt/common/btc/core/btc_task.c index 3bc91c9659..9299015591 100644 --- a/components/bt/common/btc/core/btc_task.c +++ b/components/bt/common/btc/core/btc_task.c @@ -266,6 +266,9 @@ static const btc_func_t profile_tab[BTC_PID_NUM] = { #if CONFIG_BLE_MESH_DFU_CLI [BTC_PID_DFU_CLIENT] = {btc_ble_mesh_dfu_client_call_handler, btc_ble_mesh_dfu_client_cb_handler}, #endif /* CONFIG_BLE_MESH_DFU_CLI */ +#if CONFIG_BLE_MESH_DFD_CLI + [BTC_PID_DFD_CLIENT] = {btc_ble_mesh_dfd_client_call_handler, btc_ble_mesh_dfd_client_cb_handler}, +#endif /* CONFIG_BLE_MESH_DFD_CLI */ #if CONFIG_BLE_MESH_BLE_COEX_SUPPORT || CONFIG_BLE_MESH_USE_BLE_50 [BTC_PID_BLE_MESH_BLE_COEX] = {btc_ble_mesh_ble_call_handler, btc_ble_mesh_ble_cb_handler }, #endif /* CONFIG_BLE_MESH_BLE_COEX_SUPPORT || CONFIG_BLE_MESH_USE_BLE_50 */ diff --git a/components/bt/common/btc/include/btc/btc_task.h b/components/bt/common/btc/include/btc/btc_task.h index e87ce59311..5d17120180 100644 --- a/components/bt/common/btc/include/btc/btc_task.h +++ b/components/bt/common/btc/include/btc/btc_task.h @@ -110,6 +110,8 @@ typedef enum { BTC_PID_BLOB_SERVER, BTC_PID_DFU_CLIENT, BTC_PID_DFU_SERVER, + BTC_PID_DFD_CLIENT, + BTC_PID_DFD_SERVER, BTC_PID_BLE_MESH_BLE_COEX, #endif /* CONFIG_BLE_MESH */ #if (BLE_FEAT_ISO_EN == TRUE) diff --git a/components/bt/esp_ble_mesh/Kconfig.in b/components/bt/esp_ble_mesh/Kconfig.in index c1beb54857..e6c19f0e45 100644 --- a/components/bt/esp_ble_mesh/Kconfig.in +++ b/components/bt/esp_ble_mesh/Kconfig.in @@ -1862,6 +1862,53 @@ if BLE_MESH endif #BLE_MESH_DFU_SLOTS + config BLE_MESH_DFD_CLI + bool "Support for Device Distribution Client model" + help + Enable the Device Distribution Client model + + config BLE_MESH_DFD_SRV + bool "Support for Firmware Distribution Server model" + depends on BLE_MESH_BLOB_SRV + depends on BLE_MESH_DFU_CLI + help + Enable the Firmware Distribution Server model. + + if BLE_MESH_DFD_SRV + + config BLE_MESH_DFD_SRV_SLOT_MAX_SIZE + int "Largest DFU image that can be stored" + default BLE_MESH_BLOB_SIZE_MAX + range 0 BLE_MESH_BLOB_SIZE_MAX + help + This value defines the largest DFU image a single slot can store. + + config BLE_MESH_DFD_SRV_SLOT_SPACE + int "Total DFU image storage space" + default BLE_MESH_DFD_SRV_SLOT_MAX_SIZE + range 0 4294967295 + help + This value defines the total storage space dedicated to storing DFU + images on the Firmware Distribution Server. + + config BLE_MESH_DFD_SRV_TARGETS_MAX + int "Maximum Target node count" + default 8 + range 1 65535 + help + This value defines the maximum number of Target nodes the Firmware + Distribution Server can target simultaneously. + + config BLE_MESH_DFD_SRV_OOB_UPLOAD + bool "Support for DFU image OOB upload" + help + This enables support for OOB upload of firmware images for + distribution. This makes several callbacks and use of the init + macro BLE_MESH_DFD_SRV_INIT_OOB mandatory. See the API documentation + for bt_mesh_dfd_srv_cb for details about the mandatory callbacks. + + endif #BLE_MESH_DFD_SRV + endmenu # Device Firmware Update model endmenu #Support for BLE Mesh Client/Server models diff --git a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h index 8b7ff38ed7..01ade02668 100644 --- a/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h +++ b/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h @@ -1988,7 +1988,8 @@ typedef union { #define ESP_BLE_MESH_MODEL_ID_BLOB_CLI 0x1401 #define ESP_BLE_MESH_MODEL_ID_DFU_SRV 0x1402 #define ESP_BLE_MESH_MODEL_ID_DFU_CLI 0x1403 - +#define ESP_BLE_MESH_MODEL_ID_DFD_SRV 0x1404 +#define ESP_BLE_MESH_MODEL_ID_DFD_CLI 0x1405 /** * esp_ble_mesh_opcode_config_client_get_t belongs to esp_ble_mesh_opcode_t, this typedef is only * used to locate the opcodes used by esp_ble_mesh_config_client_get_state. diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c index babbdf5408..49ae1d5dda 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_prov.c @@ -1427,6 +1427,14 @@ extern const struct bt_mesh_model_cb _bt_mesh_dfu_srv_cb; extern const struct bt_mesh_model_op _bt_mesh_dfu_cli_op[]; extern const struct bt_mesh_model_cb _bt_mesh_dfu_cli_cb; #endif /* CONFIG_BLE_MESH_DFU_CLI */ +#if CONFIG_BLE_MESH_DFD_SRV +extern const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfd_srv_cb; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ +#if CONFIG_BLE_MESH_DFD_CLI +extern const struct bt_mesh_model_op _bt_mesh_dfd_cli_op[]; +extern const struct bt_mesh_model_cb _bt_mesh_dfd_cli_cb; +#endif /* CONFIG_BLE_MESH_DFD_CLI */ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) { @@ -2274,6 +2282,24 @@ static void btc_ble_mesh_model_op_set(esp_ble_mesh_model_t *model) } break; #endif /* CONFIG_BLE_MESH_DFU_SRV */ +#if CONFIG_BLE_MESH_DFD_SRV + case BLE_MESH_MODEL_ID_DFD_SRV: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfd_srv_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfd_srv_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ +#if CONFIG_BLE_MESH_DFD_CLI + case BLE_MESH_MODEL_ID_DFD_CLI: + model->op = (esp_ble_mesh_model_op_t *)_bt_mesh_dfd_cli_op; + model->cb = (esp_ble_mesh_model_cbs_t *)&_bt_mesh_dfd_cli_cb; + if (model->pub) { + model->pub->update = (esp_ble_mesh_cb_t)btc_ble_mesh_model_publish_update; + } + break; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ default: goto set_vnd_op; } diff --git a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h index 73b00db41f..66507a1bb2 100644 --- a/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h +++ b/components/bt/esp_ble_mesh/btc/include/btc_ble_mesh_model_common.h @@ -17,6 +17,45 @@ extern "C" { #endif +static inline void btc_ble_mesh_msg_ctx_copy(struct bt_mesh_msg_ctx *dst, + const struct bt_mesh_msg_ctx *src, + bool use_dev_key) +{ + if (dst == NULL || + src == NULL) { + return; + } + + dst->net_idx = src->net_idx; + dst->app_idx = use_dev_key ? BLE_MESH_KEY_DEV : src->app_idx; + dst->addr = src->addr; + dst->send_szmic = src->send_szmic; + dst->send_ttl = src->send_ttl; + dst->send_cred = src->send_cred; + dst->send_tag = src->send_tag; + if (src->enh.adv_cfg_used) { + dst->enh.adv_cfg_used = src->enh.adv_cfg_used; + dst->enh.adv_cfg.adv_cnt = src->enh.adv_cfg.adv_cnt; + dst->enh.adv_cfg.adv_itvl = src->enh.adv_cfg.adv_itvl; + dst->enh.adv_cfg.channel_map = src->enh.adv_cfg.channel_map; + } +#if CONFIG_BLE_MESH_EXT_ADV + if (src->enh.ext_adv_cfg_used) { + dst->enh.ext_adv_cfg_used = src->enh.ext_adv_cfg_used; + dst->enh.ext_adv_cfg.primary_phy = src->enh.ext_adv_cfg.primary_phy; + dst->enh.ext_adv_cfg.secondary_phy = src->enh.ext_adv_cfg.secondary_phy; + dst->enh.ext_adv_cfg.include_tx_power = src->enh.ext_adv_cfg.include_tx_power; + dst->enh.ext_adv_cfg.tx_power = src->enh.ext_adv_cfg.tx_power; + } +#if CONFIG_BLE_MESH_LONG_PACKET + if (src->enh.long_pkt_cfg_used) { + dst->enh.long_pkt_cfg_used = src->enh.long_pkt_cfg_used; + dst->enh.long_pkt_cfg = src->enh.long_pkt_cfg; + } +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ +} + static inline void btc_ble_mesh_set_client_common_param(esp_ble_mesh_client_common_param_t *input, bt_mesh_client_common_param_t *output, bool use_dev_key) @@ -24,35 +63,8 @@ static inline void btc_ble_mesh_set_client_common_param(esp_ble_mesh_client_comm if (input && output) { output->opcode = input->opcode; output->model = (struct bt_mesh_model *)input->model; - output->ctx.net_idx = input->ctx.net_idx; - output->ctx.app_idx = use_dev_key ? BLE_MESH_KEY_DEV : input->ctx.app_idx; - output->ctx.addr = input->ctx.addr; - output->ctx.send_szmic = input->ctx.send_szmic; - output->ctx.send_ttl = input->ctx.send_ttl; - output->ctx.send_cred = input->ctx.send_cred; - output->ctx.send_tag = input->ctx.send_tag; output->msg_timeout = input->msg_timeout; - if (input->ctx.enh.adv_cfg_used) { - output->ctx.enh.adv_cfg_used = input->ctx.enh.adv_cfg_used; - output->ctx.enh.adv_cfg.adv_cnt = input->ctx.enh.adv_cfg.adv_cnt; - output->ctx.enh.adv_cfg.adv_itvl = input->ctx.enh.adv_cfg.adv_itvl; - output->ctx.enh.adv_cfg.channel_map = input->ctx.enh.adv_cfg.channel_map; - } -#if CONFIG_BLE_MESH_EXT_ADV - if (input->ctx.enh.ext_adv_cfg_used) { - output->ctx.enh.ext_adv_cfg_used = input->ctx.enh.ext_adv_cfg_used; - output->ctx.enh.ext_adv_cfg.primary_phy = input->ctx.enh.ext_adv_cfg.primary_phy; - output->ctx.enh.ext_adv_cfg.secondary_phy = input->ctx.enh.ext_adv_cfg.secondary_phy; - output->ctx.enh.ext_adv_cfg.include_tx_power = input->ctx.enh.ext_adv_cfg.include_tx_power; - output->ctx.enh.ext_adv_cfg.tx_power = input->ctx.enh.ext_adv_cfg.tx_power; - } -#if CONFIG_BLE_MESH_LONG_PACKET - if (input->ctx.enh.long_pkt_cfg_used) { - output->ctx.enh.long_pkt_cfg_used = input->ctx.enh.long_pkt_cfg_used; - output->ctx.enh.long_pkt_cfg = input->ctx.enh.long_pkt_cfg; - } -#endif -#endif + btc_ble_mesh_msg_ctx_copy(&output->ctx, (const struct bt_mesh_msg_ctx *)&input->ctx, use_dev_key); } } diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c index feb082cd66..84110f8ade 100644 --- a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c +++ b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c @@ -146,3 +146,104 @@ uint8_t esp_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv) return btc_ble_mesh_dfu_srv_progress(srv); } #endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#if CONFIG_BLE_MESH_DFD_CLI + +esp_err_t esp_ble_mesh_register_dfd_cli_callback(esp_ble_mesh_dfd_client_cb_t callback) +{ + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + return (btc_profile_cb_set(BTC_PID_DFD_CLIENT, callback) == 0 ? ESP_OK : ESP_FAIL); +} + +static bool dfd_client_opcode_need_param(esp_ble_mesh_opcode_t opcode) +{ + switch (opcode) + { + /* Get opcode */ + case ESP_BLE_MESH_DFD_OP_RECEIVERS_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX: + /* Set opcode */ + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + case ESP_BLE_MESH_DFD_OP_START: + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + return true; + default: + return false; + } +} + +esp_err_t esp_ble_mesh_dfd_cli_get(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_get_param_t *get_param) +{ + btc_ble_mesh_dfd_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (dfd_client_opcode_need_param(params->opcode) && get_param == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DFD_CLIENT; + msg.act = ESP_BLE_MESH_ACT_DFD_CLIENT_GET; + arg.dfd_client_get.params = params; + arg.dfd_client_get.get = get_param; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfd_client_args_t), btc_ble_mesh_dfd_client_arg_deep_copy, + btc_ble_mesh_dfd_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} + +esp_err_t esp_ble_mesh_dfd_cli_set(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_set_param_t *set_param) +{ + btc_ble_mesh_dfd_client_args_t arg = {0}; + btc_msg_t msg = {0}; + + if (params == NULL || params->model == NULL || + params->ctx.net_idx == ESP_BLE_MESH_KEY_UNUSED || + !ESP_BLE_MESH_ADDR_IS_UNICAST(params->ctx.addr) || + (dfd_client_opcode_need_param(params->opcode) && set_param == NULL)) { + return ESP_ERR_INVALID_ARG; + } + + switch (params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + if (set_param->receivers_add.receivers_cnt == 0) { + return ESP_ERR_INVALID_ARG; + } + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + if (set_param->dist_upload_start.fw_size == 0) { + return ESP_ERR_INVALID_ARG; + } + if (set_param->dist_upload_start.fwid == NULL) { + return ESP_ERR_INVALID_ARG; + } + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + if (set_param->dist_upload_oob_start.url == NULL) { + return ESP_ERR_INVALID_ARG; + } + break; + } + + ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED); + + msg.sig = BTC_SIG_API_CALL; + msg.pid = BTC_PID_DFD_CLIENT; + msg.act = ESP_BLE_MESH_ACT_DFD_CLIENT_SET; + arg.dfd_client_set.params = params; + arg.dfd_client_set.set = set_param; + + return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfd_client_args_t), btc_ble_mesh_dfd_client_arg_deep_copy, + btc_ble_mesh_dfd_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); +} +#endif /* CONFIG_BLE_MESH_DFD_CLI */ diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h index bf91d9e06f..6ef42d3dd8 100644 --- a/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h +++ b/components/bt/esp_ble_mesh/v1.1/api/models/include/esp_ble_mesh_dfu_model_api.h @@ -34,18 +34,55 @@ extern "C" { #define ESP_BLE_MESH_DFU_OP_UPDATE_APPLY ESP_BLE_MESH_MODEL_OP_2(0x83, 0x0f) #define ESP_BLE_MESH_DFU_OP_UPDATE_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x10) +/* Distribution Receivers Management Operations (Section 4.3.1) */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD ESP_BLE_MESH_MODEL_OP_2(0x83, 0x11) /*!< Add receivers to the distribution list. */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x12) /*!< Delete all receivers from the distribution list. */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x13) /*!< Status of receivers add/delete operations. */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x14) /*!< Get the distribution receivers list. */ +#define ESP_BLE_MESH_DFD_OP_RECEIVERS_LIST ESP_BLE_MESH_MODEL_OP_2(0x83, 0x15) /*!< List of distribution receivers. */ + +/* Distribution Capabilities Operations (Section 4.3.2) */ +#define ESP_BLE_MESH_DFD_OP_CAPABILITIES_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x16) /*!< Get distribution capabilities of the node. */ +#define ESP_BLE_MESH_DFD_OP_CAPABILITIES_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x17) /*!< Distribution capabilities status. */ + +/* Firmware Distribution Control Operations (Section 4.3.3) */ +#define ESP_BLE_MESH_DFD_OP_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x18) /*!< Get current firmware distribution status. */ +#define ESP_BLE_MESH_DFD_OP_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x19) /*!< Start firmware distribution to receivers. */ +#define ESP_BLE_MESH_DFD_OP_SUSPEND ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1a) /*!< Suspend ongoing firmware distribution. */ +#define ESP_BLE_MESH_DFD_OP_CANCEL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1b) /*!< Cancel firmware distribution. */ +#define ESP_BLE_MESH_DFD_OP_APPLY ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1c) /*!< Apply distributed firmware on target nodes. */ +#define ESP_BLE_MESH_DFD_OP_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1d) /*!< Firmware distribution status. */ + +/* Firmware Upload Management Operations (Section 4.3.4) */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1e) /*!< Get firmware upload status and progress. */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_START ESP_BLE_MESH_MODEL_OP_2(0x83, 0x1f) /*!< Start firmware upload (in-band transfer). */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB ESP_BLE_MESH_MODEL_OP_2(0x83, 0x20) /*!< Start firmware upload (out-of-band transfer). */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_CANCEL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x21) /*!< Cancel firmware upload. */ +#define ESP_BLE_MESH_DFD_OP_UPLOAD_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x22) /*!< Firmware upload status and progress. */ + +/* Firmware Image Management Operations (Section 4.3.5) */ +#define ESP_BLE_MESH_DFD_OP_FW_GET ESP_BLE_MESH_MODEL_OP_2(0x83, 0x23) /*!< Get firmware image information by FW ID. */ +#define ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX ESP_BLE_MESH_MODEL_OP_2(0x83, 0x24) /*!< Get firmware image information by index. */ +#define ESP_BLE_MESH_DFD_OP_FW_DELETE ESP_BLE_MESH_MODEL_OP_2(0x83, 0x25) /*!< Delete specific firmware image. */ +#define ESP_BLE_MESH_DFD_OP_FW_DELETE_ALL ESP_BLE_MESH_MODEL_OP_2(0x83, 0x26) /*!< Delete all firmware images. */ +#define ESP_BLE_MESH_DFD_OP_FW_STATUS ESP_BLE_MESH_MODEL_OP_2(0x83, 0x27) /*!< Firmware image management status. */ + +/* Device Firmware Distribution Constants and Status Codes */ +#define ESP_BLE_MESH_DFD_UPLOAD_PROGRESS_UNSET 101 /*!< Upload progress is not set/available. */ +#define ESP_BLE_MESH_DFD_UPLOAD_TYPE_INBAND 0 /*!< In-band firmware upload type. */ +#define ESP_BLE_MESH_DFD_UPLOAD_TYPE_OOB BIT0 /*!< Out-of-band firmware upload type. */ + #if CONFIG_BLE_MESH_DFU_CLI -/** @def ESP_BLE_MESH_MODEL_DFU_CLI +/** + * @brief Define a new DFU Client model. * - * @brief Define a new DFU Client model. + * @note This API needs to be called for each element on which + * the application needs to have a DFU Client model. * - * @note This API needs to be called for each element on which - * the application needs to have a DFU Client model. + * @param cli_pub Pointer to the unique `esp_ble_mesh_model_pub_t`. + * @param cli_data Pointer to the unique `esp_ble_mesh_client_t`. * - * @param cli_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. - * @param cli_data Pointer to the unique struct esp_ble_mesh_client_t. - * - * @return New DFU Client model instance. + * @return New DFU Client model instance. */ #define ESP_BLE_MESH_MODEL_DFU_CLI(cli_pub, cli_data) \ ESP_BLE_MESH_MODEL_BLOB_CLI(NULL, &(cli_data)->blob), \ @@ -53,16 +90,14 @@ extern "C" { NULL, cli_pub, cli_data) -/** @def ESP_BLE_MESH_DFU_CLI_INIT +/** + * @brief Initialize a DFU Client model instance. * - * @brief Initialize a DFU Client model instance. + * @note This macro initializes the DFU Client model and sets callback handlers. * - * @note This macro is used to initialize the DFU Client model. - * It sets the callback handlers for the DFU Client. + * @param _handlers Pointer to the callback handler structure `esp_ble_mesh_dfu_cli_cb_t`. * - * @param _handlers Pointer to the callback handler structure (esp_ble_mesh_dfu_cli_cb_t). - * - * @return An initialized DFU Client model instance. + * @return An initialized DFU Client model instance. */ #define ESP_BLE_MESH_DFU_CLI_INIT(_handlers) \ { \ @@ -71,17 +106,16 @@ extern "C" { #endif /* CONFIG_BLE_MESH_DFU_CLI */ #if CONFIG_BLE_MESH_DFU_SRV -/** @def ESP_BLE_MESH_MODEL_DFU_SRV +/** + * @brief Define a new DFU Server model. * - * @brief Define a new DFU Server model. + * @note This API needs to be called for each element on which + * the application needs to have a DFU Server model. * - * @note This API needs to be called for each element on which - * the application needs to have a DFU Server model. + * @param srv_pub Pointer to the unique `esp_ble_mesh_model_pub_t`. + * @param srv_data Pointer to the unique `esp_ble_mesh_dfu_trans_srv_t`. * - * @param srv_pub Pointer to the unique struct esp_ble_mesh_model_pub_t. - * @param srv_data Pointer to the unique struct esp_ble_mesh_dfu_trans_srv_t. - * - * @return New DFU Server model instance. + * @return New DFU Server model instance. */ #define ESP_BLE_MESH_MODEL_DFU_SRV(srv_pub, srv_data) \ ESP_BLE_MESH_MODEL_BLOB_SRV(NULL, &(srv_data)->blob), \ @@ -89,18 +123,17 @@ extern "C" { NULL, srv_pub, srv_data) -/** @def ESP_BLE_MESH_DFU_SRV_INIT +/** + * @brief Initialize a DFU Server model instance. * - * @brief Initialize a DFU Server model instance. + * @note This macro initializes the DFU Server model and sets callback handlers + * and image information. * - * @note This macro is used to initialize the DFU Server model. - * It sets the callback handlers and image information for the DFU Server. + * @param _handlers Pointer to the callback handler structure `esp_ble_mesh_dfu_srv_cb_t`. + * @param _imgs Pointer to the array of DFU images `esp_ble_mesh_dfu_img_t`. + * @param _img_count Number of DFU images in the array. * - * @param _handlers Pointer to the callback handler structure (esp_ble_mesh_dfu_srv_cb_t). - * @param _imgs Pointer to the array of DFU images (esp_ble_mesh_dfu_img_t). - * @param _img_count Number of DFU images in the array. - * - * @return An initialized DFU Server model instance. + * @return An initialized DFU Server model instance. */ #define ESP_BLE_MESH_DFU_SRV_INIT(_handlers, _imgs, _img_count) \ { \ @@ -109,6 +142,75 @@ extern "C" { } #endif /* CONFIG_BLE_MESH_DFU_SRV */ +#if CONFIG_BLE_MESH_DFD_CLI +/** + * @def ESP_BLE_MESH_MODEL_DFD_CLI + * + * @brief Define a new Device Firmware Distribution Client model. + * + * Define a DFD Client model for managing firmware distribution operations, + * including receiver lists, upload control, progress monitoring, and + * firmware transfers. + * + * @param cli_pub Pointer to the unique `esp_ble_mesh_model_pub_t` for publish messages. + * @param cli_data Pointer to the unique `esp_ble_mesh_client_t` containing client data. + * + * @return New DFD Client model instance. + */ +#define ESP_BLE_MESH_MODEL_DFD_CLI(cli_pub, cli_data) \ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DFD_CLI, \ + NULL, cli_pub, cli_data) +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +/** + * @def ESP_BLE_MESH_MODEL_DFD_SRV + * + * @brief Define a new Device Firmware Distribution Server model. + * + * Define a DFD Server model that stores firmware, distributes to targets, + * handles uploads, manages receiver lists, and controls distribution phases. + * Contains internal DFU Client for updates and BLOB Server for transfers. + * + * @param srv_pub Pointer to the unique `esp_ble_mesh_model_pub_t` for publish messages. + * @param srv_data Pointer to the unique `esp_ble_dfd_trans_srv_t` containing server data. + * + * @return New DFD Server model instance. + */ +#define ESP_BLE_MESH_MODEL_DFD_SRV(srv_pub, srv_data) \ + ESP_BLE_MESH_MODEL_DFU_CLI(NULL, &(srv_data)->dfu), \ + ESP_BLE_MESH_MODEL_BLOB_SRV(NULL, &((srv_data)->upload.blob)),\ + ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_DFD_SRV, \ + NULL, srv_pub, srv_data) + +/* Internal callback structures for DFD Server implementation */ +extern const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb; /*!< Internal DFU Client callbacks for DFD Server. */ +extern const struct bt_mesh_blob_srv_cb _bt_mesh_dfd_srv_blob_cb; /*!< Internal BLOB Server callbacks for DFD Server. */ + +/** + * @def ESP_BLE_MESH_DFD_SRV_INIT + * + * @brief Initialize a Device Firmware Distribution Server. + * + * Initialize a DFD Server instance with the provided callback structure + * and set up the internal DFU Client and BLOB Server components. + * + * @param _cb Pointer to a `bt_mesh_dfd_srv_cb` instance containing the server callbacks. + * + * @return Initialized DFD Server structure with internal components configured. + */ +#define ESP_BLE_MESH_DFD_SRV_INIT(_cb) \ + { \ + .cb = _cb, \ + .dfu = ESP_BLE_MESH_DFU_CLI_INIT((struct esp_ble_mesh_dfu_cli_cb *) \ + &_bt_mesh_dfd_srv_dfu_cb), \ + .upload = { \ + .blob = { .cb = (esp_ble_mesh_blob_srv_cb_t *) \ + &_bt_mesh_dfd_srv_blob_cb }, \ + }, \ + } +#endif /* CONFIG_BLE_MESH_DFD_SRV */ + /** @brief DFU image structure. **/ typedef struct esp_ble_mesh_dfu_img esp_ble_mesh_dfu_img_t; @@ -298,6 +400,95 @@ typedef struct esp_ble_mesh_dfu_srv esp_ble_mesh_dfu_srv_t; typedef struct esp_ble_mesh_dfu_srv_cb esp_ble_mesh_dfu_srv_cb_t; #endif /* CONFIG_BLE_MESH_DFU_SRV */ +#if CONFIG_BLE_MESH_DFD_CLI +/* DFD Client Forward Declarations */ +typedef enum esp_ble_mesh_dfd_client_act esp_ble_mesh_dfd_client_act_t; /*!< DFD Client action enumeration. */ +typedef enum esp_ble_mesh_dfd_client_cb_evt esp_ble_mesh_dfd_client_cb_evt_t; /*!< DFD Client callback event enumeration. */ +typedef struct esp_ble_mesh_dfd_cli_receiver_entry esp_ble_mesh_dfd_cli_receiver_entry_t; /*!< DFD Client receiver entry structure. */ + +/* DFD Client Receiver Management Structures */ +typedef struct esp_ble_mesh_dfd_cli_receivers_add esp_ble_mesh_dfd_cli_receivers_add_t; /*!< Parameters for adding receivers to distribution list. */ +typedef struct esp_ble_mesh_dfd_receiver_status esp_ble_mesh_dfd_receiver_status_t; /*!< Status response for receiver operations. */ + +typedef struct esp_ble_mesh_dfd_receivers_get esp_ble_mesh_dfd_receivers_get_t; /*!< Parameters for getting distribution receivers list. */ +typedef struct esp_ble_mesh_dfd_target_node_entry esp_ble_mesh_dfd_target_node_entry_t; /*!< Target node entry information. */ +typedef struct esp_ble_mesh_dfd_receiver_list esp_ble_mesh_dfd_receiver_list_t; /*!< Distribution receivers list response. */ + +/* DFD Client Distribution Control Structures */ +typedef struct esp_ble_mesh_dfd_dist_caps esp_ble_mesh_dfd_dist_caps_t; /*!< Distribution capabilities of the DFD Server. */ + +typedef struct esp_ble_mesh_dfd_cli_dist_start esp_ble_mesh_dfd_cli_dist_start_t; /*!< Parameters for starting firmware distribution. */ +typedef struct esp_ble_mesh_dfd_dist_status esp_ble_mesh_dfd_dist_status_t; /*!< Firmware distribution status response. */ + +/* DFD Client Upload Management Structures */ +typedef struct esp_ble_mesh_dfd_cli_dist_upload_start esp_ble_mesh_dfd_cli_dist_upload_start_t; /*!< Parameters for starting in-band firmware upload. */ +typedef struct esp_ble_mesh_dfd_cli_dist_upload_oob_start esp_ble_mesh_dfd_cli_dist_upload_oob_start_t; /*!< Parameters for starting out-of-band firmware upload. */ +typedef struct esp_ble_mesh_dfd_upload_status esp_ble_mesh_dfd_upload_status_t; /*!< Firmware upload status and progress. */ + +/* DFD Client Firmware Management Structures */ +typedef struct esp_ble_mesh_dfd_cli_dist_fw_get esp_ble_mesh_dfd_cli_dist_fw_get_t; /*!< Parameters for getting firmware by FW ID. */ +typedef struct esp_ble_mesh_dfd_cli_dist_fw_get_by_idx esp_ble_mesh_dfd_cli_dist_fw_get_by_idx_t; /*!< Parameters for getting firmware by index. */ +typedef struct esp_ble_mesh_dfd_cli_dist_fw_del esp_ble_mesh_dfd_cli_dist_fw_del_t; /*!< Parameters for deleting firmware. */ +typedef struct esp_ble_mesh_dfd_firmware_status esp_ble_mesh_dfd_firmware_status_t; /*!< Firmware management status response. */ + +/* DFD Client Callback Structures */ +typedef struct esp_ble_mesh_dfd_client_cb_param esp_ble_mesh_dfd_client_cb_param_t; /*!< DFD Client callback parameters. */ +typedef union esp_ble_mesh_dfd_client_common_cb_param esp_ble_mesh_dfd_client_common_cb_param_t; /*!< Common callback parameter union. */ + +/* DFD Client Callback Function Type */ +typedef void (*esp_ble_mesh_dfd_client_cb_t)(esp_ble_mesh_dfd_client_cb_evt_t event, /*!< DFD Client callback function type. */ + esp_ble_mesh_dfd_client_cb_param_t *param); +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +/** + * @brief Firmware Distribution status enumeration. + * + * This enumeration defines the status codes used in DFD operations + * according to the Bluetooth Mesh Model Specification v1.0. These + * status codes indicate success, failure, and error conditions + * for various firmware distribution operations. + */ +typedef enum esp_ble_mesh_dfd_status esp_ble_mesh_dfd_status_t; + +/** + * @brief Firmware distribution phases enumeration. + * + * This enumeration defines the different phases of a firmware distribution + * operation as specified in the Bluetooth Mesh Model Specification v1.0. + * The phases track the state of firmware distribution from idle through + * transfer, verification, application, and completion states. + */ +typedef enum esp_ble_mesh_dfd_phase esp_ble_mesh_dfd_phase_t; + +/** + * @brief Firmware upload phases enumeration. + * + * This enumeration defines the phases of firmware upload operations + * on the DFD Server. It tracks the state of firmware storage procedures + * including in-band and out-of-band upload methods. + */ +typedef enum esp_ble_mesh_dfd_upload_phase esp_ble_mesh_dfd_upload_phase_t; + +/** + * @brief Firmware Distribution Server callback structure. + * + * This structure contains callback function pointers that allow the + * application to handle various DFD Server events including firmware + * reception, distribution control, and phase changes. + */ +typedef struct esp_ble_mesh_dfd_srv_cb esp_ble_mesh_dfd_srv_cb_t; + +/** + * @brief Firmware Distribution Server instance structure. + * + * This structure represents a DFD Server model instance that manages + * firmware distribution operations. It contains state information for + * ongoing distributions, firmware storage, and target node management. + */ +typedef struct esp_ble_mesh_dfd_srv esp_ble_mesh_dfd_srv_t; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ + /** DFU transfer phase. */ typedef enum esp_ble_mesh_dfu_phase { /** Ready to start a Receive Firmware procedure. */ @@ -613,7 +804,7 @@ struct esp_ble_mesh_dfu_cli_xfer { struct esp_ble_mesh_device_firmware_update_info_get { uint8_t first_index; /*!< Index of the first requested entry from the Firmware Information List state */ uint8_t entries_limit; /*!< Maximum number of entries that the server includes in a Firmware Update Information Status message */ - esp_ble_mesh_dfu_img_cb_t img_cb; /*!< Added by Espressif, callback function used to walkthrough recceived images */ + esp_ble_mesh_dfu_img_cb_t img_cb; /*!< Added by Espressif, callback function used to walkthrough received images */ }; /** @@ -992,6 +1183,804 @@ bool esp_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv); uint8_t esp_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv); #endif /* CONFIG_BLE_MESH_DFU_SRV */ +#if CONFIG_BLE_MESH_DFD_CLI +/** + * @brief DFD Client receiver entry structure. + * + * This structure represents a single receiver node that will be added + * to the distribution list for firmware updates. Each entry contains + * the target node's address and the specific firmware image index + * that should be distributed to that node. + * + * @note This is used with the DFD Receivers Add message to build + * the distribution receiver list. + */ +struct esp_ble_mesh_dfd_cli_receiver_entry { + /** The unicast address of the target node to receive firmware updates */ + uint16_t addr; + /** Index of the firmware image that should be distributed to this target node */ + uint8_t fw_idx; +}; + +/** + * @brief DFD Client receivers add parameters. + * + * This structure contains the parameters for the DFD Receivers Add + * message. It is used to add multiple target nodes to the distribution + * receiver list. + * + * @note The receivers array should contain valid unicast addresses + * and corresponding firmware image indices. + */ +struct esp_ble_mesh_dfd_cli_receivers_add { + /** Pointer to array of receiver entries to add to the distribution list */ + esp_ble_mesh_dfd_cli_receiver_entry_t *receivers; + /** Number of receiver entries in the receivers array */ + uint16_t receivers_cnt; +}; + +/** + * @brief DFD receiver status response structure. + * + * This structure contains the response parameters for the DFD + * Receivers Add/Delete operations. + * + * The status indicates whether the receiver list modification + * was successful, and the receiver_list_cnt provides the current + * size of the distribution receiver list. + */ +struct esp_ble_mesh_dfd_receiver_status { + /** Status code for the receiver add/delete operation (see esp_ble_mesh_dfd_status) */ + uint8_t status; + /** Current number of entries in the Distribution Receivers List state */ + uint16_t receiver_list_cnt; +}; + +/** + * @brief DFD receivers get parameters. + * + * This structure contains the parameters for the DFD Receivers Get + * message. It is used to retrieve a portion of the distribution + * receiver list. + * + * @note This supports pagination of large receiver lists by allowing + * the client to request specific ranges of entries. + */ +struct esp_ble_mesh_dfd_receivers_get { + /** Index of the first entry in the Distribution Receivers List to return */ + uint16_t first_index; + /** Maximum number of entries to include in the response */ + uint16_t entries_limit; +}; + +/** + * @brief DFD target node entry structure. + * + * This structure represents the status of a single target node + * in the distribution receiver list. It contains detailed information + * about the target's current update phase, transfer status, and progress. + * + * This is returned in the DFD Receivers List message. + */ +struct esp_ble_mesh_dfd_target_node_entry { + /** Unicast address of the target node (15 bits) */ + uint32_t addr:15, + /** Retrieved update phase of the target node (4 bits, see esp_ble_mesh_dfu_phase) */ + retrieved_update_phase:4, + /** Update status of the target node (3 bits, see esp_ble_mesh_dfu_status) */ + update_status:3, + /** Transfer status of the target node (4 bits) */ + transfer_status:4, + /** Transfer progress percentage of the target node (6 bits, in 2 percent increments) */ + transfer_progress:6; + /** Index of the firmware image being updated on the target node */ + uint8_t update_fw_idx; +}; + +/** + * @brief DFD receiver list response structure. + * + * This structure contains the response parameters for the DFD Receivers Get + * message. It provides a list of target nodes in the distribution receiver + * list along with their current status. + */ +struct esp_ble_mesh_dfd_receiver_list { + /** Number of entries included in this response */ + uint16_t entries_cnt; + /** Index of the first entry in the Distribution Receivers List returned */ + uint16_t first_index; + /** Pointer to array of target node entries containing receiver status information */ + esp_ble_mesh_dfd_target_node_entry_t *entries; +}; + +/** + * @brief DFD distribution capabilities structure. + * + * This structure contains the capabilities of a DFD Server as + * returned by the DFD Capabilities Get message. + * + * It provides information about the server's capacity for handling + * firmware distribution operations, storage limits, and supported + * out-of-band retrieval methods. + */ +struct esp_ble_mesh_dfd_dist_caps { + /** Maximum number of receivers that can be stored in the Distribution Receivers List */ + uint16_t max_receiver_list_sz; + /** Maximum number of firmware images that can be stored in the Firmware Information List */ + uint16_t max_fw_list_sz; + /** Maximum size of a single firmware image that can be stored (in bytes) */ + uint32_t max_fw_sz; + /** Maximum upload space available for storing firmware images (in bytes) */ + uint32_t max_upload_space; + /** Remaining upload space available after current stored firmware (in bytes) */ + uint32_t remaining_upload_space; + /** Bit field indicating supported out-of-band retrieval methods (0 = none supported) */ + uint8_t oob_retrieval_supported; + /** Pointer to buffer containing supported URL scheme names (UTF-8, null-terminated) */ + struct net_buf_simple *supported_url_scheme_names; +}; + +/** + * @brief DFD Client distribution start parameters. + * + * This structure contains the parameters for the DFD Start message. + * It initiates the firmware distribution process to all target nodes + * in the Distribution Receivers List. + */ +struct esp_ble_mesh_dfd_cli_dist_start { + /** TTL value to be used for all messages sent during firmware distribution */ + uint8_t ttl; + /** Transfer mode: 0x00 = Push BLOB Transfer Mode, 0x01 = Pull BLOB Transfer Mode (2 bits) */ + uint8_t trans_mode : 2, + /** Update policy: 0x00 = Single Target Node, 0x01 = All Target Nodes (1 bit) */ + update_policy : 1, + /** Reserved for Future Use (5 bits) */ + RFU : 5; + /** Application Key Index to be used for securing firmware distribution messages */ + uint16_t app_idx; + /** Base time value used to calculate transfer timeout (in 100ms units) */ + uint16_t timeout_base; + /** Index of the firmware image in the Firmware Information List to distribute */ + uint16_t fw_idx; + /** Flag indicating whether the target address is a virtual address (true) or group address (false) */ + bool is_va; + /** Target address for firmware distribution (group address or virtual label UUID) */ + union { + /** Group address for firmware distribution (used when is_va is false) */ + uint16_t group_addr; + /** Virtual Label UUID for firmware distribution (used when is_va is true) */ + uint8_t label_uuid[16]; + }; +}; + +/** + * @brief DFD distribution status structure. + * + * This structure contains the response parameters for the DFD Get and + * DFD Start messages. It provides the current status and configuration + * of the firmware distribution operation. + */ +struct esp_ble_mesh_dfd_dist_status { + /** Status code for the distribution operation (see esp_ble_mesh_dfd_status) */ + uint8_t status; + /** Current firmware distribution phase (see esp_ble_mesh_dfd_phase) */ + uint8_t dist_phase; + /** Multicast address used for the firmware distribution (group address or virtual label) */ + uint16_t multicast_address; + /** Application Key Index being used for securing firmware distribution messages */ + uint16_t appkey_idx; + /** TTL value being used for firmware distribution messages */ + uint8_t ttl; + /** Base time value used to calculate transfer timeout (in 100ms units) */ + uint16_t timeout_base; + /** Transfer mode: 0x00 = Push BLOB Transfer Mode, 0x01 = Pull BLOB Transfer Mode (2 bits) */ + uint8_t trans_mode:2, + /** Update policy: 0x00 = Single Target Node, 0x01 = All Target Nodes (1 bit) */ + update_policy:1, + /** Reserved for Future Use (5 bits) */ + RFU:5; + /** Index of the firmware image currently being distributed */ + uint16_t firmware_image_index; +}; + +/** + * @brief DFD Client upload start parameters. + * + * This structure contains the parameters for the DFD Upload Start + * message. It initiates an in-band firmware + * upload to the DFD Server using BLOB Transfer. + * + * @note This is used for in-band firmware transfers where the firmware + * data is transferred through the mesh network. + */ +struct esp_ble_mesh_dfd_cli_dist_upload_start { + /** TTL value to be used for all messages during the upload */ + uint8_t ttl; + /** Base time value used to calculate upload timeout (in 100ms units) */ + uint16_t timeout_base; + /** Total size of the firmware image to be uploaded (in bytes) */ + uint32_t fw_size; + /** BLOB identifier that will be used for the firmware transfer */ + uint64_t blob_id; + /** Pointer to buffer containing the firmware ID of the image to upload */ + struct net_buf_simple *fwid; + /** Pointer to buffer containing the firmware metadata for the upload */ + struct net_buf_simple *fw_metadata; +}; + +/** + * @brief DFD Client out-of-band upload start parameters. + * + * This structure contains the parameters for the DFD Upload Start OOB + * message. It initiates an out-of-band firmware + * upload where the firmware is retrieved from an external source. + * + * @note This is used for out-of-band firmware transfers where the firmware + * is obtained from a URI or external source. + */ +struct esp_ble_mesh_dfd_cli_dist_upload_oob_start { + /** Pointer to buffer containing the current firmware ID to check against */ + struct net_buf_simple *fwid; + /** Pointer to buffer containing the URI for firmware retrieval (UTF-8 string) */ + struct net_buf_simple *url; +}; + +/** + * @brief DFD upload status structure. + * + * This structure contains the response parameters for the DFD Upload Get, + * DFD Upload Start, and DFD Upload Start OOB messages. + * + * It provides the current status and progress of an ongoing or completed + * firmware upload operation on the DFD Server. + */ +struct esp_ble_mesh_dfd_upload_status { + /** Status code for the upload operation (see esp_ble_mesh_dfd_status) */ + uint8_t status; + /** Current upload phase (see esp_ble_mesh_dfd_upload_phase) */ + uint8_t upload_phase; + /** Upload progress percentage (0-100%, only valid when progress != 101) */ + uint8_t upload_progress:7, + /** Upload type: 0x00 = In-band upload, 0x01 = Out-of-band upload */ + upload_type:1; + /** Union containing firmware ID information based on upload type */ + union { + /** Firmware ID for in-band upload operations */ + struct net_buf_simple *fwid; + /** Firmware ID for out-of-band upload operations */ + struct net_buf_simple *oob_fwid; + }; +}; + +/** + * @brief DFD Client firmware get parameters. + * + * This structure contains the parameters for the DFD Firmware Get + * message. It requests information about a specific + * firmware image identified by its firmware ID. + */ +struct esp_ble_mesh_dfd_cli_dist_fw_get { + /** Pointer to buffer containing the firmware ID to query */ + struct net_buf_simple *fwid; +}; + +/** + * @brief DFD Client firmware get by index parameters. + * + * This structure contains the parameters for the DFD Firmware Get By Index + * message. It requests information about a specific firmware image identified + * by its index in the Firmware Information List. + */ +struct esp_ble_mesh_dfd_cli_dist_fw_get_by_idx { + /** Index of the firmware image in the Firmware Information List */ + uint16_t dist_fw_idx; +}; + +/** + * @brief DFD Client firmware delete parameters. + * + * This structure contains the parameters for the DFD Firmware Delete + * message. It requests deletion of a specific firmware image from the + * DFD Server. + * + * @note Deleting a firmware image that is currently being distributed will + * cause the distribution to fail. + */ +struct esp_ble_mesh_dfd_cli_dist_fw_del { + /** Pointer to buffer containing the firmware ID of the image to delete */ + struct net_buf_simple *fwid; +}; + +/** + * @brief DFD firmware status structure. + * + * This structure contains the response parameters for the DFD Firmware Get + * and DFD Firmware Get By Index messages. + * + * It provides detailed information about a specific firmware image stored + * on the DFD Server. + */ +struct esp_ble_mesh_dfd_firmware_status { + /** Status code for the firmware query operation (see esp_ble_mesh_dfd_status) */ + uint8_t status; + /** Total number of entries in the Firmware Information List */ + uint16_t entry_cnt; + /** Index of the firmware image in the Firmware Information List */ + uint16_t fw_idx; + /** Pointer to buffer containing the firmware ID of the queried image */ + struct net_buf_simple *fwid; +}; + +/** + * @brief DFD Client action enumeration. + * + * This enumeration defines the different types of actions that can be performed + * by the DFD Client model. These actions are used internally to + * distinguish between different DFD message types when processing + * client requests. + */ +enum esp_ble_mesh_dfd_client_act { + /** DFD Client Get action - retrieving information from DFD Server */ + ESP_BLE_MESH_ACT_DFD_CLIENT_GET, + /** DFD Client Set action - sending commands/configuration to DFD Server */ + ESP_BLE_MESH_ACT_DFD_CLIENT_SET, + /** Maximum value for DFD Client action enumeration (bounds checking) */ + ESP_BLE_MESH_ACT_DFD_CLIENT_MAX, +}; + +/** + * @brief DFD Client callback event enumeration. + * + * This enumeration defines the different callback events that can be generated + * by the DFD Client model. These events notify the application + * about the status of DFD operations, message responses, timeouts, + * and completion of various procedures. + * + * Application should handle these events to properly manage firmware + * distribution operations and provide user feedback. + */ +enum esp_ble_mesh_dfd_client_cb_evt { + /** DFD Client timeout event - operation timed out waiting for response */ + ESP_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT, + /** DFD Client receive response event - received a response from DFD Server */ + ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP, + /** DFD Client send complete event - message transmission completed */ + ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP, + /** Maximum value for DFD Client callback event enumeration (bounds checking) */ + ESP_BLE_MESH_EVT_DFD_CLIENT_MAX, +}; + +/** + * @brief DFD Client get parameters union. + * + * This union contains different parameter structures for various DFD Client + * Get messages. The specific structure used depends on the type of + * get operation being performed. + * + * This allows type-safe access to message-specific parameters while + * using a single parameter type in the API. + */ +typedef union { + /** Parameters for DFD Receivers Get operation */ + esp_ble_mesh_dfd_receivers_get_t receivers_get; + /** Parameters for DFD Firmware Get operation */ + esp_ble_mesh_dfd_cli_dist_fw_get_t dist_fw_get; + /** Parameters for DFD Firmware Get By Index operation */ + esp_ble_mesh_dfd_cli_dist_fw_get_by_idx_t dist_fw_get_by_idx; +} esp_ble_mesh_dfd_client_get_param_t; + +/** + * @brief DFD Client set parameters union. + * + * This union contains different parameter structures for various DFD Client + * Set messages. The specific structure used depends on the type of + * set operation being performed. + * + * This allows type-safe access to message-specific parameters while + * using a single parameter type in the API. + */ +typedef union { + /** Parameters for DFD Receivers Add operation */ + esp_ble_mesh_dfd_cli_receivers_add_t receivers_add; + /** Parameters for DFD Start operation */ + esp_ble_mesh_dfd_cli_dist_start_t dist_start; + /** Parameters for DFD Upload Start operation */ + esp_ble_mesh_dfd_cli_dist_upload_start_t dist_upload_start; + /** Parameters for DFD Upload Start OOB operation */ + esp_ble_mesh_dfd_cli_dist_upload_oob_start_t dist_upload_oob_start; + /** Parameters for DFD Firmware Get operation */ + esp_ble_mesh_dfd_cli_dist_fw_get_t dist_fw_get; + /** Parameters for DFD Firmware Delete operation */ + esp_ble_mesh_dfd_cli_dist_fw_del_t dist_fw_del; +} esp_ble_mesh_dfd_client_set_param_t; + +/** + * @brief DFD Client common callback parameters union. + * + * This union contains different response structures for various DFD Client + * received messages. The specific structure used depends on the type of + * message that triggered the callback. + * + * This allows type-safe access to message-specific response data + * while using a single callback parameter type. + */ +union esp_ble_mesh_dfd_client_common_cb_param { + /** Response parameters for DFD Receivers Add/Delete operations */ + esp_ble_mesh_dfd_receiver_status_t receiver_status; + /** Response parameters for DFD Receivers Get operation */ + esp_ble_mesh_dfd_receiver_list_t receiver_list; + /** Response parameters for DFD Capabilities Get operation */ + esp_ble_mesh_dfd_dist_caps_t dist_caps; + /** Response parameters for DFD Get/Start operations */ + esp_ble_mesh_dfd_dist_status_t dist_status; + /** Response parameters for DFD Upload Get/Start operations */ + esp_ble_mesh_dfd_upload_status_t upload_status; + /** Response parameters for DFD Firmware Get operations */ + esp_ble_mesh_dfd_firmware_status_t firmware_status; +}; + +/** + * @brief DFD Client callback parameters structure. + * + * This structure contains the parameters passed to the DFD Client + * callback function for various events. It provides information about + * the operation status, error codes, and event-specific data. + * + * Applications should examine the err_code field first to determine + * whether the operation was successful, then check the appropriate + * field in the status_cb union for operation-specific data. + */ +struct esp_ble_mesh_dfd_client_cb_param { + /** Error code indicating success (0) or failure (negative) of the operation */ + int err_code; + /** Common client parameters including source address, destination, etc. */ + esp_ble_mesh_client_common_param_t *params; + /** Union containing event-specific response data */ + esp_ble_mesh_dfd_client_common_cb_param_t status_cb; +}; + +/** + * @brief Register DFD Client callback function. + * + * This function registers a callback function that will be called when + * DFD Client events occur, such as message timeouts, responses, + * or operation completions. + * + * @param callback Pointer to the callback function to register. + * + * @return ESP_OK on success, or error code otherwise. + * + * @note Only one callback can be registered at a time. Calling this + * function with a NULL callback will deregister the current callback. + */ +esp_err_t esp_ble_mesh_register_dfd_cli_callback(esp_ble_mesh_dfd_client_cb_t callback); + +/** + * @brief Send DFD Client Get message. + * + * This function sends a DFD Get message to retrieve information + * from the DFD Server. The specific type of information requested + * depends on the get_param structure provided. + * + * @param params Common client parameters including destination address, TTL, etc. + * @param get_param Union containing the specific get message parameters. + * + * @return ESP_OK on success, or error code otherwise. + * + * @note The response will be delivered through the registered callback + * function with the ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP event. + */ +esp_err_t esp_ble_mesh_dfd_cli_get(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_get_param_t *get_param); + +/** + * @brief Send DFD Client Set message. + * + * This function sends a DFD Set message to perform various operations + * on the DFD Server, such as starting firmware distribution, + * uploading firmware, or managing the receiver list. + * + * @param params Common client parameters including destination address, TTL, etc. + * @param set_param Union containing the specific set message parameters. + * + * @return ESP_OK on success, or error code otherwise. + * + * @note The response will be delivered through the registered callback + * function with the ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP event. + */ +esp_err_t esp_ble_mesh_dfd_cli_set(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_set_param_t *set_param); + +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +/** + * @brief Firmware Distribution status enumeration. + * + * This enumeration defines the status codes used in DFD operations. + * These status codes indicate success, failure, and error conditions + * for various firmware distribution operations. + */ +enum esp_ble_mesh_dfd_status { + /** The message was processed successfully. */ + ESP_BLE_MESH_DFD_SUCCESS, + + /** Insufficient resources on the node. */ + ESP_BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES, + + /** The operation cannot be performed while the Server is in the current phase. */ + ESP_BLE_MESH_DFD_ERR_WRONG_PHASE, + + /** An internal error occurred on the node. */ + ESP_BLE_MESH_DFD_ERR_INTERNAL, + + /** The requested firmware image is not stored on the Distributor. */ + ESP_BLE_MESH_DFD_ERR_FW_NOT_FOUND, + + /** The AppKey identified by the AppKey Index is not known to the node. */ + ESP_BLE_MESH_DFD_ERR_INVALID_APPKEY_INDEX, + + /** There are no Target nodes in the Distribution Receivers List state. */ + ESP_BLE_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY, + + /** Another firmware image distribution is in progress. */ + ESP_BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION, + + /** Another upload is in progress. */ + ESP_BLE_MESH_DFD_ERR_BUSY_WITH_UPLOAD, + + /** The URI scheme name indicated by the Update URI is not supported. */ + ESP_BLE_MESH_DFD_ERR_URI_NOT_SUPPORTED, + + /** The format of the Update URI is invalid. */ + ESP_BLE_MESH_DFD_ERR_URI_MALFORMED, + + /** The URI is currently unreachable. */ + ESP_BLE_MESH_DFD_ERR_URI_UNREACHABLE, + + /** The Check Firmware OOB procedure did not find any new firmware. */ + ESP_BLE_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE, + + /** The suspension of the Distribute Firmware procedure failed. */ + ESP_BLE_MESH_DFD_ERR_SUSPEND_FAILED, +}; + +/** + * @brief Firmware distribution phases enumeration. + * + * This enumeration defines the different phases of a firmware distribution + * operation. The phases track the state of firmware distribution from + * idle through transfer, verification, application, and completion states. + */ +enum esp_ble_mesh_dfd_phase { + /** No firmware distribution is in progress. */ + ESP_BLE_MESH_DFD_PHASE_IDLE, + + /** Firmware distribution is in progress. */ + ESP_BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE, + + /** The Transfer BLOB procedure has completed successfully. */ + ESP_BLE_MESH_DFD_PHASE_TRANSFER_SUCCESS, + + /** The Apply Firmware on Target Nodes procedure is being executed. */ + ESP_BLE_MESH_DFD_PHASE_APPLYING_UPDATE, + + /** The Distribute Firmware procedure has completed successfully. */ + ESP_BLE_MESH_DFD_PHASE_COMPLETED, + + /** The Distribute Firmware procedure has failed. */ + ESP_BLE_MESH_DFD_PHASE_FAILED, + + /** The Cancel Firmware Update procedure is being executed. */ + ESP_BLE_MESH_DFD_PHASE_CANCELING_UPDATE, + + /** The Transfer BLOB procedure is suspended. */ + ESP_BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED, +}; + +/** + * @brief Firmware upload phases enumeration. + * + * This enumeration defines the phases of firmware upload operations + * on the DFD Server. It tracks the state of firmware storage procedures + * including both in-band and out-of-band upload methods. + */ +enum esp_ble_mesh_dfd_upload_phase { + /** No firmware upload is in progress. */ + ESP_BLE_MESH_DFD_UPLOAD_PHASE_IDLE, + + /** The Store Firmware procedure is being executed. */ + ESP_BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE, + + /** The Store Firmware procedure or Store Firmware OOB procedure failed. */ + ESP_BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR, + + /** The Store Firmware procedure or the Store Firmware OOB procedure completed successfully. */ + ESP_BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS, +}; + +#if 0 +/** + * @brief Flash partition + * + * This structure represents a fixed-size partition on a flash device. + * Each partition contains one or more flash sectors. + */ +struct flash_area { + /** ID number */ + uint8_t fa_id; + uint16_t pad16; + /** Start offset from the beginning of the flash device */ + off_t fa_off; + /** Total size */ + size_t fa_size; + /** Backing flash device */ + const struct device *fa_dev; +#if CONFIG_FLASH_MAP_LABELS + /** Partition label if defined in DTS. Otherwise nullptr; */ + const char *fa_label; +#endif +}; +#endif + +/** Firmware Distribution Server callbacks: */ +struct esp_ble_mesh_dfd_srv_cb { + + /** @brief Slot receive callback. + * + * Called at the start of an upload procedure. The callback must fill + * @c io with a pointer to a writable BLOB stream for the Firmware Distribution + * Server to write the firmware image to. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being received. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*recv)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot, + const esp_ble_mesh_blob_io_t **io); + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + /** @brief Firmware upload OOB start callback. + * + * Called at the start of an OOB firmware upload. The application must + * start a firmware check using an OOB mechanism, and then call + * bt_mesh_dfd_srv_oob_check_complete. Depending on the return + * value of this function, the application must then start storing the + * firmware image using an OOB mechanism, and call + * bt_mesh_dfd_srv_oob_store_complete. This callback is mandatory + * to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot Slot to be used for the upload. + * @param uri Pointer to buffer containing the URI used to + * check for new firmware. + * @param uri_len Length of the URI buffer. + * @param fwid Pointer to buffer containing the current + * firmware ID to be used when checking for + * availability of new firmware. + * @param fwid_len Length of the current firmware ID. Must be set + * to the length of the new firmware ID if it is + * available, or to 0 if new firmware is not + * available. + * + * @return ESP_BLE_MESH_DFD_SUCCESS on success, or error code otherwise. + */ + int (*start_oob_upload)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot, + const uint8_t *uri, uint8_t uri_len, + const uint8_t *fwid, uint16_t fwid_len); + + /** @brief Cancel store OOB callback + * + * Called when an OOB store is cancelled. The application must stop + * any ongoing OOB image transfer. This callback is mandatory to + * support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to cancel + */ + void (*cancel_oob_upload)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot); + + /** @brief Get the progress of an ongoing OOB store + * + * Called by the Firmware Distribution Server model when it needs to + * get the current progress of an ongoing OOB store from the + * application. This callback is mandatory to support OOB uploads. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot to get progress for. + * + * @return The current progress of the ongoing OOB store, in percent. + */ + uint8_t (*oob_progress_get)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + + /** @brief Slot delete callback. + * + * Called when the Firmware Distribution Server is about to delete a DFU image slot. + * All allocated data associated with the firmware slot should be + * deleted. + * + * @param srv Firmware Update Server instance. + * @param slot DFU image slot being deleted. + */ + void (*del)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot); + + /** @brief Slot send callback. + * + * Called at the start of a distribution procedure. The callback must + * fill @c io with a pointer to a readable BLOB stream for the Firmware + * Distribution Server to read the firmware image from. + * + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being sent. + * @param io BLOB stream response pointer. + * + * @return 0 on success, or (negative) error code otherwise. + */ + int (*send)(esp_ble_mesh_dfd_srv_t *srv, + const esp_ble_mesh_dfu_slot_t *slot, + const esp_ble_mesh_blob_io_t **io); + + /** @brief Phase change callback (Optional). + * + * Called whenever the phase of the Firmware Distribution Server changes. + * + * @param srv Firmware Distribution Server model instance. + * @param phase New Firmware Distribution phase. + */ + void (*phase)(esp_ble_mesh_dfd_srv_t *srv, esp_ble_mesh_dfd_phase_t phase); +}; + +/** Firmware Distribution Server instance. */ +struct esp_ble_mesh_dfd_srv { + const esp_ble_mesh_dfd_srv_cb_t *cb; + esp_ble_mesh_model_t *mod; + esp_ble_mesh_dfu_cli_t dfu; + esp_ble_mesh_dfu_target_t targets[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX]; + esp_ble_mesh_blob_target_pull_t pull_ctxs[CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX]; + const esp_ble_mesh_blob_io_t *io; + uint16_t target_cnt; + uint16_t slot_idx; + bool apply; + esp_ble_mesh_dfd_phase_t phase; + esp_ble_mesh_blob_cli_inputs_t inputs; + + struct { + esp_ble_mesh_dfd_upload_phase_t phase; + esp_ble_mesh_dfu_slot_t *slot; +#if 0 + const struct flash_area *area; +#endif + esp_ble_mesh_blob_srv_t blob; +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + bool is_oob; + bool is_pending_oob_check; + struct { + uint8_t uri_len; + uint8_t uri[CONFIG_BLE_MESH_DFU_URI_MAXLEN]; + uint16_t current_fwid_len; + uint8_t current_fwid[CONFIG_BLE_MESH_DFU_FWID_MAXLEN]; + esp_ble_mesh_msg_ctx_t ctx; + } oob; +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ + } upload; + +#ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD + struct { + const uint8_t *schemes; + const uint8_t count; + } oob_schemes; +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ +}; +#endif /* CONFIG_BLE_MESH_DFD_SRV */ + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c index 91f0ab9d83..d60df283f1 100644 --- a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c @@ -12,6 +12,9 @@ #include "esp_ble_mesh_dfu_model_api.h" #include "mesh_v1.1/dfu/dfu_cli.h" #include "mesh_v1.1/dfu/dfu_srv.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfd_cli.h" +#include "mesh_v1.1/dfu/dfd_srv.h" #if CONFIG_BLE_MESH_DFU_CLI /* Device Firmware Update Client model related functions */ @@ -59,15 +62,20 @@ void btc_ble_mesh_dfu_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p src->dfu_get.get->dfu_metadata_check.metadata->data, src->dfu_get.get->dfu_metadata_check.metadata->len); } else { + bt_mesh_free(dst->dfu_get.get); + bt_mesh_free(dst->dfu_get.params); BT_ERR("Out of memory for metadata"); return; } } else { + bt_mesh_free(dst->dfu_get.get); + bt_mesh_free(dst->dfu_get.params); BT_ERR("Metadata should be exists"); return; } } } else { + bt_mesh_free(dst->dfu_get.params); BT_ERR("%s, Out of memory, act %d", __func__, msg->act); } } @@ -92,12 +100,21 @@ void btc_ble_mesh_dfu_client_arg_deep_free(btc_msg_t *msg) switch (msg->act) { case BTC_BLE_MESH_ACT_DFU_CLIENT_GET_STATE: + if (arg->dfu_get.get) { + switch (arg->dfu_get.params->opcode) { + case ESP_BLE_MESH_DFU_OP_UPDATE_METADATA_CHECK: + if (arg->dfu_get.get->dfu_metadata_check.metadata) { + bt_mesh_free_buf(arg->dfu_get.get->dfu_metadata_check.metadata); + } + break; + default: + break; + } + bt_mesh_free(arg->dfu_get.get); + } if (arg->dfu_get.params) { bt_mesh_free(arg->dfu_get.params); } - if (arg->dfu_get.get) { - bt_mesh_free(arg->dfu_get.get); - } break; default: break; @@ -134,12 +151,15 @@ static void btc_ble_mesh_dfu_client_copy_req_data(btc_msg_t *msg, void *p_dest, length = p_src_data->recv.dfu_update_info_status.fw_info_list_cnt * sizeof(esp_ble_mesh_firmware_info_t); p_dest_data->recv.dfu_update_info_status.fw_info_list = bt_mesh_calloc(length); if (!p_dest_data->recv.dfu_update_info_status.fw_info_list) { + bt_mesh_free(p_dest_data->params); BT_ERR("%s, Out of memory, act %d", __func__, msg->act); return; } memcpy(p_dest_data->recv.dfu_update_info_status.fw_info_list, p_src_data->recv.dfu_update_info_status.fw_info_list, length); + } else { + p_dest_data->recv.dfu_update_info_status.fw_info_list = NULL; } break; default: @@ -165,7 +185,7 @@ static void btc_ble_mesh_dfu_client_free_req_data(btc_msg_t *msg) } if (msg->act >= ESP_BLE_MESH_DFU_CLIENT_EVT_MAX) { - BT_ERR("%s, Invalid event %d", msg->act); + BT_ERR("%s, Invalid event %d", __func, msg->act); return; } @@ -412,3 +432,785 @@ uint8_t btc_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv) return bt_mesh_dfu_srv_progress((struct bt_mesh_dfu_srv *)srv); } #endif /* CONFIG_BLE_MESH_DFU_SRV */ + +#if CONFIG_BLE_MESH_DFD_CLI +static inline void btc_ble_mesh_dfd_client_cb_to_app(btc_ble_mesh_dfd_client_cb_evt_t event, + esp_ble_mesh_dfd_client_cb_param_t *param) +{ + esp_ble_mesh_dfd_client_cb_t btc_ble_mesh_cb = + (esp_ble_mesh_dfd_client_cb_t)btc_profile_cb_get(BTC_PID_DFD_CLIENT); + if (btc_ble_mesh_cb) { + btc_ble_mesh_cb(event, param); + } +} + +static inline bool dfd_client_param_need(uint32_t opcode) +{ + switch (opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX: + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + case ESP_BLE_MESH_DFD_OP_START: + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + return true; + default: + break; + } + return false; +} + +static int btc_ble_mesh_dfd_client_get(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_get_param_t *get) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + + if (dfd_client_param_need(params->opcode) != (!!get)) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + + switch(params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET: + case ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX: + if (get == NULL) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + break; + default: + break; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, false); + + switch (params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_GET: + return bt_mesh_dfd_cli_receivers_get(¶m, get->receivers_get.first_index, + get->receivers_get.entries_limit); + case ESP_BLE_MESH_DFD_OP_CAPABILITIES_GET: + return bt_mesh_dfd_cli_distribution_capabilities_get(¶m); + case ESP_BLE_MESH_DFD_OP_GET: + return bt_mesh_dfd_cli_distribution_get(¶m); + case ESP_BLE_MESH_DFD_OP_UPLOAD_GET: + return bt_mesh_dfd_cli_distribution_upload_get(¶m); + case ESP_BLE_MESH_DFD_OP_FW_GET: + return bt_mesh_dfd_cli_firmware_get(¶m, get->dist_fw_get.fwid); + case ESP_BLE_MESH_DFD_OP_FW_GET_BY_INDEX: + return bt_mesh_dfd_cli_firmware_get_by_index(¶m, get->dist_fw_get_by_idx.dist_fw_idx); + default: + BT_ERR("UknOpc:%04x", params->opcode); + return -EINVAL; + } +} + +static int btc_ble_mesh_dfd_client_set(esp_ble_mesh_client_common_param_t *params, + esp_ble_mesh_dfd_client_set_param_t *set) +{ + bt_mesh_client_common_param_t param = {0}; + + if (params == NULL) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + + if (dfd_client_param_need(params->opcode) != (!!set)) { + BT_ERR("%s:InvParam", __func__); + return -EINVAL; + } + + btc_ble_mesh_set_client_common_param(params, ¶m, false); + + switch (params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + return bt_mesh_dfd_cli_receivers_add(¶m, (dfd_cli_receiver_entry_t *)set->receivers_add.receivers, set->receivers_add.receivers_cnt); + case ESP_BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL: + return bt_mesh_dfd_cli_receivers_delete_all(¶m); + case ESP_BLE_MESH_DFD_OP_START: + return bt_mesh_dfd_cli_distribution_start(¶m, (dfd_cli_dist_start_t *)&set->dist_start); + case ESP_BLE_MESH_DFD_OP_SUSPEND: + return bt_mesh_dfd_cli_distribution_suspend(¶m); + case ESP_BLE_MESH_DFD_OP_CANCEL: + return bt_mesh_dfd_cli_distribution_cancel(¶m); + case ESP_BLE_MESH_DFD_OP_APPLY: + return bt_mesh_dfd_cli_distribution_apply(¶m); + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + return bt_mesh_dfd_cli_distribution_upload_start(¶m, (dfd_cli_dist_upload_start_t *)&set->dist_upload_start); + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + return bt_mesh_dfd_cli_distribution_upload_oob_start(¶m, (dfd_cli_dist_upload_oob_start_t *)&set->dist_upload_oob_start); + case ESP_BLE_MESH_DFD_OP_UPLOAD_CANCEL: + return bt_mesh_dfd_cli_distribution_upload_oob_cancel(¶m); + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + return bt_mesh_dfd_cli_firmware_get_delete(¶m, set->dist_fw_del.fwid); + case ESP_BLE_MESH_DFD_OP_FW_DELETE_ALL: + return bt_mesh_dfd_cli_firmware_delete_all(¶m); + default: + BT_ERR("UknOpc:%04x", params->opcode); + return -EINVAL; + } +} + +void btc_ble_mesh_dfd_client_cb_handler(btc_msg_t *msg) +{ + esp_ble_mesh_dfd_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + arg = (esp_ble_mesh_dfd_client_cb_param_t *)msg->arg; + + if (msg->act < ESP_BLE_MESH_EVT_DFD_CLIENT_MAX) { + btc_ble_mesh_dfd_client_cb_to_app(msg->act, arg); + } else { + BT_ERR("%s, Unknown act %d", __func__, msg->act); + } + + btc_ble_mesh_dfd_client_rsp_deep_free(msg); +} + +void btc_ble_mesh_dfd_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + btc_ble_mesh_dfd_client_args_t *dst = (btc_ble_mesh_dfd_client_args_t *)p_dest; + btc_ble_mesh_dfd_client_args_t *src = (btc_ble_mesh_dfd_client_args_t *)p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s,InvParam", __func__); + return; + } + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFD_CLIENT_GET: + dst->dfd_client_get.params = + (esp_ble_mesh_client_common_param_t *)bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->dfd_client_get.params == NULL) { + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_get.params, src->dfd_client_get.params, sizeof(esp_ble_mesh_client_common_param_t)); + + if (src->dfd_client_get.get) { + dst->dfd_client_get.get = (esp_ble_mesh_dfd_client_get_param_t *)bt_mesh_calloc(sizeof(esp_ble_mesh_dfd_client_get_param_t)); + if (dst->dfd_client_get.get == NULL) { + bt_mesh_free(dst->dfd_client_get.params); + dst->dfd_client_get.params = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_get.get, src->dfd_client_get.get, sizeof(esp_ble_mesh_dfd_client_get_param_t)); + } + + switch (dst->dfd_client_get.params->opcode) { + case ESP_BLE_MESH_DFD_OP_FW_GET: + if (src->dfd_client_get.get->dist_fw_get.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + bt_mesh_free(dst->dfd_client_get.params); + dst->dfd_client_get.params = NULL; + bt_mesh_free(dst->dfd_client_get.get); + dst->dfd_client_get.get = NULL; + break; + } + + dst->dfd_client_get.get->dist_fw_get.fwid = + bt_mesh_alloc_buf(src->dfd_client_get.get->dist_fw_get.fwid->len); + if (dst->dfd_client_get.get->dist_fw_get.fwid == NULL) { + bt_mesh_free(dst->dfd_client_get.params); + dst->dfd_client_get.params = NULL; + bt_mesh_free(dst->dfd_client_get.get); + dst->dfd_client_get.get = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_get.get->dist_fw_get.fwid, + src->dfd_client_get.get->dist_fw_get.fwid->data, + src->dfd_client_get.get->dist_fw_get.fwid->len); + break; + default: + break; + } + break; + case BTC_BLE_MESH_ACT_DFD_CLIENT_SET: + dst->dfd_client_set.params = + (esp_ble_mesh_client_common_param_t *)bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->dfd_client_set.params == NULL) { + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_set.params, src->dfd_client_set.params, sizeof(esp_ble_mesh_client_common_param_t)); + + if (src->dfd_client_set.set) { + dst->dfd_client_set.set = (esp_ble_mesh_dfd_client_set_param_t *)bt_mesh_calloc(sizeof(esp_ble_mesh_dfd_client_set_param_t)); + if (dst->dfd_client_set.set == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_set.set, src->dfd_client_set.set, sizeof(esp_ble_mesh_dfd_client_set_param_t)); + } + switch (dst->dfd_client_set.params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + if (src->dfd_client_set.set->receivers_add.receivers_cnt == 0) { + dst->dfd_client_set.set->receivers_add.receivers = NULL; + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + dst->dfd_client_set.set->receivers_add.receivers = + (esp_ble_mesh_dfd_cli_receiver_entry_t *)bt_mesh_calloc(dst->dfd_client_set.set->receivers_add.receivers_cnt * + sizeof(esp_ble_mesh_dfd_cli_receiver_entry_t)); + if (dst->dfd_client_set.set->receivers_add.receivers == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + memcpy(dst->dfd_client_set.set->receivers_add.receivers, src->dfd_client_set.set->receivers_add.receivers, + dst->dfd_client_set.set->receivers_add.receivers_cnt * sizeof(esp_ble_mesh_dfd_cli_receiver_entry_t)); + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + if (src->dfd_client_set.set->dist_upload_start.fwid == NULL) { + dst->dfd_client_set.set->dist_upload_start.fwid = NULL; + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + + dst->dfd_client_set.set->dist_upload_start.fwid = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_upload_start.fwid->len); + if (dst->dfd_client_set.set->dist_upload_start.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_upload_start.fwid, + src->dfd_client_set.set->dist_upload_start.fwid->data, + src->dfd_client_set.set->dist_upload_start.fwid->len); + + if (src->dfd_client_set.set->dist_upload_start.fw_metadata->len == 0) { + dst->dfd_client_set.set->dist_upload_start.fw_metadata = NULL; + break; + } else { + dst->dfd_client_set.set->dist_upload_start.fw_metadata = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_upload_start.fw_metadata->len); + if (dst->dfd_client_set.set->dist_upload_start.fw_metadata == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + bt_mesh_free_buf(dst->dfd_client_set.set->dist_upload_start.fwid); + dst->dfd_client_set.set->dist_upload_start.fwid = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_upload_start.fw_metadata, + src->dfd_client_set.set->dist_upload_start.fw_metadata->data, + src->dfd_client_set.set->dist_upload_start.fw_metadata->len); + } + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + if (src->dfd_client_set.set->dist_upload_oob_start.url == NULL || + src->dfd_client_set.set->dist_upload_oob_start.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + dst->dfd_client_set.set->dist_upload_oob_start.url = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_upload_oob_start.url->len); + if (dst->dfd_client_set.set->dist_upload_oob_start.url == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + dst->dfd_client_set.set->dist_upload_oob_start.fwid = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_upload_oob_start.fwid->len); + if (dst->dfd_client_set.set->dist_upload_oob_start.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + bt_mesh_free_buf(dst->dfd_client_set.set->dist_upload_oob_start.url); + dst->dfd_client_set.set->dist_upload_oob_start.url = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_upload_oob_start.url, + src->dfd_client_set.set->dist_upload_oob_start.url->data, + src->dfd_client_set.set->dist_upload_oob_start.url->len); + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_upload_oob_start.fwid, + src->dfd_client_set.set->dist_upload_oob_start.fwid->data, + src->dfd_client_set.set->dist_upload_oob_start.fwid->len); + break; + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + if (src->dfd_client_set.set->dist_fw_del.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + dst->dfd_client_set.set->dist_fw_del.fwid = + bt_mesh_alloc_buf(src->dfd_client_set.set->dist_fw_del.fwid->len); + if (dst->dfd_client_set.set->dist_fw_del.fwid == NULL) { + bt_mesh_free(dst->dfd_client_set.params); + dst->dfd_client_set.params = NULL; + bt_mesh_free(dst->dfd_client_set.set); + dst->dfd_client_set.set = NULL; + BT_ERR("%s:%d,OutMem", __func__, __LINE__); + break; + } + net_buf_simple_add_mem( + dst->dfd_client_set.set->dist_fw_del.fwid, + src->dfd_client_set.set->dist_fw_del.fwid->data, + src->dfd_client_set.set->dist_fw_del.fwid->len); + break; + default: + break; + } + default: + BT_DBG("%s, Unknown act %d", __func__, msg->act); + break; + } +} + +void btc_ble_mesh_dfd_client_arg_deep_free(btc_msg_t *msg) +{ + btc_ble_mesh_dfd_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + if (msg->act >= ESP_BLE_MESH_ACT_DFD_CLIENT_MAX) { + BT_ERR("%s, Invalid event %d", __func__, msg->act); + return; + } + + arg = (btc_ble_mesh_dfd_client_args_t *)msg->arg; + + switch (msg->act) { + case ESP_BLE_MESH_ACT_DFD_CLIENT_GET: + if (arg->dfd_client_get.params == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + switch (arg->dfd_client_get.params->opcode) { + case ESP_BLE_MESH_DFD_OP_FW_GET: + if (arg->dfd_client_get.get->dist_fw_get.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free_buf(arg->dfd_client_get.get->dist_fw_get.fwid); + break; + default: + break; + } + if (arg->dfd_client_get.get) { + bt_mesh_free(arg->dfd_client_get.get); + } + bt_mesh_free(arg->dfd_client_get.params); + break; + case ESP_BLE_MESH_ACT_DFD_CLIENT_SET: + if (arg->dfd_client_set.params == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + switch (arg->dfd_client_set.params->opcode) { + case ESP_BLE_MESH_DFD_OP_RECEIVERS_ADD: + if (arg->dfd_client_set.set->receivers_add.receivers == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free(arg->dfd_client_set.set->receivers_add.receivers); + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START: + if (arg->dfd_client_set.set->dist_upload_start.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free_buf(arg->dfd_client_set.set->dist_upload_start.fwid); + if (arg->dfd_client_set.set->dist_upload_start.fw_metadata) { + bt_mesh_free_buf(arg->dfd_client_set.set->dist_upload_start.fw_metadata); + } + break; + case ESP_BLE_MESH_DFD_OP_UPLOAD_START_OOB: + if (arg->dfd_client_set.set->dist_upload_oob_start.url == NULL || + arg->dfd_client_set.set->dist_upload_oob_start.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free_buf(arg->dfd_client_set.set->dist_upload_oob_start.url); + bt_mesh_free_buf(arg->dfd_client_set.set->dist_upload_oob_start.fwid); + break; + case ESP_BLE_MESH_DFD_OP_FW_DELETE: + if (arg->dfd_client_set.set->dist_fw_del.fwid == NULL) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + break; + } + bt_mesh_free_buf(arg->dfd_client_set.set->dist_fw_del.fwid); + break; + } + if (arg->dfd_client_set.set) { + bt_mesh_free(arg->dfd_client_set.set); + } + bt_mesh_free(arg->dfd_client_set.params); + break; + default: + BT_WARN("Unprocessed event %d", msg->act); + break; + } + + return; +} + +void btc_ble_mesh_dfd_client_rsp_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src) +{ + esp_ble_mesh_dfd_client_cb_param_t *dst =(esp_ble_mesh_dfd_client_cb_param_t *) p_dest; + esp_ble_mesh_dfd_client_cb_param_t *src =(esp_ble_mesh_dfd_client_cb_param_t *) p_src; + + if (!msg || !dst || !src) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + dst->err_code = src->err_code; + + if (src->params) { + dst->params = bt_mesh_calloc(sizeof(esp_ble_mesh_client_common_param_t)); + if (dst->params == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + memcpy(dst->params, src->params, sizeof(esp_ble_mesh_client_common_param_t)); + } + + switch (msg->act) { + case ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP: + switch(dst->params->opcode) { + case BLE_MESH_DFD_OP_RECEIVERS_LIST: + dst->status_cb.receiver_list.first_index = src->status_cb.receiver_list.first_index; + dst->status_cb.receiver_list.entries_cnt = src->status_cb.receiver_list.entries_cnt; + if (dst->status_cb.receiver_list.entries_cnt) { + dst->status_cb.receiver_list.entries = bt_mesh_calloc(sizeof(esp_ble_mesh_dfd_target_node_entry_t) * dst->status_cb.receiver_list.entries_cnt); + if (dst->status_cb.receiver_list.entries == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + memcpy(dst->status_cb.receiver_list.entries, src->status_cb.receiver_list.entries, + sizeof(esp_ble_mesh_dfd_target_node_entry_t) * dst->status_cb.receiver_list.entries_cnt); + } else { + dst->status_cb.receiver_list.entries = NULL; + } + break; + case BLE_MESH_DFD_OP_CAPABILITIES_STATUS: + dst->status_cb.dist_caps.max_receiver_list_sz = src->status_cb.dist_caps.max_receiver_list_sz; + dst->status_cb.dist_caps.max_fw_list_sz = src->status_cb.dist_caps.max_fw_list_sz; + dst->status_cb.dist_caps.max_fw_sz = src->status_cb.dist_caps.max_fw_sz; + dst->status_cb.dist_caps.max_upload_space = src->status_cb.dist_caps.max_upload_space; + dst->status_cb.dist_caps.remaining_upload_space = src->status_cb.dist_caps.remaining_upload_space; + dst->status_cb.dist_caps.oob_retrieval_supported = src->status_cb.dist_caps.oob_retrieval_supported; + if (src->status_cb.dist_caps.supported_url_scheme_names) { + dst->status_cb.dist_caps.supported_url_scheme_names = + bt_mesh_alloc_buf(src->status_cb.dist_caps.supported_url_scheme_names->len); + if (dst->status_cb.dist_caps.supported_url_scheme_names == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + net_buf_simple_add_mem( + dst->status_cb.dist_caps.supported_url_scheme_names, + src->status_cb.dist_caps.supported_url_scheme_names->data, + src->status_cb.dist_caps.supported_url_scheme_names->len); + } else { + dst->status_cb.dist_caps.supported_url_scheme_names = NULL; + } + break; + case BLE_MESH_DFD_OP_UPLOAD_STATUS: + dst->status_cb.upload_status.status = src->status_cb.upload_status.status; + dst->status_cb.upload_status.upload_phase = src->status_cb.upload_status.upload_phase; + dst->status_cb.upload_status.upload_progress = src->status_cb.upload_status.upload_progress; + dst->status_cb.upload_status.upload_type = src->status_cb.upload_status.upload_type; + + if (dst->status_cb.upload_status.upload_progress == ESP_BLE_MESH_DFD_UPLOAD_PROGRESS_UNSET) { + dst->status_cb.upload_status.fwid = NULL; + return; + } + + if (dst->status_cb.upload_status.upload_type == ESP_BLE_MESH_DFD_UPLOAD_TYPE_INBAND) { + if (src->status_cb.upload_status.fwid) { + dst->status_cb.upload_status.fwid = bt_mesh_alloc_buf(src->status_cb.upload_status.fwid->len); + if (dst->status_cb.upload_status.fwid == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + net_buf_simple_add_mem( + dst->status_cb.upload_status.fwid, + src->status_cb.upload_status.fwid->data, + src->status_cb.upload_status.fwid->len); + } else { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + } + } else { + if(src->status_cb.upload_status.oob_fwid) { + dst->status_cb.upload_status.oob_fwid = bt_mesh_alloc_buf(src->status_cb.upload_status.oob_fwid->len); + if (dst->status_cb.upload_status.oob_fwid == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + net_buf_simple_add_mem( + dst->status_cb.upload_status.oob_fwid, + src->status_cb.upload_status.oob_fwid->data, + src->status_cb.upload_status.oob_fwid->len); + } else { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + } + } + break; + case BLE_MESH_DFD_OP_FW_STATUS: + dst->status_cb.firmware_status.status = src->status_cb.firmware_status.status; + dst->status_cb.firmware_status.entry_cnt = src->status_cb.firmware_status.entry_cnt; + dst->status_cb.firmware_status.fw_idx = src->status_cb.firmware_status.fw_idx; + if (src->status_cb.firmware_status.fwid) { + dst->status_cb.firmware_status.fwid = bt_mesh_alloc_buf(src->status_cb.firmware_status.fwid->len); + if (dst->status_cb.firmware_status.fwid == NULL) { + BT_ERR("%s:%d,OutOfMem", __func__, __LINE__); + return; + } + net_buf_simple_add_mem( + dst->status_cb.firmware_status.fwid, + src->status_cb.firmware_status.fwid->data, + src->status_cb.firmware_status.fwid->len); + } else { + dst->status_cb.firmware_status.fwid = NULL; + } + break; + case BLE_MESH_DFD_OP_RECEIVERS_STATUS: + dst->status_cb.receiver_status.status = src->status_cb.receiver_status.status; + dst->status_cb.receiver_status.receiver_list_cnt = src->status_cb.receiver_status.receiver_list_cnt; + break; + case BLE_MESH_DFD_OP_STATUS: + dst->status_cb.dist_status.status = src->status_cb.dist_status.status; + dst->status_cb.dist_status.dist_phase = src->status_cb.dist_status.dist_phase; + dst->status_cb.dist_status.multicast_address = src->status_cb.dist_status.multicast_address; + dst->status_cb.dist_status.appkey_idx = src->status_cb.dist_status.appkey_idx; + dst->status_cb.dist_status.ttl = src->status_cb.dist_status.ttl; + dst->status_cb.dist_status.timeout_base = src->status_cb.dist_status.timeout_base; + dst->status_cb.dist_status.trans_mode = src->status_cb.dist_status.trans_mode; + dst->status_cb.dist_status.update_policy = src->status_cb.dist_status.update_policy; + dst->status_cb.dist_status.firmware_image_index = src->status_cb.dist_status.firmware_image_index; + break; + default: + BT_ERR("Unknown opcode %04x", dst->params->opcode); + break; + + } + break; + case ESP_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT: + break; + case ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP: + break; + default: + BT_ERR("Unknown event %d", msg->act); + } + +} + +void btc_ble_mesh_dfd_client_rsp_deep_free(btc_msg_t *msg) +{ + esp_ble_mesh_dfd_client_cb_param_t *arg = NULL; + + if (!msg) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + return; + } + + arg = (esp_ble_mesh_dfd_client_cb_param_t *)(msg->arg); + + if (arg->params == NULL && + msg->act != ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP) { + BT_ERR("%s:%d,InvParam", __func__, __LINE__); + return; + } + + switch (msg->act) { + case ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP: + switch (arg->params->opcode) { + case BLE_MESH_DFD_OP_RECEIVERS_LIST: + if (arg->status_cb.receiver_list.entries) { + bt_mesh_free(arg->status_cb.receiver_list.entries); + arg->status_cb.receiver_list.entries = NULL; + } + break; + case BLE_MESH_DFD_OP_CAPABILITIES_STATUS: + if (arg->status_cb.dist_caps.supported_url_scheme_names) { + bt_mesh_free_buf(arg->status_cb.dist_caps.supported_url_scheme_names); + arg->status_cb.dist_caps.supported_url_scheme_names = NULL; + } + break; + case BLE_MESH_DFD_OP_UPLOAD_STATUS: + /** + * firmware_id and upload_oob_firmware_id are a union + * structure, so only one pointer needs to be released + */ + if (arg->status_cb.upload_status.fwid) { + bt_mesh_free_buf(arg->status_cb.upload_status.fwid); + arg->status_cb.upload_status.fwid = NULL; + } + break; + case BLE_MESH_DFD_OP_FW_STATUS: + if (arg->status_cb.firmware_status.fwid) { + bt_mesh_free_buf(arg->status_cb.firmware_status.fwid); + arg->status_cb.firmware_status.fwid = NULL; + } + break; + } + break; + default: + break; + } + + if (arg->params) { + bt_mesh_free(arg->params); + } +} + +static void btc_ble_mesh_dfd_client_callback(esp_ble_mesh_dfd_client_cb_param_t *cb_params, + uint8_t act) +{ + btc_msg_t msg = {0}; + + /* If corresponding callback is not registered, event will not be posted. */ + if (!btc_profile_cb_get(BTC_PID_DFD_CLIENT)) { + return; + } + + msg.sig = BTC_SIG_API_CB; + msg.pid = BTC_PID_DFD_CLIENT; + msg.act = act; + + btc_transfer_context(&msg, cb_params, cb_params == NULL ? 0 : sizeof(esp_ble_mesh_dfd_client_cb_param_t), + btc_ble_mesh_dfd_client_rsp_deep_copy, btc_ble_mesh_dfd_client_rsp_deep_free); +} + +void bt_mesh_dfd_client_cb_evt_to_btc(btc_ble_mesh_dfd_client_cb_evt_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len) +{ + esp_ble_mesh_dfd_client_cb_param_t cb_params = {0}; + esp_ble_mesh_client_common_param_t params = {0}; + uint8_t act = 0U; + + if (!model || !ctx || len > sizeof(cb_params.status_cb)) { + BT_ERR("%s, Invalid parameter", __func__); + return; + } + + switch (event) { + case BTC_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP: + act = ESP_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP; + break; + case BTC_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT: + act = ESP_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT; + break; + default: + BT_ERR("Unknown event %d", event); + break; + } + + params.opcode = ctx->recv_op; + params.model = (esp_ble_mesh_model_t *)model; + btc_ble_mesh_msg_ctx_copy((struct bt_mesh_msg_ctx *)¶ms.ctx, ctx, false); + + cb_params.params = ¶ms; + cb_params.err_code = 0; + + if (val && len) { + memcpy(&cb_params.status_cb, val, len); + } + + btc_ble_mesh_dfd_client_callback(&cb_params, act); + return; +} + +void btc_ble_mesh_dfd_client_call_handler(btc_msg_t *msg) +{ + esp_ble_mesh_dfd_client_cb_param_t cb = {0}; + btc_ble_mesh_dfd_client_args_t *arg = NULL; + + if (!msg) { + BT_ERR("%s,InvParam", __func__); + return; + } + + arg = (btc_ble_mesh_dfd_client_args_t *)msg->arg; + + switch (msg->act) { + case BTC_BLE_MESH_ACT_DFD_CLIENT_GET: + cb.params = arg->dfd_client_get.params; + cb.err_code = btc_ble_mesh_dfd_client_get(arg->dfd_client_get.params, arg->dfd_client_get.get); + btc_ble_mesh_dfd_client_callback(&cb, ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP); + break; + case BTC_BLE_MESH_ACT_DFD_CLIENT_SET: + cb.params = arg->dfd_client_set.params; + cb.err_code = btc_ble_mesh_dfd_client_set(arg->dfd_client_set.params, arg->dfd_client_set.set); + btc_ble_mesh_dfd_client_callback(&cb, ESP_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP); + break; + default: + break; + } + + btc_ble_mesh_dfd_client_arg_deep_free(msg); +} +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +#if CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD +int btc_ble_mesh_dfd_srv_oob_check_complete(struct esp_ble_mesh_dfd_srv *srv, + const struct esp_ble_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len) +{ + bt_mesh_dfd_srv_oob_check_complete((struct bt_mesh_dfd_srv *)srv, (struct bt_mesh_dfu_slot *)slot, status, fwid, fwid_len); + return 0; +} +int btc_ble_mesh_dfd_srv_oob_store_complete(struct esp_ble_mesh_dfd_srv *srv, + const struct esp_ble_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len) +{ + bt_mesh_dfd_srv_oob_store_complete((struct bt_mesh_dfd_srv *)srv, (struct bt_mesh_dfu_slot *)slot, success, size, metadata, metadata_len); + return 0; +} +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ +#endif /* CONFIG_BLE_MESH_DFD_SRV */ diff --git a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h index a74aeb5453..0111e86549 100644 --- a/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h +++ b/components/bt/esp_ble_mesh/v1.1/btc/include/btc_ble_mesh_dfu_model.h @@ -67,6 +67,55 @@ bool btc_ble_mesh_dfu_srv_is_busy(const esp_ble_mesh_dfu_srv_t *srv); uint8_t btc_ble_mesh_dfu_srv_progress(const esp_ble_mesh_dfu_srv_t *srv); #endif /* CONFIG_BLE_MESH_DFU_SRV */ +#if CONFIG_BLE_MESH_DFD_CLI +typedef enum { + BTC_BLE_MESH_ACT_DFD_CLIENT_GET, + BTC_BLE_MESH_ACT_DFD_CLIENT_SET, + BTC_BLE_MESH_ACT_DFD_CLIEND_SEND_COMP, + BTC_BLE_MESH_ACT_DFD_CLIENT_MAX, +} btc_ble_mesh_dfd_client_act_t; + +typedef enum { + BTC_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT, + BTC_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP, + BTC_BLE_MESH_EVT_DFD_CLIENT_MAX, +} btc_ble_mesh_dfd_client_cb_evt_t; + +typedef union { + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_dfd_client_get_param_t *get; + } dfd_client_get; + struct { + esp_ble_mesh_client_common_param_t *params; + esp_ble_mesh_dfd_client_set_param_t *set; + } dfd_client_set; +} btc_ble_mesh_dfd_client_args_t; + +void btc_ble_mesh_dfd_client_cb_handler(btc_msg_t *msg); +void btc_ble_mesh_dfd_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); +void btc_ble_mesh_dfd_client_arg_deep_free(btc_msg_t *msg); +void btc_ble_mesh_dfd_client_rsp_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src); +void btc_ble_mesh_dfd_client_rsp_deep_free(btc_msg_t *msg); +void bt_mesh_dfd_client_cb_evt_to_btc(btc_ble_mesh_dfd_client_cb_evt_t event, + struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const uint8_t *val, size_t len); +void btc_ble_mesh_dfd_client_call_handler(btc_msg_t *msg); + +#endif /* CONFIG_BLE_MESH_DFD_CLI */ + +#if CONFIG_BLE_MESH_DFD_SRV +#if CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD +int btc_ble_mesh_dfd_srv_oob_check_complete(struct esp_ble_mesh_dfd_srv *srv, + const struct esp_ble_mesh_dfu_slot *slot, int status, + uint8_t *fwid, size_t fwid_len); +int btc_ble_mesh_dfd_srv_oob_store_complete(struct esp_ble_mesh_dfd_srv *srv, + const struct esp_ble_mesh_dfu_slot *slot, bool success, + size_t size, const uint8_t *metadata, size_t metadata_len); +#endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ +#endif /* CONFIG_BLE_MESH_DFD_SRV */ + #ifdef __cplusplus } #endif diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h b/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h deleted file mode 100644 index ee94be24e6..0000000000 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfd.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA - * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "access.h" - -/* @todo: adapt to dfd client */ -#if CONFIG_BLE_MESH_DFD_SRV -#define BT_MESH_DFD_OP_RECEIVERS_ADD BLE_MESH_MODEL_OP_2(0x83, 0x11) -#define BT_MESH_DFD_OP_RECEIVERS_DELETE_ALL BLE_MESH_MODEL_OP_2(0x83, 0x12) -#define BT_MESH_DFD_OP_RECEIVERS_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x13) -#define BT_MESH_DFD_OP_RECEIVERS_GET BLE_MESH_MODEL_OP_2(0x83, 0x14) -#define BT_MESH_DFD_OP_RECEIVERS_LIST BLE_MESH_MODEL_OP_2(0x83, 0x15) -#define BT_MESH_DFD_OP_CAPABILITIES_GET BLE_MESH_MODEL_OP_2(0x83, 0x16) -#define BT_MESH_DFD_OP_CAPABILITIES_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x17) -#define BT_MESH_DFD_OP_GET BLE_MESH_MODEL_OP_2(0x83, 0x18) -#define BT_MESH_DFD_OP_START BLE_MESH_MODEL_OP_2(0x83, 0x19) -#define BT_MESH_DFD_OP_SUSPEND BLE_MESH_MODEL_OP_2(0x83, 0x1a) -#define BT_MESH_DFD_OP_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x1b) -#define BT_MESH_DFD_OP_APPLY BLE_MESH_MODEL_OP_2(0x83, 0x1c) -#define BT_MESH_DFD_OP_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x1d) -#define BT_MESH_DFD_OP_UPLOAD_GET BLE_MESH_MODEL_OP_2(0x83, 0x1e) -#define BT_MESH_DFD_OP_UPLOAD_START BLE_MESH_MODEL_OP_2(0x83, 0x1f) -#define BT_MESH_DFD_OP_UPLOAD_START_OOB BLE_MESH_MODEL_OP_2(0x83, 0x20) -#define BT_MESH_DFD_OP_UPLOAD_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x21) -#define BT_MESH_DFD_OP_UPLOAD_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x22) -#define BT_MESH_DFD_OP_FW_GET BLE_MESH_MODEL_OP_2(0x83, 0x23) -#define BT_MESH_DFD_OP_FW_GET_BY_INDEX BLE_MESH_MODEL_OP_2(0x83, 0x24) -#define BT_MESH_DFD_OP_FW_DELETE BLE_MESH_MODEL_OP_2(0x83, 0x25) -#define BT_MESH_DFD_OP_FW_DELETE_ALL BLE_MESH_MODEL_OP_2(0x83, 0x26) -#define BT_MESH_DFD_OP_FW_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x27) -#endif diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_cli.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_cli.c new file mode 100644 index 0000000000..19fce3b9a8 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_cli.c @@ -0,0 +1,699 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "dfu_slot.h" +#include "dfu.h" +#include "net.h" +#include "transport.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" +#include "btc_ble_mesh_dfu_model.h" + +#include "mesh_v1.1/dfu/dfd_cli.h" + +#if CONFIG_BLE_MESH_DFD_CLI +static const bt_mesh_client_op_pair_t dfd_cli_pair[] = { + {BLE_MESH_DFD_OP_RECEIVERS_ADD, BLE_MESH_DFD_OP_RECEIVERS_STATUS}, + {BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL, BLE_MESH_DFD_OP_RECEIVERS_STATUS}, + {BLE_MESH_DFD_OP_RECEIVERS_GET, BLE_MESH_DFD_OP_RECEIVERS_LIST}, + {BLE_MESH_DFD_OP_CAPABILITIES_GET, BLE_MESH_DFD_OP_CAPABILITIES_STATUS}, + {BLE_MESH_DFD_OP_GET, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_START, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_SUSPEND, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_CANCEL, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_APPLY, BLE_MESH_DFD_OP_STATUS}, + {BLE_MESH_DFD_OP_UPLOAD_GET, BLE_MESH_DFD_OP_UPLOAD_STATUS}, + {BLE_MESH_DFD_OP_UPLOAD_START, BLE_MESH_DFD_OP_UPLOAD_STATUS}, + {BLE_MESH_DFD_OP_UPLOAD_START_OOB, BLE_MESH_DFD_OP_UPLOAD_STATUS}, + {BLE_MESH_DFD_OP_UPLOAD_CANCEL, BLE_MESH_DFD_OP_UPLOAD_STATUS}, + {BLE_MESH_DFD_OP_FW_GET, BLE_MESH_DFD_OP_FW_STATUS}, + {BLE_MESH_DFD_OP_FW_GET_BY_INDEX, BLE_MESH_DFD_OP_FW_STATUS}, + {BLE_MESH_DFD_OP_FW_DELETE, BLE_MESH_DFD_OP_FW_STATUS}, + {BLE_MESH_DFD_OP_FW_DELETE_ALL, BLE_MESH_DFD_OP_FW_STATUS}, +}; + +static bt_mesh_mutex_t dfd_client_lock; + +static void timeout_handler(struct k_work *work) +{ + struct k_delayed_work *timer = NULL; + bt_mesh_client_node_t *node = NULL; + + BT_WARN("DFDRspTmo"); + + bt_mesh_mutex_lock(&dfd_client_lock); + + timer = CONTAINER_OF(work, struct k_delayed_work, work); + + if (timer && !k_delayed_work_free(timer)) { + node = CONTAINER_OF(work, bt_mesh_client_node_t, timer.work); + if (node) { + bt_mesh_dfd_client_cb_evt_to_btc(BTC_BLE_MESH_EVT_DFD_CLIENT_TIMEOUT, node->model, &node->ctx, NULL, 0); + bt_mesh_client_free_node(node); + } + } + + bt_mesh_mutex_unlock(&dfd_client_lock); + + return; +} + +static void dfd_client_recv_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + void *status, size_t len) +{ + bt_mesh_client_node_t *node = NULL; + struct net_buf_simple buf = {0}; + btc_ble_mesh_dfd_client_cb_evt_t evt = 0; + + if (!model || !ctx) { + BT_ERR("%s,InvParam", __func__); + return; + } + + buf.data = (uint8_t *)status; + buf.len = (uint16_t)len; + + bt_mesh_mutex_lock(&dfd_client_lock); + + node = bt_mesh_is_client_recv_publish_msg(model, ctx, &buf, true); + if (!node) { + BT_DBG("UnexpDfdStus:0x%04x", ctx->recv_op); + } else { + switch (ctx->recv_op) { + case BLE_MESH_DFD_OP_RECEIVERS_STATUS: + case BLE_MESH_DFD_OP_CAPABILITIES_GET: + case BLE_MESH_DFD_OP_RECEIVERS_LIST: + case BLE_MESH_DFD_OP_CAPABILITIES_STATUS: + case BLE_MESH_DFD_OP_STATUS: + case BLE_MESH_DFD_OP_UPLOAD_STATUS: + case BLE_MESH_DFD_OP_FW_STATUS: + evt = BTC_BLE_MESH_EVT_DFD_CLIENT_RECV_RSP; + break; + default: + BT_ERR("UnkwnOpc:%04x", node->opcode); + break; + } + + if (!k_delayed_work_free(&node->timer)) { + bt_mesh_dfd_client_cb_evt_to_btc(evt, model, ctx, (const uint8_t *)status, len); + bt_mesh_client_free_node(node); + } + } + + bt_mesh_mutex_unlock(&dfd_client_lock); +} + +static void handle_receiver_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + + status.receiver_status.status = net_buf_simple_pull_u8(buf); + + if (status.receiver_status.status > BLE_MESH_DFD_ERR_SUSPEND_FAILED) { + BT_ERR("InvSrvStu:%d", status.receiver_status.status); + return; + } + + if (status.receiver_status.status != BLE_MESH_DFD_SUCCESS) { + BT_ERR("StusErr:%d", status); + return; + } + + status.receiver_status.receiver_list_cnt = net_buf_simple_pull_le16(buf); + + BT_DBG("RecvLstCnt:%d", status.receiver_status.receiver_list_cnt); + + dfd_client_recv_status(model, ctx, &status, sizeof(status.receiver_status)); +} + +static void handle_receiver_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + int i = 0; + uint32_t target_info = 0; + + dfd_status_t status = {0}; + status.receiver_list.entries_cnt = net_buf_simple_pull_le16(buf); + status.receiver_list.first_index = net_buf_simple_pull_le16(buf); + status.receiver_list.entries = bt_mesh_calloc(status.receiver_list.entries_cnt * sizeof(target_node_entry_t)); + for (i = 0; i < status.receiver_list.entries_cnt; i++) { + target_info = net_buf_simple_pull_le32(buf); + status.receiver_list.entries[i].addr = TARGET_ADDR(target_info); + status.receiver_list.entries[i].retrieved_update_phase = TARGET_UPDATE_PHASE(target_info); + status.receiver_list.entries[i].update_status = TARGET_UPDATE_STATUS(target_info); + status.receiver_list.entries[i].transfer_status = TARGET_TRANSFER_STATUS(target_info); + status.receiver_list.entries[i].transfer_progress = TARGET_TRANSFER_PROGRESS(target_info); + status.receiver_list.entries[i].update_fw_idx = net_buf_simple_pull_u8(buf); + } + dfd_client_recv_status(model, ctx, &status, sizeof(status.receiver_list)); + bt_mesh_free(status.receiver_list.entries); + return; +} + +static void handle_capabilities(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + struct net_buf_simple url_scheme_names = {0}; + + status.dist_caps.max_receiver_list_sz = net_buf_simple_pull_le16(buf); + status.dist_caps.max_fw_list_sz = net_buf_simple_pull_le16(buf); + status.dist_caps.max_fw_sz = net_buf_simple_pull_le32(buf); + status.dist_caps.max_upload_space = net_buf_simple_pull_le32(buf); + status.dist_caps.remaining_upload_space = net_buf_simple_pull_le32(buf); + status.dist_caps.oob_retrieval_supported = net_buf_simple_pull_le32(buf); + if (buf->len) { + status.dist_caps.supported_url_scheme_names = &url_scheme_names; + net_buf_simple_init_with_data(status.dist_caps.supported_url_scheme_names, buf->data, buf->len); + net_buf_simple_pull_mem(buf, buf->len); + } + dfd_client_recv_status(model, ctx, &status, sizeof(status.dist_caps)); + return; +} + +static void handle_dfd_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + uint8_t trans_mode_policy = 0; + + status.dist_status.status = net_buf_simple_pull_u8(buf); + status.dist_status.dist_phase = net_buf_simple_pull_u8(buf); + if (buf->len != 0 && buf->len != 10) { + BT_ERR("Invalid data"); + return; + } + status.dist_status.multicast_address = net_buf_simple_pull_le16(buf); + status.dist_status.appkey_idx = net_buf_simple_pull_le16(buf); + status.dist_status.ttl = net_buf_simple_pull_u8(buf); + status.dist_status.timeout_base = net_buf_simple_pull_le16(buf); + + trans_mode_policy = net_buf_simple_pull_u8(buf); + if ((trans_mode_policy & ~(BIT6 - 1)) != 0) { + BT_ERR("RFU should be zero"); + return; + } + status.dist_status.trans_mode = trans_mode_policy >> 6; + status.dist_status.update_policy = (trans_mode_policy >> 5) & 0x01; + status.dist_status.RFU = trans_mode_policy & 0x1f; + status.dist_status.fw_idx = net_buf_simple_pull_le16(buf); + dfd_client_recv_status(model, ctx, &status, sizeof(status.dist_status)); + return; +} + +static void handle_upload_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + uint8_t progress_type = 0; + struct net_buf_simple buf_cache = {0}; + status.upload_status.status = net_buf_simple_pull_u8(buf); + status.upload_status.upload_phase = net_buf_simple_pull_u8(buf); + + if (buf->len == 0) { + status.upload_status.upload_progress = UPLOAD_PROGRESS_UNSET; + dfd_client_recv_status(model, ctx, &status, sizeof(status.upload_status)); + return; + } + + progress_type = net_buf_simple_pull_u8(buf); + status.upload_status.upload_progress = progress_type>>1; + + if (status.upload_status.upload_progress >= UPLOAD_PROGRESS_UNSET) { + BT_ERR("Invalid upload progress"); + return; + } + + if (buf->len == 0) { + BT_ERR("InvFwID"); + return; + } + + status.upload_status.upload_type = progress_type & 0x01; + if (status.upload_status.upload_type == UPLOAD_IN_BAND) { + status.upload_status.fwid = &buf_cache; + net_buf_simple_init_with_data(status.upload_status.fwid, buf->data, buf->len); + net_buf_simple_pull_mem(buf, buf->len); + } else if (status.upload_status.upload_type == UPLOAD_OOB){ + status.upload_status.oob_fwid = &buf_cache; + net_buf_simple_init_with_data(status.upload_status.oob_fwid, buf->data, buf->len); + net_buf_simple_pull_mem(buf, buf->len); + } else { + BT_ERR("Invalid upload type:%d", status.upload_status.upload_type); + return; + } + + dfd_client_recv_status(model, ctx, &status, sizeof(status.upload_status)); + return; +} + +static void handle_fw_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *buf) +{ + dfd_status_t status = {0}; + struct net_buf_simple buf_cache = {0}; + status.firmware_status.status = net_buf_simple_pull_u8(buf); + status.firmware_status.entry_cnt = net_buf_simple_pull_le16(buf); + status.firmware_status.firmware_image_index = net_buf_simple_pull_le16(buf); + if (buf->len) { + status.firmware_status.fwid = &buf_cache; + net_buf_simple_init_with_data(status.firmware_status.fwid, buf->data, buf->len); + net_buf_simple_pull_mem(buf, buf->len); + } + + dfd_client_recv_status(model, ctx, &status, sizeof(status.firmware_status)); + return; +} + +const struct bt_mesh_model_op _bt_mesh_dfd_cli_op[] = { + { BLE_MESH_DFD_OP_RECEIVERS_STATUS, 3, handle_receiver_status }, + { BLE_MESH_DFD_OP_RECEIVERS_LIST, 4 , handle_receiver_list }, + { BLE_MESH_DFD_OP_CAPABILITIES_STATUS, 17, handle_capabilities }, + { BLE_MESH_DFD_OP_STATUS, 2, handle_dfd_status }, + { BLE_MESH_DFD_OP_UPLOAD_STATUS, 2, handle_upload_status }, + { BLE_MESH_DFD_OP_FW_STATUS, 5, handle_fw_status }, +}; + +int bt_mesh_dfd_cli_receivers_add(bt_mesh_client_common_param_t *param, dfd_cli_receiver_entry_t *receivers, uint16_t receivers_cnt) +{ + uint16_t msg_length = 2; + struct net_buf_simple *msg = NULL; + dfd_cli_receiver_entry_t *entry = NULL; + int err = 0; + + if (param == NULL) { + BT_ERR("Invalid param"); + return -EINVAL; + } + + BT_INFO("AddedValidCnt:%d", receivers_cnt); + msg_length += (receivers_cnt * 3); + + /* needs to confirm long or short mic */ + if (msg_length > BLE_MESH_MAX_PDU_LEN_WITH_SMIC) { + BT_ERR("Too much receivers added once time"); + return -EINVAL; + } + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_RECEIVERS_ADD); + + for (int i = 0; i < receivers_cnt; i++) { + entry = &receivers[i]; + if (BLE_MESH_ADDR_IS_UNICAST(entry->addr)) { + net_buf_simple_add_le16(msg, entry->addr); + net_buf_simple_add_u8(msg, entry->fw_idx); + BT_INFO("AddedUnicastAddr:0x%04x,FwIdx:%d", entry->addr, entry->fw_idx); + } + } + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_receivers_delete_all(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL); + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_receivers_get(bt_mesh_client_common_param_t *param, uint16_t first_index, uint16_t entries_limit) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_RECEIVERS_GET, 4); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_RECEIVERS_GET); + net_buf_simple_add_le16(&msg, first_index); + net_buf_simple_add_le16(&msg, entries_limit); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_capabilities_get(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_CAPABILITIES_GET, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_CAPABILITIES_GET); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_get(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_GET, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_GET); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_start_t *start) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_START, 2 + 1 + 2 + 1 + 2 + 16); + if (!param || !start) { + BT_ERR("Invalid param"); + return -EINVAL; + } + + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_START); + net_buf_simple_add_le16(&msg, start->app_idx); + net_buf_simple_add_u8(&msg, start->ttl); + net_buf_simple_add_le16(&msg, start->timeout_base); + net_buf_simple_add_u8(&msg, ((start->trans_mode) << 6) | ((start->update_policy) << 5)); + net_buf_simple_add_le16(&msg, start->fw_idx); + + if (start->is_va) { + net_buf_simple_add_mem(&msg, &(start->label_uuid), 16); + } else { + net_buf_simple_add_le16(&msg, start->group_addr); + } + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_suspend(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_SUSPEND, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_SUSPEND); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_cancel(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_CANCEL, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_CANCEL); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_apply(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_APPLY, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_APPLY); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_upload_get(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_UPLOAD_GET, 0); + if (!param) { + BT_ERR("Invalid param"); + return -EINVAL; + } + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_UPLOAD_GET); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_distribution_upload_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_upload_start_t *start) +{ + struct net_buf_simple *msg = NULL; + uint16_t msg_length = 2; + int err = 0; + + if (!param || !start) { + BT_ERR("Invalid param"); + return -EINVAL; + } + + msg_length += (1 + 2 + 8 + 4 + 1 + start->fwid->len); + if (start->fw_metadata) { + msg_length += start->fw_metadata->len; + } + + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_UPLOAD_START); + net_buf_simple_add_u8(msg, start->ttl); + net_buf_simple_add_le16(msg, start->timeout_base); + net_buf_simple_add_le64(msg, start->blob_id); + net_buf_simple_add_le32(msg, start->fw_size); + if (start->fw_metadata) { + net_buf_simple_add_u8(msg, start->fw_metadata->len); + net_buf_simple_add_mem(msg, start->fw_metadata->data, start->fw_metadata->len); + } else { + net_buf_simple_add_u8(msg, 0); + } + net_buf_simple_add_mem(msg, start->fwid->data, start->fwid->len); + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_distribution_upload_oob_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_upload_oob_start_t *start) +{ + int err = 0; + struct net_buf_simple *msg = NULL; + uint16_t msg_length = 2; + + if (!param || !start) { + BT_ERR("Invalid param"); + return -1; + } + + if (!start->url) { + BT_ERR("Null url info"); + return -1; + } + + if (!start->fwid) { + BT_ERR("Invalid firmware id"); + return -1; + } + + msg_length += (1 + start->url->len + start->fwid->len); + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_UPLOAD_START_OOB); + net_buf_simple_add_u8(msg, start->url->len); + net_buf_simple_add_mem(msg, start->url->data, start->url->len); + net_buf_simple_add_mem(msg, start->fwid->data, start->fwid->len); + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_distribution_upload_oob_cancel(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_UPLOAD_CANCEL, 0); + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_UPLOAD_CANCEL); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_firmware_get(bt_mesh_client_common_param_t *param, struct net_buf_simple *fwid) +{ + struct net_buf_simple *msg = NULL; + uint16_t msg_length = 2; + int err; + + + if (!fwid) { + BT_ERR("NULL Firmware id"); + return -EINVAL; + } + + msg_length += fwid->len; + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_FW_GET); + net_buf_simple_add_mem(msg, fwid->data, fwid->len); + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_firmware_get_by_index(bt_mesh_client_common_param_t *param, uint16_t fw_id_index) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_FW_GET_BY_INDEX, 2); + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_FW_GET_BY_INDEX); + + net_buf_simple_add_le16(&msg, fw_id_index); + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +int bt_mesh_dfd_cli_firmware_get_delete(bt_mesh_client_common_param_t *param, struct net_buf_simple *fwid) +{ + struct net_buf_simple *msg = NULL; + uint16_t msg_length = 2; + int err; + + + if (!fwid) { + BT_ERR("NULL Firmware id"); + return -EINVAL; + } + + msg_length += fwid->len; + + msg = bt_mesh_alloc_buf(msg_length + BLE_MESH_MIC_SHORT); + if (!msg) { + BT_ERR("Failed to alloc buffer to send message"); + return -EINVAL; + } + + bt_mesh_model_msg_init(msg, BLE_MESH_DFD_OP_FW_DELETE); + net_buf_simple_add_mem(msg, fwid->data, fwid->len); + + err = bt_mesh_client_send_msg(param, msg, true, timeout_handler); + bt_mesh_free_buf(msg); + return err; +} + +int bt_mesh_dfd_cli_firmware_delete_all(bt_mesh_client_common_param_t *param) +{ + BLE_MESH_MODEL_BUF_DEFINE(msg, BLE_MESH_DFD_OP_FW_DELETE_ALL, 0); + bt_mesh_model_msg_init(&msg, BLE_MESH_DFD_OP_FW_DELETE_ALL); + + return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); +} + +static int dfd_cli_init(struct bt_mesh_model *model) +{ + bt_mesh_dfd_client_t *client = NULL; + dfd_internal_data_t *internal = NULL; + + if (!model) { + BT_ERR("Invalid Device Firmware Distribution Client model"); + return -EINVAL; + } + + if (!bt_mesh_model_in_primary(model)) { + BT_ERR("Device Firmware Distribution Client only allowed in primary element"); + return -EINVAL; + } + + client = (bt_mesh_dfd_client_t *)model->user_data; + if (!client) { + BT_ERR("No Device Firmware Distribution Client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + BT_WARN("%s, Already", __func__); + return -EALREADY; + } + + internal = bt_mesh_calloc(sizeof(dfd_internal_data_t)); + if (!internal) { + BT_ERR("%s, Out of memory", __func__); + return -ENOMEM; + } + + sys_slist_init(&internal->queue); + + client->model = model; + client->op_pair_size = ARRAY_SIZE(dfd_cli_pair); + client->op_pair = dfd_cli_pair; + client->internal_data = internal; + BT_INFO("Dfd client initialized"); + bt_mesh_mutex_create(&dfd_client_lock); + + return 0; +} + +#if CONFIG_BLE_MESH_DEINIT +static int dfd_cli_deinit(struct bt_mesh_model *model) +{ + bt_mesh_dfd_client_t *client = NULL; + + if (!model) { + BT_ERR("Invalid Device Firmware Distribution Client model"); + return -EINVAL; + } + + client = (bt_mesh_dfd_client_t *)model->user_data; + if (!client) { + BT_ERR("No Device Firmware Distribution Client context provided"); + return -EINVAL; + } + + if (client->internal_data) { + /* Remove items from the list */ + bt_mesh_client_clear_list(client->internal_data); + + /* Free the allocated internal data */ + bt_mesh_free(client->internal_data); + client->internal_data = NULL; + } + + bt_mesh_mutex_free(&dfd_client_lock); + + return 0; +} +#endif + +const struct bt_mesh_model_cb _bt_mesh_dfd_cli_cb = { + .init = dfd_cli_init, +#if CONFIG_BLE_MESH_DEINIT + .deinit = dfd_cli_deinit, +#endif /* CONFIG_BLE_MESH_DEINIT */ +}; +#endif diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c index 7821b21b88..955419ef1f 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfd_srv.c @@ -6,7 +6,6 @@ */ #include #include "dfu_slot.h" -#include "dfd.h" #include "dfu.h" #include "dfd_srv_internal.h" #include "net.h" @@ -19,7 +18,7 @@ #if CONFIG_BLE_MESH_DFD_SRV #define DFD_UPLOAD_STATUS_MSG_MAXLEN (5 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN) -_Static_assert((DFD_UPLOAD_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_UPLOAD_STATUS) + +_Static_assert((DFD_UPLOAD_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFD_OP_UPLOAD_STATUS) + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, "The Firmware Distribution Upload Status message does not fit into the maximum " "outgoing SDU size."); @@ -27,21 +26,21 @@ _Static_assert((DFD_UPLOAD_STATUS_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_DFD #define DFD_UPLOAD_START_MSG_MAXLEN (16 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN + \ CONFIG_BLE_MESH_DFU_METADATA_MAXLEN) -_Static_assert((DFD_UPLOAD_START_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_UPLOAD_START) + +_Static_assert((DFD_UPLOAD_START_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFD_OP_UPLOAD_START) + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, "The Firmware Distribution Upload Start message does not fit into the maximum " "incoming SDU size."); #define DFD_RECEIVERS_LIST_MSG_MAXLEN (4 + CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX * 5) -_Static_assert((DFD_RECEIVERS_LIST_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_RECEIVERS_LIST) + +_Static_assert((DFD_RECEIVERS_LIST_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFD_OP_RECEIVERS_LIST) + BLE_MESH_MIC_SHORT) <= BLE_MESH_TX_SDU_MAX, "The Firmware Distribution Receivers List message does not fit into the maximum " "outgoing SDU size."); #define DFD_RECEIVERS_ADD_MSG_MAXLEN (CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX * 3) -_Static_assert((DFD_RECEIVERS_ADD_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BT_MESH_DFD_OP_RECEIVERS_ADD) + +_Static_assert((DFD_RECEIVERS_ADD_MSG_MAXLEN + BLE_MESH_MODEL_OP_LEN(BLE_MESH_DFD_OP_RECEIVERS_ADD) + BLE_MESH_MIC_SHORT) <= BLE_MESH_RX_SDU_MAX, "The Firmware Distribution Receivers Add message does not fit into the maximum " "incoming SDU size."); @@ -76,15 +75,15 @@ static struct bt_mesh_dfu_target *target_get(struct bt_mesh_dfd_srv *srv, static bool is_busy(const struct bt_mesh_dfd_srv *srv) { - return srv->phase == BT_MESH_DFD_PHASE_TRANSFER_ACTIVE || - srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUCCESS || - srv->phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE; + return srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE || + srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUCCESS || + srv->phase == BLE_MESH_DFD_PHASE_APPLYING_UPDATE; } static bool upload_is_busy(const struct bt_mesh_dfd_srv *srv) { return bt_mesh_blob_srv_is_busy(&srv->upload.blob) || - srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + srv->upload.phase == BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; } static int slot_del(struct bt_mesh_dfd_srv *srv, const struct bt_mesh_dfu_slot *slot) @@ -100,8 +99,8 @@ static void receivers_status_rsp(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, enum bt_mesh_dfd_status status) { - BLE_MESH_MODEL_BUF_DEFINE(buf, BT_MESH_DFD_OP_RECEIVERS_STATUS, 3); - bt_mesh_model_msg_init(&buf, BT_MESH_DFD_OP_RECEIVERS_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(buf, BLE_MESH_DFD_OP_RECEIVERS_STATUS, 3); + bt_mesh_model_msg_init(&buf, BLE_MESH_DFD_OP_RECEIVERS_STATUS); net_buf_simple_add_u8(&buf, status); net_buf_simple_add_le16(&buf, srv->target_cnt); @@ -112,7 +111,7 @@ static void receivers_status_rsp(struct bt_mesh_dfd_srv *srv, static int handle_receivers_add(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - enum bt_mesh_dfd_status status = BT_MESH_DFD_SUCCESS; + enum bt_mesh_dfd_status status = BLE_MESH_DFD_SUCCESS; struct bt_mesh_dfd_srv *srv = mod->user_data; if (buf->len % 3) { @@ -121,11 +120,11 @@ static int handle_receivers_add(const struct bt_mesh_model *mod, struct bt_mesh_ if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { receivers_status_rsp(srv, ctx, - BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION); + BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION); return 0; } - while (buf->len >= 3 && status == BT_MESH_DFD_SUCCESS) { + while (buf->len >= 3 && status == BLE_MESH_DFD_SUCCESS) { uint8_t img_idx; uint16_t addr; @@ -166,9 +165,9 @@ static int handle_receivers_get(const struct bt_mesh_model *mod, struct bt_mesh_ /* Create a buffer that can fit the full target list, maxing out at TX_SDU_MAX: */ NET_BUF_SIMPLE_DEFINE( - rsp, BLE_MESH_MODEL_BUF_LEN(BT_MESH_DFD_OP_RECEIVERS_LIST, + rsp, BLE_MESH_MODEL_BUF_LEN(BLE_MESH_DFD_OP_RECEIVERS_LIST, DFD_RECEIVERS_LIST_MSG_MAXLEN)); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_RECEIVERS_LIST); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_RECEIVERS_LIST); net_buf_simple_add_le16(&rsp, srv->target_cnt); net_buf_simple_add_le16(&rsp, first); @@ -208,8 +207,8 @@ static int handle_capabilities_get(const struct bt_mesh_model *mod, struct bt_me { size_t size = 0; - BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_CAPABILITIES_STATUS, 17); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_CAPABILITIES_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFD_OP_CAPABILITIES_GET, 17); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_CAPABILITIES_GET); net_buf_simple_add_le16(&rsp, CONFIG_BLE_MESH_DFD_SRV_TARGETS_MAX); net_buf_simple_add_le16(&rsp, CONFIG_BLE_MESH_DFU_SLOT_CNT); @@ -243,13 +242,13 @@ static int handle_capabilities_get(const struct bt_mesh_model *mod, struct bt_me static void status_rsp(struct bt_mesh_dfd_srv *srv, struct bt_mesh_msg_ctx *ctx, enum bt_mesh_dfd_status status) { - BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_STATUS, 12); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_STATUS); + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFD_OP_STATUS, 12); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_STATUS); net_buf_simple_add_u8(&rsp, status); net_buf_simple_add_u8(&rsp, srv->phase); - if (srv->phase == BT_MESH_DFD_PHASE_IDLE || !srv->dfu.xfer.slot) { + if (srv->phase == BLE_MESH_DFD_PHASE_IDLE || !srv->dfu.xfer.slot) { bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); return; } @@ -270,7 +269,7 @@ static int handle_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx *c { struct bt_mesh_dfd_srv *srv = mod->user_data; - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); return 0; } @@ -292,7 +291,7 @@ static int handle_start(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx if (buf->len == 16) { /* TODO: Virtual addresses not supported. */ - status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); return 0; } @@ -343,14 +342,14 @@ static void upload_status_rsp_with_progress(struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_status status, uint8_t progress) { - BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_UPLOAD_STATUS, + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFD_OP_UPLOAD_STATUS, DFD_UPLOAD_STATUS_MSG_MAXLEN); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_UPLOAD_STATUS); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_UPLOAD_STATUS); net_buf_simple_add_u8(&rsp, status); net_buf_simple_add_u8(&rsp, srv->upload.phase); - if (srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_IDLE || + if (srv->upload.phase == BLE_MESH_DFD_UPLOAD_PHASE_IDLE || !srv->upload.slot) { bt_mesh_model_send(srv->mod, ctx, &rsp, NULL, NULL); return; @@ -395,7 +394,7 @@ static int handle_upload_get(const struct bt_mesh_model *mod, struct bt_mesh_msg { struct bt_mesh_dfd_srv *srv = mod->user_data; - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); return 0; } @@ -410,22 +409,22 @@ static inline int set_upload_fwid(struct bt_mesh_dfd_srv *srv, struct bt_mesh_ms case -EALREADY: /* Other server is in progress with this fwid */ bt_mesh_dfu_slot_release(srv->upload.slot); srv->upload.slot = NULL; - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); break; case -EEXIST: /* Img with this fwid already is in list */ - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; bt_mesh_dfu_slot_release(srv->upload.slot); err = bt_mesh_dfu_slot_get(fwid, fwid_len, &srv->upload.slot); if (!err) { - upload_status_rsp_with_progress(srv, ctx, BT_MESH_DFD_SUCCESS, 100); + upload_status_rsp_with_progress(srv, ctx, BLE_MESH_DFD_SUCCESS, 100); } else { srv->upload.slot = NULL; - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); } break; case 0: - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; break; case -EINVAL: /* Slot in wrong state. */ default: @@ -464,14 +463,14 @@ static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_m if (size > CONFIG_BLE_MESH_DFD_SRV_SLOT_MAX_SIZE) { upload_status_rsp(srv, ctx, - BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); return 0; } if (upload_is_busy(srv)) { if (!srv->upload.slot) { BT_WARN("Busy with no upload slot"); - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); return 0; } @@ -487,12 +486,12 @@ static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_m #endif ) { BT_DBG("Duplicate upload start"); - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); return 0; } BT_WARN("Upload already in progress"); - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_BUSY_WITH_UPLOAD); return 0; } @@ -511,7 +510,7 @@ static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_m if (!srv->upload.slot) { BT_WARN("No space for slot"); upload_status_rsp(srv, ctx, - BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); return 0; } @@ -523,7 +522,7 @@ static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_m err = bt_mesh_dfu_slot_info_set(srv->upload.slot, size, meta, meta_len); switch (err) { case -EFBIG: - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); break; case 0: break; @@ -536,7 +535,7 @@ static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_m if (err || !srv->io) { BT_ERR("App rejected upload. err: %d io: %p", err, srv->io); bt_mesh_dfu_slot_release(srv->upload.slot); - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); return 0; } @@ -545,14 +544,14 @@ static int handle_upload_start(const struct bt_mesh_model *mod, struct bt_mesh_m if (err) { BT_ERR("BLOB Server rejected upload (err: %d)", err); bt_mesh_dfu_slot_release(srv->upload.slot); - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); return 0; } BT_DBG("%s", bt_hex(fwid, fwid_len)); - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE; + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); return 0; } @@ -588,11 +587,11 @@ static int handle_upload_start_oob(const struct bt_mesh_model *mod, struct bt_me !memcmp(uri, srv->upload.oob.uri, uri_len) && !memcmp(fwid, srv->upload.oob.current_fwid, fwid_len)) { /* Same image, return SUCCESS for idempotency */ - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); return 0; } #endif - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_BUSY_WITH_UPLOAD); return 0; #ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD } else if (srv->upload.is_oob && srv->upload.is_pending_oob_check) { @@ -604,14 +603,14 @@ static int handle_upload_start_oob(const struct bt_mesh_model *mod, struct bt_me #ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD if (uri_len > CONFIG_BLE_MESH_DFU_URI_MAXLEN || fwid_len > CONFIG_BLE_MESH_DFU_FWID_MAXLEN) { - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); return 0; } struct bt_mesh_dfu_slot *slot = bt_mesh_dfu_slot_reserve(); if (slot == NULL) { - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES); return 0; } @@ -635,14 +634,14 @@ static int handle_upload_start_oob(const struct bt_mesh_model *mod, struct bt_me srv->upload.oob.current_fwid, srv->upload.oob.current_fwid_len); - if (status != BT_MESH_DFD_SUCCESS) { + if (status != BLE_MESH_DFD_SUCCESS) { upload_status_rsp(srv, ctx, status); bt_mesh_dfu_slot_release(srv->upload.slot); } else { srv->upload.is_pending_oob_check = true; } #else - upload_status_rsp(srv, ctx, BT_MESH_DFD_ERR_URI_NOT_SUPPORTED); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_URI_NOT_SUPPORTED); #endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ return 0; @@ -653,7 +652,7 @@ static int handle_upload_cancel(const struct bt_mesh_model *mod, struct bt_mesh_ { struct bt_mesh_dfd_srv *srv = mod->user_data; - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_IDLE; #ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD if (srv->upload.is_oob) { srv->cb->cancel_oob_upload(srv, srv->upload.slot); @@ -662,7 +661,7 @@ static int handle_upload_cancel(const struct bt_mesh_model *mod, struct bt_mesh_ { (void)bt_mesh_blob_srv_cancel(&srv->upload.blob); } - upload_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + upload_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); return 0; } @@ -672,9 +671,9 @@ static void fw_status_rsp(struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_status status, uint16_t idx, const uint8_t *fwid, size_t fwid_len) { - BLE_MESH_MODEL_BUF_DEFINE(rsp, BT_MESH_DFD_OP_FW_STATUS, + BLE_MESH_MODEL_BUF_DEFINE(rsp, BLE_MESH_DFD_OP_FW_STATUS, 7 + CONFIG_BLE_MESH_DFU_FWID_MAXLEN); - bt_mesh_model_msg_init(&rsp, BT_MESH_DFD_OP_FW_STATUS); + bt_mesh_model_msg_init(&rsp, BLE_MESH_DFD_OP_FW_STATUS); net_buf_simple_add_u8(&rsp, status); net_buf_simple_add_le16(&rsp, bt_mesh_dfu_slot_count()); @@ -701,10 +700,10 @@ static int handle_fw_get(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx idx = bt_mesh_dfu_slot_get(fwid, fwid_len, &slot); if (idx >= 0) { - fw_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS, idx, fwid, + fw_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS, idx, fwid, fwid_len); } else { - fw_status_rsp(srv, ctx, BT_MESH_DFD_ERR_FW_NOT_FOUND, 0xffff, + fw_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_FW_NOT_FOUND, 0xffff, fwid, fwid_len); } @@ -722,10 +721,10 @@ static int handle_fw_get_by_index(const struct bt_mesh_model *mod, struct bt_mes slot = bt_mesh_dfu_slot_at(idx); if (slot) { - fw_status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS, idx, slot->fwid, + fw_status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS, idx, slot->fwid, slot->fwid_len); } else { - fw_status_rsp(srv, ctx, BT_MESH_DFD_ERR_FW_NOT_FOUND, idx, + fw_status_rsp(srv, ctx, BLE_MESH_DFD_ERR_FW_NOT_FOUND, idx, NULL, 0); } @@ -772,23 +771,23 @@ static int handle_fw_delete_all(const struct bt_mesh_model *mod, struct bt_mesh_ } const struct bt_mesh_model_op _bt_mesh_dfd_srv_op[] = { - { BT_MESH_DFD_OP_RECEIVERS_ADD, 3, (void *)handle_receivers_add }, - { BT_MESH_DFD_OP_RECEIVERS_DELETE_ALL, 0, (void *)handle_receivers_delete_all }, - { BT_MESH_DFD_OP_RECEIVERS_GET, 4, (void *)handle_receivers_get }, - { BT_MESH_DFD_OP_CAPABILITIES_GET, 0, (void *)handle_capabilities_get }, - { BT_MESH_DFD_OP_GET, 0, (void *)handle_get }, - { BT_MESH_DFD_OP_START, 10, (void *)handle_start }, - { BT_MESH_DFD_OP_SUSPEND, 0, (void *)handle_suspend }, - { BT_MESH_DFD_OP_CANCEL, 0, (void *)handle_cancel }, - { BT_MESH_DFD_OP_APPLY, 0, (void *)handle_apply }, - { BT_MESH_DFD_OP_UPLOAD_GET, 0, (void *)handle_upload_get }, - { BT_MESH_DFD_OP_UPLOAD_START, 16, (void *)handle_upload_start }, - { BT_MESH_DFD_OP_UPLOAD_START_OOB, 2, (void *)handle_upload_start_oob }, - { BT_MESH_DFD_OP_UPLOAD_CANCEL, 0, (void *)handle_upload_cancel }, - { BT_MESH_DFD_OP_FW_GET, 0, (void *)handle_fw_get }, - { BT_MESH_DFD_OP_FW_GET_BY_INDEX, 2, (void *)handle_fw_get_by_index }, - { BT_MESH_DFD_OP_FW_DELETE, 0, (void *)handle_fw_delete }, - { BT_MESH_DFD_OP_FW_DELETE_ALL, 0, (void *)handle_fw_delete_all }, + { BLE_MESH_DFD_OP_RECEIVERS_ADD, 3, (void *)handle_receivers_add }, + { BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL, 0, (void *)handle_receivers_delete_all }, + { BLE_MESH_DFD_OP_RECEIVERS_GET, 4, (void *)handle_receivers_get }, + { BLE_MESH_DFD_OP_CAPABILITIES_GET, 0, (void *)handle_capabilities_get }, + { BLE_MESH_DFD_OP_GET, 0, (void *)handle_get }, + { BLE_MESH_DFD_OP_START, 10, (void *)handle_start }, + { BLE_MESH_DFD_OP_SUSPEND, 0, (void *)handle_suspend }, + { BLE_MESH_DFD_OP_CANCEL, 0, (void *)handle_cancel }, + { BLE_MESH_DFD_OP_APPLY, 0, (void *)handle_apply }, + { BLE_MESH_DFD_OP_UPLOAD_GET, 0, (void *)handle_upload_get }, + { BLE_MESH_DFD_OP_UPLOAD_START, 16, (void *)handle_upload_start }, + { BLE_MESH_DFD_OP_UPLOAD_START_OOB, 2, (void *)handle_upload_start_oob }, + { BLE_MESH_DFD_OP_UPLOAD_CANCEL, 0, (void *)handle_upload_cancel }, + { BLE_MESH_DFD_OP_FW_GET, 0, (void *)handle_fw_get }, + { BLE_MESH_DFD_OP_FW_GET_BY_INDEX, 2, (void *)handle_fw_get_by_index }, + { BLE_MESH_DFD_OP_FW_DELETE, 0, (void *)handle_fw_delete }, + { BLE_MESH_DFD_OP_FW_DELETE_ALL, 0, (void *)handle_fw_delete_all }, BLE_MESH_MODEL_OP_END }; @@ -798,7 +797,7 @@ static void dfu_suspended(struct bt_mesh_dfu_cli *cli) struct bt_mesh_dfd_srv *srv = CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); - dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED); } static void dfu_ended(struct bt_mesh_dfu_cli *cli, @@ -810,31 +809,31 @@ static void dfu_ended(struct bt_mesh_dfu_cli *cli, BT_DBG("reason: %u, phase: %u, apply: %u", reason, srv->phase, srv->apply); - if (srv->phase == BT_MESH_DFD_PHASE_IDLE) { + if (srv->phase == BLE_MESH_DFD_PHASE_IDLE) { return; } - if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + if (srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); return; } if (reason != BLE_MESH_DFU_SUCCESS) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_FAILED); return; } if (!srv->apply) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_SUCCESS); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_TRANSFER_SUCCESS); return; } - dfd_phase_set(srv, BT_MESH_DFD_PHASE_APPLYING_UPDATE); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_APPLYING_UPDATE); err = bt_mesh_dfu_cli_apply(cli); if (err) { BT_ERR("Apply failed: %d", err); - dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_FAILED); } } @@ -844,19 +843,19 @@ static void dfu_applied(struct bt_mesh_dfu_cli *cli) CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); int err; - if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + if (srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_FAILED); return; } - if (srv->phase != BT_MESH_DFD_PHASE_APPLYING_UPDATE) { + if (srv->phase != BLE_MESH_DFD_PHASE_APPLYING_UPDATE) { return; } err = bt_mesh_dfu_cli_confirm(cli); if (err) { BT_ERR("Confirm failed: %d", err); - dfd_phase_set(srv, BT_MESH_DFD_PHASE_FAILED); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_FAILED); } } @@ -865,12 +864,12 @@ static void dfu_confirmed(struct bt_mesh_dfu_cli *cli) struct bt_mesh_dfd_srv *srv = CONTAINER_OF(cli, struct bt_mesh_dfd_srv, dfu); - if (srv->phase != BT_MESH_DFD_PHASE_APPLYING_UPDATE && - srv->phase != BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + if (srv->phase != BLE_MESH_DFD_PHASE_APPLYING_UPDATE && + srv->phase != BLE_MESH_DFD_PHASE_CANCELING_UPDATE) { return; } - dfd_phase_set(srv, BT_MESH_DFD_PHASE_COMPLETED); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_COMPLETED); } const struct bt_mesh_dfu_cli_cb _bt_mesh_dfd_srv_dfu_cb = { @@ -892,19 +891,19 @@ static void upload_end(struct bt_mesh_blob_srv *b, uint64_t id, bool success) struct bt_mesh_dfd_srv *srv = CONTAINER_OF(b, struct bt_mesh_dfd_srv, upload.blob); - if (srv->upload.phase != BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE) { + if (srv->upload.phase != BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE) { return; } BT_DBG("%u", success); if (success && (bt_mesh_dfu_slot_commit(srv->upload.slot) == 0)) { - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; return; } /* Will delete slot when we start a new upload */ - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; } static void upload_timeout(struct bt_mesh_blob_srv *b) @@ -933,9 +932,9 @@ static void dfd_srv_reset(struct bt_mesh_model *mod) { struct bt_mesh_dfd_srv *srv = mod->user_data; - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_IDLE; + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_IDLE; sys_slist_init(&srv->inputs.targets); srv->target_cnt = 0; @@ -963,19 +962,19 @@ enum bt_mesh_dfd_status bt_mesh_dfd_srv_receiver_add(struct bt_mesh_dfd_srv *srv struct bt_mesh_blob_target_pull *p; if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } t = target_get(srv, addr); if (t) { t->img_idx = img_idx; - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } /* New target node, add it to the list */ if (srv->target_cnt == ARRAY_SIZE(srv->targets)) { - return BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES; + return BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES; } t = &srv->targets[srv->target_cnt]; @@ -991,19 +990,19 @@ enum bt_mesh_dfd_status bt_mesh_dfd_srv_receiver_add(struct bt_mesh_dfd_srv *srv BT_DBG("Added receiver 0x%04x img: %u", t->blob.addr, t->img_idx); - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_receivers_delete_all(struct bt_mesh_dfd_srv *srv) { if (bt_mesh_dfu_cli_is_busy(&srv->dfu)) { - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; } sys_slist_init(&srv->inputs.targets); srv->target_cnt = 0; - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, @@ -1013,17 +1012,17 @@ enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, struct bt_mesh_dfu_cli_xfer xfer = { 0 }; if (!srv->target_cnt) { - return BT_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY; + return BLE_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY; } if (!bt_mesh_app_key_get(params->app_idx)) { - return BT_MESH_DFD_ERR_INVALID_APPKEY_INDEX; + return BLE_MESH_DFD_ERR_INVALID_APPKEY_INDEX; } xfer.mode = params->xfer_mode; xfer.slot = bt_mesh_dfu_slot_at(params->slot_idx); if (!xfer.slot) { - return BT_MESH_DFD_ERR_FW_NOT_FOUND; + return BLE_MESH_DFD_ERR_FW_NOT_FOUND; } if (srv->inputs.app_idx == params->app_idx && @@ -1032,29 +1031,29 @@ enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, srv->dfu.xfer.blob.mode == xfer.mode && srv->apply == params->apply && srv->slot_idx == params->slot_idx) { if (is_busy(srv) || - srv->phase == BT_MESH_DFD_PHASE_COMPLETED) { + srv->phase == BLE_MESH_DFD_PHASE_COMPLETED) { BT_WARN("Already completed or in progress"); - return BT_MESH_DFD_SUCCESS; - } else if (srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + return BLE_MESH_DFD_SUCCESS; + } else if (srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { bt_mesh_dfu_cli_resume(&srv->dfu); - dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_ACTIVE); - return BT_MESH_DFD_SUCCESS; + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE); + return BLE_MESH_DFD_SUCCESS; } } else if (is_busy(srv) || - srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { BT_WARN("Busy with distribution"); - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; } - if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE) { + if (srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE) { BT_WARN("Canceling distribution"); - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; } srv->io = NULL; err = srv->cb->send(srv, xfer.slot, &srv->io); if (err || !srv->io) { - return BT_MESH_DFD_ERR_INTERNAL; + return BLE_MESH_DFD_ERR_INTERNAL; } sys_slist_init(&srv->inputs.targets); @@ -1083,35 +1082,35 @@ enum bt_mesh_dfd_status bt_mesh_dfd_srv_start(struct bt_mesh_dfd_srv *srv, /* DFD Server will always retrieve targets' capabilities before distributing a firmware.*/ xfer.blob_params = NULL; - dfd_phase_set(srv, BT_MESH_DFD_PHASE_TRANSFER_ACTIVE); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE); err = bt_mesh_dfu_cli_send(&srv->dfu, &srv->inputs, srv->io, &xfer); if (err) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); - return BT_MESH_DFD_ERR_INTERNAL; + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); + return BLE_MESH_DFD_ERR_INTERNAL; } - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_suspend(struct bt_mesh_dfd_srv *srv) { int err; - if (srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { - return BT_MESH_DFD_SUCCESS; + if (srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED) { + return BLE_MESH_DFD_SUCCESS; } - if (srv->phase != BT_MESH_DFD_PHASE_TRANSFER_ACTIVE) { - return BT_MESH_DFD_ERR_WRONG_PHASE; + if (srv->phase != BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE) { + return BLE_MESH_DFD_ERR_WRONG_PHASE; } err = bt_mesh_dfu_cli_suspend(&srv->dfu); if (err) { - return BT_MESH_DFD_ERR_SUSPEND_FAILED; + return BLE_MESH_DFD_ERR_SUSPEND_FAILED; } - srv->phase = BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED; - return BT_MESH_DFD_SUCCESS; + srv->phase = BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED; + return BLE_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_cancel(struct bt_mesh_dfd_srv *srv, @@ -1120,36 +1119,36 @@ enum bt_mesh_dfd_status bt_mesh_dfd_srv_cancel(struct bt_mesh_dfd_srv *srv, enum bt_mesh_dfd_phase prev_phase; int err; - if (srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE || - srv->phase == BT_MESH_DFD_PHASE_IDLE) { + if (srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE || + srv->phase == BLE_MESH_DFD_PHASE_IDLE) { if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); } - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } - if (srv->phase == BT_MESH_DFD_PHASE_COMPLETED || - srv->phase == BT_MESH_DFD_PHASE_FAILED) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + if (srv->phase == BLE_MESH_DFD_PHASE_COMPLETED || + srv->phase == BLE_MESH_DFD_PHASE_FAILED) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); } - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } /* Phase TRANSFER_ACTIVE, TRANSFER_SUSPENDED, TRANSFER_SUCCESS, APPLYING_UPDATE: */ prev_phase = srv->phase; - dfd_phase_set(srv, BT_MESH_DFD_PHASE_CANCELING_UPDATE); + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_CANCELING_UPDATE); err = bt_mesh_dfu_cli_cancel(&srv->dfu, NULL); if (err) { if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_ERR_INTERNAL); + status_rsp(srv, ctx, BLE_MESH_DFD_ERR_INTERNAL); } - return BT_MESH_DFD_ERR_INTERNAL; + return BLE_MESH_DFD_ERR_INTERNAL; } - if (prev_phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE && ctx) { + if (prev_phase == BLE_MESH_DFD_PHASE_APPLYING_UPDATE && ctx) { /* Disable randomization for the Firmware Distribution State message to avoid * reordering when Firmware Distribution Server sends 2 messages in a row when * cancelling the update (see section 6.2.3.10 of MshDFUv1.0). @@ -1161,43 +1160,43 @@ enum bt_mesh_dfd_status bt_mesh_dfd_srv_cancel(struct bt_mesh_dfd_srv *srv, } if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); } - if (prev_phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE) { - dfd_phase_set(srv, BT_MESH_DFD_PHASE_IDLE); + if (prev_phase == BLE_MESH_DFD_PHASE_APPLYING_UPDATE) { + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_IDLE); if (ctx != NULL) { - status_rsp(srv, ctx, BT_MESH_DFD_SUCCESS); + status_rsp(srv, ctx, BLE_MESH_DFD_SUCCESS); } } - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_apply(struct bt_mesh_dfd_srv *srv) { int err; - if (srv->phase == BT_MESH_DFD_PHASE_IDLE || - srv->phase == BT_MESH_DFD_PHASE_CANCELING_UPDATE || - srv->phase == BT_MESH_DFD_PHASE_TRANSFER_ACTIVE || - srv->phase == BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED || - srv->phase == BT_MESH_DFD_PHASE_FAILED) { - return BT_MESH_DFD_ERR_WRONG_PHASE; + if (srv->phase == BLE_MESH_DFD_PHASE_IDLE || + srv->phase == BLE_MESH_DFD_PHASE_CANCELING_UPDATE || + srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE || + srv->phase == BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED || + srv->phase == BLE_MESH_DFD_PHASE_FAILED) { + return BLE_MESH_DFD_ERR_WRONG_PHASE; } - if (srv->phase == BT_MESH_DFD_PHASE_APPLYING_UPDATE || - srv->phase == BT_MESH_DFD_PHASE_COMPLETED) { - return BT_MESH_DFD_SUCCESS; + if (srv->phase == BLE_MESH_DFD_PHASE_APPLYING_UPDATE || + srv->phase == BLE_MESH_DFD_PHASE_COMPLETED) { + return BLE_MESH_DFD_SUCCESS; } err = bt_mesh_dfu_cli_apply(&srv->dfu); if (err) { - return BT_MESH_DFD_ERR_INTERNAL; + return BLE_MESH_DFD_ERR_INTERNAL; } - dfd_phase_set(srv, BT_MESH_DFD_PHASE_APPLYING_UPDATE); - return BT_MESH_DFD_SUCCESS; + dfd_phase_set(srv, BLE_MESH_DFD_PHASE_APPLYING_UPDATE); + return BLE_MESH_DFD_SUCCESS; } enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete(struct bt_mesh_dfd_srv *srv, size_t *fwid_len, @@ -1206,38 +1205,38 @@ enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete(struct bt_mesh_dfd_srv *srv, s struct bt_mesh_dfu_slot *slot; int idx, err; - if (srv->phase != BT_MESH_DFD_PHASE_IDLE) { + if (srv->phase != BLE_MESH_DFD_PHASE_IDLE) { *fwid = NULL; *fwid_len = 0; - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; } idx = bt_mesh_dfu_slot_get(*fwid, *fwid_len, &slot); if (idx < 0) { - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } err = slot_del(srv, slot); if (err) { *fwid = NULL; *fwid_len = 0; - return BT_MESH_DFD_ERR_INTERNAL; + return BLE_MESH_DFD_ERR_INTERNAL; } else { - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } } enum bt_mesh_dfd_status bt_mesh_dfd_srv_fw_delete_all(struct bt_mesh_dfd_srv *srv) { - if (srv->phase != BT_MESH_DFD_PHASE_IDLE) { - return BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; + if (srv->phase != BLE_MESH_DFD_PHASE_IDLE) { + return BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION; } bt_mesh_dfu_slot_foreach(slot_del_cb, srv); bt_mesh_dfu_slot_del_all(); - return BT_MESH_DFD_SUCCESS; + return BLE_MESH_DFD_SUCCESS; } #ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD @@ -1248,7 +1247,7 @@ int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, int err; if (slot != srv->upload.slot || !srv->upload.is_oob || - srv->upload.phase == BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || + srv->upload.phase == BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || !srv->upload.is_pending_oob_check) { /* This should not happen, unless the application calls the function with a * "wrong" pointer or at a wrong time. @@ -1258,7 +1257,7 @@ int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, srv->upload.is_pending_oob_check = false; - if (status != BT_MESH_DFD_SUCCESS) { + if (status != BLE_MESH_DFD_SUCCESS) { bt_mesh_dfu_slot_release(srv->upload.slot); upload_status_rsp(srv, &srv->upload.oob.ctx, status); return -ECANCELED; @@ -1270,7 +1269,7 @@ int bt_mesh_dfd_srv_oob_check_complete(struct bt_mesh_dfd_srv *srv, return err; } - upload_status_rsp(srv, &srv->upload.oob.ctx, BT_MESH_DFD_SUCCESS); + upload_status_rsp(srv, &srv->upload.oob.ctx, BLE_MESH_DFD_SUCCESS); return 0; } @@ -1280,7 +1279,7 @@ int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv, { int err = 0; - if (srv->upload.phase != BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || + if (srv->upload.phase != BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE || srv->upload.slot != slot || !srv->upload.is_oob) { return -EINVAL; } @@ -1299,11 +1298,11 @@ int bt_mesh_dfd_srv_oob_store_complete(struct bt_mesh_dfd_srv *srv, goto error; } - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS; return 0; error: - srv->upload.phase = BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; + srv->upload.phase = BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR; bt_mesh_dfu_slot_release(srv->upload.slot); return err; } diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c index 8ce345831d..e5ff20c328 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c @@ -105,8 +105,10 @@ static void req_timeout_handler(struct k_work *work) } bt_mesh_dfu_cli_rm_req_from_list(req); + if (req->params) { + bt_mesh_free(req->params); + } req_free(req); - bt_mesh_r_mutex_unlock(&dfu_req_list.op_lock); } @@ -897,7 +899,7 @@ static int handle_status(const struct bt_mesh_model *mod, struct bt_mesh_msg_ctx } bt_mesh_dfu_client_cb_evt_to_btc(req->opcode, BTC_BLE_MESH_EVT_DFU_CLIENT_RECV_GET_RSP, req->dfu_cli->mod, &req->ctx, req->params, - sizeof(struct bt_mesh_dfu_metadata_status)); + sizeof(struct bt_mesh_dfu_target_status)); bt_mesh_free(req->params); bt_mesh_dfu_cli_rm_req_from_list(req); k_delayed_work_cancel(&req->timer); diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h index b91ee418e2..a9634ef220 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd.h @@ -12,6 +12,30 @@ extern "C" { #endif +#define BLE_MESH_DFD_OP_RECEIVERS_ADD BLE_MESH_MODEL_OP_2(0x83, 0x11) +#define BLE_MESH_DFD_OP_RECEIVERS_DELETE_ALL BLE_MESH_MODEL_OP_2(0x83, 0x12) +#define BLE_MESH_DFD_OP_RECEIVERS_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x13) +#define BLE_MESH_DFD_OP_RECEIVERS_GET BLE_MESH_MODEL_OP_2(0x83, 0x14) +#define BLE_MESH_DFD_OP_RECEIVERS_LIST BLE_MESH_MODEL_OP_2(0x83, 0x15) +#define BLE_MESH_DFD_OP_CAPABILITIES_GET BLE_MESH_MODEL_OP_2(0x83, 0x16) +#define BLE_MESH_DFD_OP_CAPABILITIES_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x17) +#define BLE_MESH_DFD_OP_GET BLE_MESH_MODEL_OP_2(0x83, 0x18) +#define BLE_MESH_DFD_OP_START BLE_MESH_MODEL_OP_2(0x83, 0x19) +#define BLE_MESH_DFD_OP_SUSPEND BLE_MESH_MODEL_OP_2(0x83, 0x1a) +#define BLE_MESH_DFD_OP_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x1b) +#define BLE_MESH_DFD_OP_APPLY BLE_MESH_MODEL_OP_2(0x83, 0x1c) +#define BLE_MESH_DFD_OP_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x1d) +#define BLE_MESH_DFD_OP_UPLOAD_GET BLE_MESH_MODEL_OP_2(0x83, 0x1e) +#define BLE_MESH_DFD_OP_UPLOAD_START BLE_MESH_MODEL_OP_2(0x83, 0x1f) +#define BLE_MESH_DFD_OP_UPLOAD_START_OOB BLE_MESH_MODEL_OP_2(0x83, 0x20) +#define BLE_MESH_DFD_OP_UPLOAD_CANCEL BLE_MESH_MODEL_OP_2(0x83, 0x21) +#define BLE_MESH_DFD_OP_UPLOAD_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x22) +#define BLE_MESH_DFD_OP_FW_GET BLE_MESH_MODEL_OP_2(0x83, 0x23) +#define BLE_MESH_DFD_OP_FW_GET_BY_INDEX BLE_MESH_MODEL_OP_2(0x83, 0x24) +#define BLE_MESH_DFD_OP_FW_DELETE BLE_MESH_MODEL_OP_2(0x83, 0x25) +#define BLE_MESH_DFD_OP_FW_DELETE_ALL BLE_MESH_MODEL_OP_2(0x83, 0x26) +#define BLE_MESH_DFD_OP_FW_STATUS BLE_MESH_MODEL_OP_2(0x83, 0x27) + /** * @defgroup bt_mesh_dfd Firmware Distribution models * @ingroup bt_mesh @@ -21,96 +45,96 @@ extern "C" { /** Firmware distribution status. */ enum bt_mesh_dfd_status { /** The message was processed successfully. */ - BT_MESH_DFD_SUCCESS, + BLE_MESH_DFD_SUCCESS, /** Insufficient resources on the node. */ - BT_MESH_DFD_ERR_INSUFFICIENT_RESOURCES, + BLE_MESH_DFD_ERR_INSUFFICIENT_RESOURCES, /** The operation cannot be performed while the Server is in the current * phase. */ - BT_MESH_DFD_ERR_WRONG_PHASE, + BLE_MESH_DFD_ERR_WRONG_PHASE, /** An internal error occurred on the node. */ - BT_MESH_DFD_ERR_INTERNAL, + BLE_MESH_DFD_ERR_INTERNAL, /** The requested firmware image is not stored on the Distributor. */ - BT_MESH_DFD_ERR_FW_NOT_FOUND, + BLE_MESH_DFD_ERR_FW_NOT_FOUND, /** The AppKey identified by the AppKey Index is not known to the node. */ - BT_MESH_DFD_ERR_INVALID_APPKEY_INDEX, + BLE_MESH_DFD_ERR_INVALID_APPKEY_INDEX, /** There are no Target nodes in the Distribution Receivers List * state. */ - BT_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY, + BLE_MESH_DFD_ERR_RECEIVERS_LIST_EMPTY, /** Another firmware image distribution is in progress. */ - BT_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION, + BLE_MESH_DFD_ERR_BUSY_WITH_DISTRIBUTION, /** Another upload is in progress. */ - BT_MESH_DFD_ERR_BUSY_WITH_UPLOAD, + BLE_MESH_DFD_ERR_BUSY_WITH_UPLOAD, /** The URI scheme name indicated by the Update URI is not supported. */ - BT_MESH_DFD_ERR_URI_NOT_SUPPORTED, + BLE_MESH_DFD_ERR_URI_NOT_SUPPORTED, /** The format of the Update URI is invalid. */ - BT_MESH_DFD_ERR_URI_MALFORMED, + BLE_MESH_DFD_ERR_URI_MALFORMED, /** The URI is currently unreachable. */ - BT_MESH_DFD_ERR_URI_UNREACHABLE, + BLE_MESH_DFD_ERR_URI_UNREACHABLE, /** The Check Firmware OOB procedure did not find any new firmware. */ - BT_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE, + BLE_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE, /** The suspension of the Distribute Firmware procedure failed. */ - BT_MESH_DFD_ERR_SUSPEND_FAILED, + BLE_MESH_DFD_ERR_SUSPEND_FAILED, }; /** Firmware distribution phases. */ enum bt_mesh_dfd_phase { /** No firmware distribution is in progress. */ - BT_MESH_DFD_PHASE_IDLE, + BLE_MESH_DFD_PHASE_IDLE, /** Firmware distribution is in progress. */ - BT_MESH_DFD_PHASE_TRANSFER_ACTIVE, + BLE_MESH_DFD_PHASE_TRANSFER_ACTIVE, /** The Transfer BLOB procedure has completed successfully. */ - BT_MESH_DFD_PHASE_TRANSFER_SUCCESS, + BLE_MESH_DFD_PHASE_TRANSFER_SUCCESS, /** The Apply Firmware on Target Nodes procedure is being executed. */ - BT_MESH_DFD_PHASE_APPLYING_UPDATE, + BLE_MESH_DFD_PHASE_APPLYING_UPDATE, /** The Distribute Firmware procedure has completed successfully. */ - BT_MESH_DFD_PHASE_COMPLETED, + BLE_MESH_DFD_PHASE_COMPLETED, /** The Distribute Firmware procedure has failed. */ - BT_MESH_DFD_PHASE_FAILED, + BLE_MESH_DFD_PHASE_FAILED, /** The Cancel Firmware Update procedure is being executed. */ - BT_MESH_DFD_PHASE_CANCELING_UPDATE, + BLE_MESH_DFD_PHASE_CANCELING_UPDATE, /** The Transfer BLOB procedure is suspended. */ - BT_MESH_DFD_PHASE_TRANSFER_SUSPENDED, + BLE_MESH_DFD_PHASE_TRANSFER_SUSPENDED, }; /** Firmware upload phases. */ enum bt_mesh_dfd_upload_phase { /** No firmware upload is in progress. */ - BT_MESH_DFD_UPLOAD_PHASE_IDLE, + BLE_MESH_DFD_UPLOAD_PHASE_IDLE, /** The Store Firmware procedure is being executed. */ - BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE, + BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ACTIVE, /** The Store Firmware procedure or Store Firmware OOB procedure failed. */ - BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR, + BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_ERROR, /** The Store Firmware procedure or the Store Firmware OOB procedure * completed successfully. */ - BT_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS, + BLE_MESH_DFD_UPLOAD_PHASE_TRANSFER_SUCCESS, }; /** @} */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_cli.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_cli.h new file mode 100644 index 0000000000..2fa96b0373 --- /dev/null +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_cli.h @@ -0,0 +1,472 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @defgroup bt_mesh_dfd_cli Device Firmware Distribution Client model + * @ingroup bt_mesh_dfd + * @{ + * @brief API for the Device Firmware Distribution Client model + */ + +#ifndef _BLE_MESH_v11_DFD_CLI_H__ +#define _BLE_MESH_v11_DFD_CLI_H__ + +#include "mesh/access.h" +#include "mesh/client_common.h" +#include "mesh_v1.1/dfu/dfd.h" +#include "mesh_v1.1/dfu/dfu_cli.h" +#include "mesh_v1.1/mbt/blob_cli.h" +#include "mesh_v1.1/mbt/blob_srv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Device Firmware Distribution Client model instance. */ +typedef bt_mesh_client_user_data_t bt_mesh_dfd_client_t; + +/** @brief DFD Client internal data structure. */ +typedef bt_mesh_client_internal_data_t dfd_internal_data_t; + +/*!< Maximum value of upload progress indicating progress is unset. */ +#define UPLOAD_PROGRESS_UNSET 101 + +/*!< In-band upload type. */ +#define UPLOAD_IN_BAND 0x00 + +/*!< Out-of-band upload type. */ +#define UPLOAD_OOB 0x01 + +/*!< Upload type is not set. */ +#define UPLOAD_TYPE_UNSET 0xFF + +/*!< Extract target address from target info bitfield. */ +#define TARGET_ADDR(target_info) (target_info >> 17) + +/*!< Extract target update phase from target info bitfield. */ +#define TARGET_UPDATE_PHASE(target_info) ((target_info >> 13) & 0x0f) + +/*!< Extract target update status from target info bitfield. */ +#define TARGET_UPDATE_STATUS(target_info) ((target_info >> 10) & 0x07) + +/*!< Extract target transfer status from target info bitfield. */ +#define TARGET_TRANSFER_STATUS(target_info) ((target_info >> 6) & 0x0f) + +/*!< Extract target transfer progress from target info bitfield. */ +#define TARGET_TRANSFER_PROGRESS(target_info) (target_info & 0x3f) + +/** + * @brief DFD Client receiver entry structure. + * + * This structure represents a single receiver node that will receive firmware + * distribution. Each receiver is identified by its unicast address and the + * firmware image index that should be distributed to it. + */ +typedef struct { + uint16_t addr; /*!< Unicast address of the receiver node. */ + uint8_t fw_idx; /*!< Index of the firmware image to distribute. */ +} dfd_cli_receiver_entry_t; + +/** + * @brief Target node entry information structure. + * + * This structure contains detailed information about a target node's + * firmware distribution status, including address, update phase, transfer + * progress, and other related information. + */ +typedef struct { + uint32_t addr:15; /*!< Unicast address of the target node. */ + uint32_t retrieved_update_phase:4; /*!< Current update phase of the target. */ + uint32_t update_status:3; /*!< Update status of the target node. */ + uint32_t transfer_status:4; /*!< Transfer status of the target. */ + uint32_t transfer_progress:6; /*!< Transfer progress percentage. */ + uint8_t update_fw_idx; /*!< Index of firmware being updated. */ +} target_node_entry_t; + +/** + * @brief DFD receiver status response structure. + * + * This structure contains the status response for receiver add/delete + * operations, including the operation result and current receiver list size. + */ +typedef struct { + uint8_t status; /*!< Status code of the operation (see @ref bt_mesh_dfd_status). */ + uint16_t receiver_list_cnt; /*!< Current number of receivers in the distribution list. */ +} dfd_cli_receiver_status_t; + +/** + * @brief DFD receiver list response structure. + * + * This structure contains the response to a receivers get request, + * providing a list of target nodes with their current status information. + */ +typedef struct { + uint16_t entries_cnt; /*!< Number of receiver entries in the list. */ + uint16_t first_index; /*!< Index of the first entry in the list. */ + target_node_entry_t *entries; /*!< Pointer to array of target node entries. */ +} dfd_cli_receiver_list_t; + +/** + * @brief DFD distribution capabilities structure. + * + * This structure contains the capabilities of the DFD Server, including + * storage limits, receiver limits, and supported features. + */ +typedef struct { + uint16_t max_receiver_list_sz; /*!< Maximum number of receivers supported. */ + uint16_t max_fw_list_sz; /*!< Maximum number of firmware images supported. */ + uint32_t max_fw_sz; /*!< Maximum firmware image size supported. */ + uint32_t max_upload_space; /*!< Total upload storage space available. */ + uint32_t remaining_upload_space; /*!< Remaining upload storage space. */ + uint8_t oob_retrieval_supported; /*!< OOB retrieval support flag. */ + struct net_buf_simple *supported_url_scheme_names; /*!< Supported URL scheme names. */ +} dfd_cli_dist_caps_t; + +/** + * @brief DFD distribution status structure. + * + * This structure contains the current status of an ongoing or completed + * firmware distribution operation, including phase, progress, and configuration. + */ +typedef struct { + uint8_t status; /*!< Distribution status code (see @ref bt_mesh_dfd_status). */ + uint8_t dist_phase; /*!< Current distribution phase (see @ref bt_mesh_dfd_phase). */ + uint16_t multicast_address; /*!< Multicast address used for distribution. */ + uint16_t appkey_idx; /*!< Application key index used for distribution. */ + uint8_t ttl; /*!< TTL value used for distribution messages. */ + uint16_t timeout_base; /*!< Base timeout value for distribution. */ + uint8_t trans_mode:2; /*!< Transfer mode (push or pull). */ + uint8_t update_policy:1; /*!< Update policy (single or all). */ + uint8_t RFU:5; /*!< Reserved for future use. */ + uint16_t fw_idx; /*!< Index of firmware being distributed. */ +} dfd_cli_dist_status_t; + +/** + * @brief DFD upload status structure. + * + * This structure contains the current status of a firmware upload operation, + * including phase, progress, and firmware identification. + */ +typedef struct { + uint8_t status; /*!< Upload operation status code (see @ref bt_mesh_dfd_status). */ + uint8_t upload_phase; /*!< Current upload phase (see @ref bt_mesh_dfd_upload_phase). */ + uint8_t upload_progress:7; /*!< Upload progress percentage (0-100). */ + uint8_t upload_type:1; /*!< Upload type (in-band or OOB). */ + union { + struct net_buf_simple *fwid; /*!< Firmware ID for in-band uploads. */ + struct net_buf_simple *oob_fwid; /*!< Firmware ID for OOB uploads. */ + }; +} dfd_cli_upload_status_t; + +/** + * @brief DFD firmware status structure. + * + * This structure contains the status response for firmware management + * operations, including information about firmware images. + */ +typedef struct { + uint8_t status; /*!< Firmware operation status code (see @ref bt_mesh_dfd_status). */ + uint16_t entry_cnt; /*!< Number of firmware entries. */ + uint16_t firmware_image_index; /*!< Index of the firmware image. */ + struct net_buf_simple *fwid; /*!< Firmware ID buffer. */ +} dfd_cli_firmware_status_t; + +/** + * @brief DFD distribution start parameters structure. + * + * This structure contains parameters for starting a firmware distribution + * operation, including target configuration and distribution settings. + */ +typedef struct { + uint8_t ttl; /*!< TTL value for distribution messages. */ + uint8_t trans_mode:2; /*!< Transfer mode (push or pull). */ + uint8_t update_policy:1; /*!< Update policy (single or all). */ + uint8_t RFU:5; /*!< Reserved for future use. */ + uint16_t app_idx; /*!< Application key index for distribution. */ + uint16_t timeout_base; /*!< Base timeout value for distribution. */ + uint16_t fw_idx; /*!< Index of firmware to distribute. */ + bool is_va; /*!< True if using virtual address, false for group address. */ + union { + uint16_t group_addr; /*!< Group address for distribution (if is_va is false). */ + uint8_t label_uuid[16]; /*!< Virtual label UUID for distribution (if is_va is true). */ + }; +} dfd_cli_dist_start_t; + +/** + * @brief DFD distribution upload start parameters structure. + * + * This structure contains parameters for starting an in-band firmware + * upload operation to the DFD Server. + */ +typedef struct { + uint8_t ttl; /*!< TTL value for upload messages. */ + uint16_t timeout_base; /*!< Base timeout value for upload. */ + uint32_t fw_size; /*!< Size of the firmware image in bytes. */ + uint64_t blob_id; /*!< BLOB ID for the firmware transfer. */ + struct net_buf_simple *fwid; /*!< Firmware ID buffer. */ + struct net_buf_simple *fw_metadata; /*!< Firmware metadata buffer. */ +} dfd_cli_dist_upload_start_t; + +/** + * @brief DFD distribution OOB upload start parameters structure. + * + * This structure contains parameters for starting an out-of-band firmware + * upload operation to the DFD Server. + */ +typedef struct { + struct net_buf_simple *fwid; /*!< Firmware ID buffer. */ + struct net_buf_simple *url; /*!< URL for retrieving the firmware. */ +} dfd_cli_dist_upload_oob_start_t; + +/** + * @brief DFD status response union. + * + * This union contains different status response structures for various DFD + * Client operations, allowing type-safe access to operation-specific responses. + */ +typedef union { + dfd_cli_receiver_status_t receiver_status; /*!< Receiver add/delete status. */ + dfd_cli_receiver_list_t receiver_list; /*!< Receiver list response. */ + dfd_cli_dist_caps_t dist_caps; /*!< Distribution capabilities. */ + dfd_cli_dist_status_t dist_status; /*!< Distribution status. */ + dfd_cli_upload_status_t upload_status; /*!< Upload status. */ + dfd_cli_firmware_status_t firmware_status; /*!< Firmware management status. */ +} dfd_status_t; + +/*!< DFD Client model operation handlers. */ +extern const struct bt_mesh_model_op _bt_mesh_dfd_cli_op[]; + +/*!< DFD Client model callbacks. */ +extern const struct bt_mesh_model_cb _bt_mesh_dfd_cli_cb; + +/** + * @brief Add receivers to the distribution list. + * + * Add multiple target nodes to the DFD Server's distribution receiver list. + * These receivers will be included in subsequent firmware distribution operations. + * + * @param[in] param Common client parameters for the operation. + * @param[in] receivers Pointer to array of receiver entries to add. + * @param[in] receivers_cnt Number of receiver entries in the array. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_receivers_add(bt_mesh_client_common_param_t *param, + dfd_cli_receiver_entry_t *receivers, + uint16_t receivers_cnt); + +/** + * @brief Delete all receivers from the distribution list. + * + * Remove all target nodes from the DFD Server's distribution receiver list. + * This operation will clear the entire receiver list. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_receivers_delete_all(bt_mesh_client_common_param_t *param); + +/** + * @brief Get the distribution receiver list. + * + * Retrieve a portion of the DFD Server's distribution receiver list. + * Supports pagination to retrieve large receiver lists in chunks. + * + * @param[in] param Common client parameters for the operation. + * @param[in] first_index Index of the first receiver entry to retrieve. + * @param[in] entries_limit Maximum number of entries to retrieve. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_receivers_get(bt_mesh_client_common_param_t *param, + uint16_t first_index, + uint16_t entries_limit); + +/** + * @brief Get distribution capabilities from the DFD Server. + * + * Query the DFD Server's capabilities, including storage limits, + * supported features, and maximum receiver count. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_capabilities_get(bt_mesh_client_common_param_t *param); +/** + * @brief Get current distribution status from the DFD Server. + * + * Query the current status of firmware distribution operations, + * including phase, progress, and configuration information. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_get(bt_mesh_client_common_param_t *param); + +/** + * @brief Start firmware distribution to receivers. + * + * Initiate firmware distribution to all target nodes in the distribution + * receiver list using the specified configuration parameters. + * + * @param[in] param Common client parameters for the operation. + * @param[in] start Distribution start parameters and configuration. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_start_t *start); + +/** + * @brief Suspend ongoing firmware distribution. + * + * Suspend a currently active firmware distribution operation. + * The distribution can be resumed later if needed. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_suspend(bt_mesh_client_common_param_t *param); + +/** + * @brief Cancel firmware distribution. + * + * Cancel an ongoing or suspended firmware distribution operation. + * This will terminate the distribution process. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_cancel(bt_mesh_client_common_param_t *param); + +/** + * @brief Apply distributed firmware on target nodes. + * + * Apply the distributed firmware image on target nodes that have + * successfully received the firmware transfer. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_apply(bt_mesh_client_common_param_t *param); +/** + * @brief Get firmware upload status from the DFD Server. + * + * Query the current status of firmware upload operations, including + * phase, progress, and transfer information. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_upload_get(bt_mesh_client_common_param_t *param); + +/** + * @brief Start in-band firmware upload to the DFD Server. + * + * Initiate an in-band firmware upload using BLOB transfer protocol. + * The firmware image will be transferred directly through the mesh network. + * + * @param[in] param Common client parameters for the operation. + * @param[in] start Upload start parameters including firmware details. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_upload_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_upload_start_t *start); + +/** + * @brief Start out-of-band firmware upload to the DFD Server. + * + * Initiate an out-of-band firmware upload where the DFD Server + * retrieves the firmware from the specified URL. + * + * @param[in] param Common client parameters for the operation. + * @param[in] start OOB upload start parameters including URL and firmware ID. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_upload_oob_start(bt_mesh_client_common_param_t *param, + dfd_cli_dist_upload_oob_start_t *start); + +/** + * @brief Cancel out-of-band firmware upload. + * + * Cancel an ongoing out-of-band firmware upload operation. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_distribution_upload_oob_cancel(bt_mesh_client_common_param_t *param); +/** + * @brief Get firmware information by firmware ID. + * + * Query detailed information about a specific firmware image + * stored on the DFD Server using its firmware ID. + * + * @param[in] param Common client parameters for the operation. + * @param[in] fwid Firmware ID to query information for. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_firmware_get(bt_mesh_client_common_param_t *param, + struct net_buf_simple *fwid); + +/** + * @brief Get firmware information by index. + * + * Query detailed information about a firmware image stored on the + * DFD Server using its index in the firmware list. + * + * @param[in] param Common client parameters for the operation. + * @param[in] fw_id_index Index of the firmware image to query. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_firmware_get_by_index(bt_mesh_client_common_param_t *param, + uint16_t fw_id_index); + +/** + * @brief Delete specific firmware image by firmware ID. + * + * Delete a specific firmware image from the DFD Server's storage + * using its firmware ID. + * + * @param[in] param Common client parameters for the operation. + * @param[in] fwid Firmware ID of the image to delete. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_firmware_get_delete(bt_mesh_client_common_param_t *param, + struct net_buf_simple *fwid); + +/** + * @brief Delete all firmware images from the DFD Server. + * + * Delete all firmware images stored on the DFD Server. + * This operation will clear the entire firmware storage. + * + * @param[in] param Common client parameters for the operation. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_dfd_cli_firmware_delete_all(bt_mesh_client_common_param_t *param); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* _BLE_MESH_v11_DFD_CLI_H__ */ diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h index fd0223af1c..b494ce775d 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfd_srv.h @@ -42,15 +42,14 @@ struct bt_mesh_dfd_srv; #ifdef CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD /** + * @brief Initialization parameters for the @ref bt_mesh_dfd_srv with OOB + * upload support. * - * @brief Initialization parameters for the @ref bt_mesh_dfd_srv with OOB - * upload support. - * - * @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance. - * @param[in] _oob_schemes Array of OOB schemes supported by the server, - * each scheme being a code point from the - * Bluetooth SIG Assigned Numbers document. - * @param[in] _oob_schemes_count Number of schemes in @c _oob_schemes. + * @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance. + * @param[in] _oob_schemes Array of OOB schemes supported by the server, + * each scheme being a code point from the + * Bluetooth SIG Assigned Numbers document. + * @param[in] _oob_schemes_count Number of schemes in @c _oob_schemes. */ #define BT_MESH_DFD_SRV_OOB_INIT(_cb, _oob_schemes, _oob_schemes_count) \ { \ @@ -67,10 +66,9 @@ struct bt_mesh_dfd_srv; #endif /* CONFIG_BLE_MESH_DFD_SRV_OOB_UPLOAD */ /** + * @brief Initialization parameters for the @ref bt_mesh_dfd_srv. * - * @brief Initialization parameters for the @ref bt_mesh_dfd_srv. - * - * @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance. + * @param[in] _cb Pointer to a @ref bt_mesh_dfd_srv_cb instance. */ #define BT_MESH_DFD_SRV_INIT(_cb) \ { \ @@ -82,10 +80,9 @@ struct bt_mesh_dfd_srv; } /** + * @brief Firmware Distribution Server model Composition Data entry. * - * @brief Firmware Distribution Server model Composition Data entry. - * - * @param _srv Pointer to a @ref bt_mesh_dfd_srv instance. + * @param _srv Pointer to a @ref bt_mesh_dfd_srv instance. */ #define BT_MESH_MODEL_DFD_SRV(_srv) \ BT_MESH_MODEL_DFU_CLI(&(_srv)->dfu), \ @@ -98,15 +95,15 @@ struct bt_mesh_dfd_srv_cb { /** @brief Slot receive callback. * - * Called at the start of an upload procedure. The callback must fill - * @c io with a pointer to a writable BLOB stream for the Firmware Distribution - * Server to write the firmware image to. + * Called at the start of an upload procedure. The callback must fill + * @c io with a pointer to a writable BLOB stream for the Firmware Distribution + * Server to write the firmware image to. * - * @param srv Firmware Distribution Server model instance. - * @param slot DFU image slot being received. - * @param io BLOB stream response pointer. + * @param srv Firmware Distribution Server model instance. + * @param slot DFU image slot being received. + * @param io BLOB stream response pointer. * - * @return 0 on success, or (negative) error code otherwise. + * @return 0 on success, or (negative) error code otherwise. */ int (*recv)(struct bt_mesh_dfd_srv *srv, const struct bt_mesh_dfu_slot *slot, @@ -136,7 +133,7 @@ struct bt_mesh_dfd_srv_cb { * available, or to 0 if new firmware is not * available. * - * @return BT_MESH_DFD_SUCCESS on success, or error code otherwise. + * @return BLE_MESH_DFD_SUCCESS on success, or error code otherwise. */ int (*start_oob_upload)(struct bt_mesh_dfd_srv *srv, const struct bt_mesh_dfu_slot *slot, @@ -255,11 +252,11 @@ struct bt_mesh_dfd_srv { * callback has completed or failed. The @p status param should be set to one of the following * values: * - * * @c BT_MESH_DFD_SUCCESS if the check was successful and a new firmware ID was found. - * * @c BT_MESH_DFD_ERR_URI_MALFORMED if the URI is not formatted correctly. - * * @c BT_MESH_DFD_ERR_URI_NOT_SUPPORTED if the URI scheme is not supported by the node. - * * @c BT_MESH_DFD_ERR_URI_UNREACHABLE if the URI can't be reached. - * * @c BT_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE if the check completes successfully but no new + * * @c BLE_MESH_DFD_SUCCESS if the check was successful and a new firmware ID was found. + * * @c BLE_MESH_DFD_ERR_URI_MALFORMED if the URI is not formatted correctly. + * * @c BLE_MESH_DFD_ERR_URI_NOT_SUPPORTED if the URI scheme is not supported by the node. + * * @c BLE_MESH_DFD_ERR_URI_UNREACHABLE if the URI can't be reached. + * * @c BLE_MESH_DFD_ERR_NEW_FW_NOT_AVAILABLE if the check completes successfully but no new * firmware is available. * * If this function returns 0, the application should then download the firmware to the diff --git a/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst b/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst index b83b6059ff..94e7cccfe6 100644 --- a/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst +++ b/docs/en/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst @@ -135,11 +135,11 @@ Mesh Models * Device Firmware Update Client models * Firmware Update Client model (Preview) - * Firmware Distribution Client model (coming soon) + * Firmware Distribution Client model (Preview) + * Device Firmware Update Server models * Firmware Update Server model (Preview) - * Firmware Distribution Server model (coming soon) - + * Firmware Distribution Server model (Preview) Mesh Examples """"""""""""" diff --git a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst index edac2c0b2c..a383f17c3d 100644 --- a/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst +++ b/docs/zh_CN/api-guides/esp-ble-mesh/ble-mesh-feature-list.rst @@ -132,6 +132,14 @@ Mesh 模型 * 灯光 LC 服务器 * 灯光 LC 设置服务器 +* 设备固件更新客户端模型 + * 固件更新客户端模型(预览) + * 固件分发客户端模型(预览) + +* 设备固件更新服务器模型 + * 固件更新服务器模型(预览) + * 固件分发服务器模型(预览) + Mesh 示例 """"""""""" From dde791b387323639cb4553b333fd3638028fcec8 Mon Sep 17 00:00:00 2001 From: Linyan Liu Date: Wed, 27 Aug 2025 16:11:56 +0800 Subject: [PATCH 141/156] feat(ble_mesh): Miscellaneous update for BLE Mesh --- components/bt/CMakeLists.txt | 12 +- components/bt/esp_ble_mesh/core/access.c | 70 ++++++- components/bt/esp_ble_mesh/core/adv.c | 86 +++----- components/bt/esp_ble_mesh/core/adv.h | 4 - components/bt/esp_ble_mesh/core/adv_common.c | 196 +++++++++--------- components/bt/esp_ble_mesh/core/adv_common.h | 54 +++-- components/bt/esp_ble_mesh/core/ble_adv.c | 33 +-- .../core/bluedroid_host/adapter.c | 8 +- components/bt/esp_ble_mesh/core/ext_adv.c | 129 +++++------- components/bt/esp_ble_mesh/core/ext_adv.h | 9 +- components/bt/esp_ble_mesh/core/friend.c | 2 +- .../esp_ble_mesh/core/include/mesh/adapter.h | 10 +- components/bt/esp_ble_mesh/core/net.c | 14 +- .../esp_ble_mesh/core/nimble_host/adapter.c | 25 ++- .../bt/esp_ble_mesh/core/proxy_server.c | 10 + components/bt/esp_ble_mesh/core/scan.c | 40 ++-- components/bt/esp_ble_mesh/core/transport.c | 83 +------- .../bt/esp_ble_mesh/core/transport.enh.c | 68 ------ .../models/client/client_common.c | 51 ++--- 19 files changed, 392 insertions(+), 512 deletions(-) diff --git a/components/bt/CMakeLists.txt b/components/bt/CMakeLists.txt index 1f942a3a21..c412ca6146 100644 --- a/components/bt/CMakeLists.txt +++ b/components/bt/CMakeLists.txt @@ -571,7 +571,6 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/core/storage/settings.c" "esp_ble_mesh/core/access.c" "esp_ble_mesh/core/adv_common.c" - "esp_ble_mesh/core/ble_adv.c" "esp_ble_mesh/core/beacon.c" "esp_ble_mesh/core/cfg_cli.c" "esp_ble_mesh/core/cfg_srv.c" @@ -634,24 +633,27 @@ if(CONFIG_BT_ENABLED) "esp_ble_mesh/v1.1/btc/btc_ble_mesh_sar_model.c" "esp_ble_mesh/v1.1/btc/btc_ble_mesh_srpl_model.c" "esp_ble_mesh/lib/ext.c") + if(CONFIG_BLE_MESH_SAR_ENHANCEMENT) list(APPEND srcs "esp_ble_mesh/core/transport.enh.c") else() list(APPEND srcs "esp_ble_mesh/core/transport.c") endif() else() - list(APPEND srcs - "esp_ble_mesh/core/transport.c") + list(APPEND srcs "esp_ble_mesh/core/transport.c") endif() + if(CONFIG_BLE_MESH_SUPPORT_MULTI_ADV) list(APPEND srcs "esp_ble_mesh/core/ext_adv.c") else() list(APPEND srcs "esp_ble_mesh/core/adv.c") endif() + + if(CONFIG_BLE_MESH_SUPPORT_BLE_ADV) + list(APPEND srcs "esp_ble_mesh/core/ble_adv.c") + endif() endif() - - if(CONFIG_BT_LE_CONTROLLER_NPL_OS_PORTING_SUPPORT) list(APPEND srcs "porting/npl/freertos/src/npl_os_freertos.c" diff --git a/components/bt/esp_ble_mesh/core/access.c b/components/bt/esp_ble_mesh/core/access.c index 86d80139d0..44b7009d8e 100644 --- a/components/bt/esp_ble_mesh/core/access.c +++ b/components/bt/esp_ble_mesh/core/access.c @@ -117,7 +117,7 @@ static int32_t next_period(struct bt_mesh_model *mod) if (!pub) { BT_ERR("Model has no publication support"); - return -ENOTSUP; + return 0; } period = bt_mesh_model_pub_period_get(mod); @@ -1385,3 +1385,71 @@ struct bt_mesh_app_key *bt_mesh_rx_appkey_get(size_t index) return key; } + +struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) +{ + if (bt_mesh_is_provisioned()) { +#if CONFIG_BLE_MESH_NODE + if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { + for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { + if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && + bt_mesh.app_keys[i].app_idx == app_idx) { + return &bt_mesh.app_keys[i]; + } + } + } else { + return bt_mesh_fast_prov_app_key_find(app_idx); + } +#endif + } else if (bt_mesh_is_provisioner_en()) { +#if CONFIG_BLE_MESH_PROVISIONER + for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { + if (bt_mesh.p_app_keys[i] && + bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && + bt_mesh.p_app_keys[i]->app_idx == app_idx) { + return bt_mesh.p_app_keys[i]; + } + } +#endif + } + + return NULL; +} + +int bt_mesh_upper_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, + const uint8_t **key, uint8_t *aid, uint16_t dst) +{ + struct bt_mesh_app_key *app_key = NULL; + + if (app_idx == BLE_MESH_KEY_DEV) { + *key = bt_mesh_dev_key_get(dst); + if (!*key) { + BT_ERR("DevKey of 0x%04x not found", dst); + return -EINVAL; + } + + *aid = 0U; + return 0; + } + + if (!subnet) { + BT_ERR("Invalid subnet"); + return -EINVAL; + } + + app_key = bt_mesh_app_key_get(app_idx); + if (!app_key) { + BT_ERR("AppKey 0x%04x not found", app_idx); + return -ENOENT; + } + + if (subnet->kr_phase == BLE_MESH_KR_PHASE_2 && app_key->updated) { + *key = app_key->keys[1].val; + *aid = app_key->keys[1].id; + } else { + *key = app_key->keys[0].val; + *aid = app_key->keys[0].id; + } + + return 0; +} diff --git a/components/bt/esp_ble_mesh/core/adv.c b/components/bt/esp_ble_mesh/core/adv.c index fa4249c187..d9096caa13 100644 --- a/components/bt/esp_ble_mesh/core/adv.c +++ b/components/bt/esp_ble_mesh/core/adv.c @@ -37,24 +37,7 @@ static QueueSetHandle_t mesh_queue_set; #endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ -static inline void adv_send_start(uint16_t duration, int err, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->start) { - cb->start(duration, err, cb_data); - } -} - -static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->end) { - cb->end(err, cb_data); - } -} - -static inline int adv_send(struct net_buf *buf) +static int adv_send(struct net_buf *buf) { const struct bt_mesh_send_cb *cb = BLE_MESH_ADV(buf)->cb; void *cb_data = BLE_MESH_ADV(buf)->cb_data; @@ -201,17 +184,15 @@ static inline int adv_send(struct net_buf *buf) BT_DBG("Advertising started. Sleeping %u ms", duration); #if CONFIG_BLE_MESH_USE_BLE_50 - if (!ble_mesh_adv_task_wait(UINT32_MAX, K_FOREVER, NULL)) { + if (!bt_mesh_adv_task_wait(UINT32_MAX, K_FOREVER, NULL)) { BT_WARN("Advertising didn't finish on time"); bt_le_ext_adv_stop(CONFIG_BLE_MESH_ADV_INST_ID); } #else /* CONFIG_BLE_MESH_USE_BLE_50 */ - ble_mesh_adv_task_wait(K_MSEC(duration)); -#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ + bt_mesh_adv_task_wait(K_MSEC(duration)); -#if !CONFIG_BLE_MESH_USE_BLE_50 err = bt_le_adv_stop(); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ adv_send_end(err, cb, cb_data); if (err) { @@ -223,15 +204,34 @@ static inline int adv_send(struct net_buf *buf) return 0; } +#if CONFIG_BLE_MESH_RELAY_ADV_BUF +static QueueHandle_t relay_adv_handle_get(void) +{ + struct bt_mesh_adv_type_manager *adv_type = NULL; + + adv_type = bt_mesh_adv_types_mgmt_get(BLE_MESH_ADV_RELAY_DATA); + + if (adv_type->adv_q == NULL) { + return NULL; + } + + return adv_type->adv_q->q.handle; +} +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ + static void adv_thread(void *p) { #if CONFIG_BLE_MESH_RELAY_ADV_BUF + QueueHandle_t relay_adv_handle = NULL; QueueSetMemberHandle_t handle = NULL; - QueueHandle_t relay_adv_handle = - bt_mesh_adv_types_mgnt_get(BLE_MESH_ADV_RELAY_DATA)->adv_q->q.handle; #endif - bt_mesh_msg_t msg = {0}; struct net_buf **buf = NULL; + bt_mesh_msg_t msg = {0}; + +#if CONFIG_BLE_MESH_RELAY_ADV_BUF + relay_adv_handle = relay_adv_handle_get(); + assert(relay_adv_handle); +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ buf = (struct net_buf **)(&msg.arg); @@ -328,28 +328,6 @@ static void adv_thread(void *p) } } -void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - bt_mesh_msg_t msg = { - .relay = false, - }; - - BT_DBG("type 0x%02x len %u: %s", BLE_MESH_ADV(buf)->type, buf->len, - bt_hex(buf->data, buf->len)); - - BLE_MESH_ADV(buf)->cb = cb; - BLE_MESH_ADV(buf)->cb_data = cb_data; - bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1); - BLE_MESH_ADV(buf)->xmit = xmit; - - bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); - - msg.arg = (void *)net_buf_ref(buf); - bt_mesh_task_post(&msg, portMAX_DELAY, false); -} - void bt_mesh_adv_update(void) { bt_mesh_msg_t msg = { @@ -375,11 +353,11 @@ void bt_mesh_adv_init(void) bt_mesh_ble_adv_init(); #endif -#if CONFIG_BLE_MESH_RELAY_ADV_BUF && !CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - QueueHandle_t relay_adv_handle = - bt_mesh_adv_types_mgnt_get(BLE_MESH_ADV_RELAY_DATA)->adv_q->q.handle; +#if CONFIG_BLE_MESH_RELAY_ADV_BUF + QueueHandle_t relay_adv_handle = relay_adv_handle_get(); + assert(relay_adv_handle); mesh_queue_set = xQueueCreateSet(BLE_MESH_QUEUE_SET_SIZE); - __ASSERT(mesh_queue_set, "Failed to create queue set"); + assert(mesh_queue_set); xQueueAddToSet(adv_queue->q.handle, mesh_queue_set); xQueueAddToSet(relay_adv_handle, mesh_queue_set); #endif @@ -394,8 +372,8 @@ void bt_mesh_adv_deinit(void) bt_mesh_adv_task_deinit(); #if CONFIG_BLE_MESH_RELAY_ADV_BUF - QueueHandle_t relay_adv_handle = - bt_mesh_adv_types_mgnt_get(BLE_MESH_ADV_RELAY_DATA)->adv_q->q.handle; + QueueHandle_t relay_adv_handle = relay_adv_handle_get(); + assert(relay_adv_handle); xQueueRemoveFromSet(adv_queue->q.handle, mesh_queue_set); xQueueRemoveFromSet(relay_adv_handle, mesh_queue_set); diff --git a/components/bt/esp_ble_mesh/core/adv.h b/components/bt/esp_ble_mesh/core/adv.h index 5770364a2e..a2c8dd0330 100644 --- a/components/bt/esp_ble_mesh/core/adv.h +++ b/components/bt/esp_ble_mesh/core/adv.h @@ -23,10 +23,6 @@ extern "C" { #endif -void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, - const struct bt_mesh_send_cb *cb, - void *cb_data); - void bt_mesh_adv_update(void); void bt_mesh_adv_init(void); diff --git a/components/bt/esp_ble_mesh/core/adv_common.c b/components/bt/esp_ble_mesh/core/adv_common.c index 96b4ac773a..ec1e3b68db 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.c +++ b/components/bt/esp_ble_mesh/core/adv_common.c @@ -76,15 +76,7 @@ static inline void init_adv_with_defaults(struct bt_mesh_adv *adv, NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, BLE_MESH_ADV_DATA_SIZE, NULL); -bt_mesh_friend_adv_t frnd_adv_pool[FRIEND_BUF_COUNT]; - -struct bt_mesh_adv *bt_mesh_frnd_adv_buf_get(int idx, enum bt_mesh_adv_type type) -{ - memset(&frnd_adv_pool[idx].adv, 0, sizeof(struct bt_mesh_adv)); - init_adv_with_defaults(&frnd_adv_pool[idx].adv, type); - frnd_adv_pool[idx].app_idx = BLE_MESH_KEY_UNUSED; - return &frnd_adv_pool[idx].adv; -} +static bt_mesh_friend_adv_t frnd_adv_pool[FRIEND_BUF_COUNT]; #endif struct bt_mesh_adv_task { @@ -102,7 +94,7 @@ static struct bt_mesh_adv_type_manager adv_types[BLE_MESH_ADV_TYPES_NUM]; #if CONFIG_BLE_MESH_USE_BLE_50 static struct bt_mesh_adv_inst adv_insts[] = { - [BLE_MESH_ADV_INS] = { + [BLE_MESH_ADV_INST] = { .id = CONFIG_BLE_MESH_ADV_INST_ID, #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV .busy = false, @@ -111,19 +103,19 @@ static struct bt_mesh_adv_inst adv_insts[] = { #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER - [BLE_MESH_ADV_PROXY_INS] = { + [BLE_MESH_ADV_PROXY_INST] = { .id = CONFIG_BLE_MESH_PROXY_ADV_INST_ID, .busy = false, }, #endif #if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE - [BLE_MESH_RELAY_ADV_INS] = { + [BLE_MESH_RELAY_ADV_INST] = { .id = CONFIG_BLE_MESH_RELAY_ADV_INST_ID, .busy = false, }, #endif #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE - [BLE_MESH_BLE_ADV_INS] = { + [BLE_MESH_BLE_ADV_INST] = { .id = CONFIG_BLE_MESH_BLE_ADV_INST_ID, .busy = false, }, @@ -154,7 +146,7 @@ bool bt_mesh_is_adv_inst_used(uint8_t adv_inst_id) int bt_mesh_adv_inst_init(enum bt_mesh_adv_inst_type inst_type, uint8_t inst_id) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { BT_ERR("Invalid instance type %d", inst_type); return -EINVAL; } @@ -170,7 +162,7 @@ int bt_mesh_adv_inst_init(enum bt_mesh_adv_inst_type inst_type, uint8_t inst_id) int bt_mesh_adv_inst_deinit(enum bt_mesh_adv_inst_type inst_type) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { BT_ERR("Invalid instance type %d", inst_type); return -EINVAL; } @@ -186,7 +178,7 @@ int bt_mesh_adv_inst_deinit(enum bt_mesh_adv_inst_type inst_type) #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ -struct bt_mesh_adv *adv_alloc(int id, enum bt_mesh_adv_type type) +static struct bt_mesh_adv *adv_alloc(int id, enum bt_mesh_adv_type type) { init_adv_with_defaults(&adv_pool[id], type); return &adv_pool[id]; @@ -268,10 +260,10 @@ void bt_mesh_adv_buf_ref_debug(const char *func, struct net_buf *buf, } #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV -void bt_mesh_adv_inst_supported_adv_type_add(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type) +void bt_mesh_adv_inst_type_add(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { BT_ERR("Invalid instance type %d", inst_type); return; } @@ -284,10 +276,10 @@ void bt_mesh_adv_inst_supported_adv_type_add(enum bt_mesh_adv_inst_type inst_typ adv_insts[inst_type].spt_mask |= BIT(adv_type); } -void bt_mesh_adv_inst_supported_adv_type_rm(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type) +void bt_mesh_adv_inst_type_rm(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { BT_ERR("Invalid instance type %d", inst_type); return; } @@ -303,7 +295,7 @@ void bt_mesh_adv_inst_supported_adv_type_rm(enum bt_mesh_adv_inst_type inst_type void bt_mesh_adv_inst_supported_adv_type_clear(enum bt_mesh_adv_inst_type inst_type, enum bt_mesh_adv_type adv_type) { - if (inst_type >= BLE_MESH_ADV_INS_TYPES_NUM) { + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { BT_ERR("Invalid instance type %d", inst_type); return; } @@ -379,18 +371,18 @@ void bt_mesh_adv_type_deinit(enum bt_mesh_adv_type adv_type) } #if CONFIG_BLE_MESH_USE_BLE_50 -int ble_mesh_adv_task_wakeup(uint32_t evt) +int bt_mesh_adv_task_wakeup(uint32_t evt) { xTaskNotify(adv_task.handle, evt, eSetBits); return 0; } -bool ble_mesh_adv_task_wait(uint32_t wait_bits, uint32_t timeout, uint32_t *notify) +bool bt_mesh_adv_task_wait(uint32_t wait_bits, uint32_t timeout, uint32_t *notify) { return (xTaskNotifyWait(wait_bits, UINT32_MAX, notify, K_WAIT(timeout)) == pdTRUE); } #else /* CONFIG_BLE_MESH_USE_BLE_50 */ -bool ble_mesh_adv_task_wait(uint32_t timeout) +bool bt_mesh_adv_task_wait(uint32_t timeout) { vTaskDelay(K_WAIT(timeout)); return true; @@ -408,25 +400,29 @@ uint16_t bt_mesh_pdu_duration(uint8_t xmit) return duration; } -struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, - int32_t timeout) +struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, int32_t timeout) { struct bt_mesh_adv *adv = NULL; struct net_buf *buf = NULL; - struct net_buf_pool *pool = adv_types[type].pool; if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_SUSPENDED)) { BT_WARN("Refusing to allocate buffer while suspended"); return NULL; } - if (!pool || !adv_types[type].pool_allocator) { + if (type >= BLE_MESH_ADV_TYPES_NUM) { + BT_ERR("%s, Invalid adv type %u", __func__, type); + return NULL; + } + + if (adv_types[type].pool == NULL || adv_types[type].pool_allocator == NULL) { BT_ERR("Uninitialized adv type %d", type); return NULL; } bt_mesh_r_mutex_lock(&adv_buf_alloc_lock); - buf = net_buf_alloc(pool, timeout); + + buf = net_buf_alloc(adv_types[type].pool, timeout); if (!buf) { bt_mesh_r_mutex_unlock(&adv_buf_alloc_lock); BT_WARN("Buf alloc failed"); @@ -434,7 +430,8 @@ struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, } BT_DBG("pool %p, buf_count %d, uinit_count %d, ref %d", - buf->pool, pool->buf_count, pool->uninit_count, buf->ref); + adv_types[type].pool, adv_types[type].pool->buf_count, + adv_types[type].pool->uninit_count, buf->ref); adv = adv_types[type].pool_allocator(net_buf_id(buf), type); BLE_MESH_ADV(buf) = adv; @@ -460,10 +457,9 @@ void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool) void bt_mesh_unref_buf(bt_mesh_msg_t *msg) { - struct net_buf *buf = NULL; + struct net_buf *buf = msg->arg; - if (msg->arg) { - buf = (struct net_buf *)msg->arg; + if (buf) { bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0); if (buf->ref > 1U) { buf->ref = 1U; @@ -502,12 +498,13 @@ void bt_mesh_generic_adv_send(struct net_buf *buf, uint8_t xmit, } #endif - assert(adv_types[BLE_MESH_ADV(buf)->type].adv_q && adv_types[BLE_MESH_ADV(buf)->type].adv_q->send); + assert(adv_types[BLE_MESH_ADV(buf)->type].adv_q); + assert(adv_types[BLE_MESH_ADV(buf)->type].adv_q->send); adv_types[BLE_MESH_ADV(buf)->type].adv_q->send(&msg, portMAX_DELAY, front); #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - ble_mesh_adv_task_wakeup(ADV_TASK_PKT_SEND_EVT); + bt_mesh_adv_task_wakeup(ADV_TASK_PKT_SEND_EVT); #endif } @@ -558,12 +555,7 @@ static struct bt_mesh_adv *relay_adv_alloc(int id, enum bt_mesh_adv_type type) return &relay_adv_pool[id]; } -struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, int32_t timeout) -{ - return bt_mesh_adv_create_from_pool(type, timeout); -} - -static void ble_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) +static void bt_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) { bt_mesh_msg_t old_msg = {0}; @@ -609,7 +601,7 @@ uint16_t bt_mesh_get_stored_relay_count(void) } static ALWAYS_INLINE -uint16_t ble_mesh_relay_adv_buf_count_get(void) +uint16_t bt_mesh_relay_adv_buf_count_get(void) { uint16_t relay_adv_count = 2 + CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT; @@ -625,8 +617,8 @@ uint16_t ble_mesh_relay_adv_buf_count_get(void) void bt_mesh_relay_adv_init(void) { - bt_mesh_adv_queue_init(&relay_adv_queue, ble_mesh_relay_adv_buf_count_get(), - ble_mesh_relay_task_post); + bt_mesh_adv_queue_init(&relay_adv_queue, bt_mesh_relay_adv_buf_count_get(), + bt_mesh_relay_task_post); bt_mesh_adv_type_init(BLE_MESH_ADV_RELAY_DATA, &relay_adv_queue, &relay_adv_buf_pool, &relay_adv_alloc); #if CONFIG_BLE_MESH_EXT_ADV @@ -634,29 +626,29 @@ void bt_mesh_relay_adv_init(void) &ext_adv_buf_pool, &ext_relay_adv_alloc); #if CONFIG_BLE_MESH_LONG_PACKET && CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_LONG_RELAY_DATA, &relay_adv_queue, - &ext_long_relay_adv_buf_pool, ext_long_relay_adv_alloc); -#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + &ext_long_relay_adv_buf_pool, ext_long_relay_adv_alloc); +#endif /* CONFIG_BLE_MESH_LONG_PACKET && CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE - bt_mesh_adv_inst_init(BLE_MESH_RELAY_ADV_INS, + bt_mesh_adv_inst_init(BLE_MESH_RELAY_ADV_INST, CONFIG_BLE_MESH_RELAY_ADV_INST_ID); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ -#else +#else /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -673,25 +665,25 @@ void bt_mesh_relay_adv_deinit(void) #if CONFIG_BLE_MESH_LONG_PACKET bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ -#endif +#endif /* CONFIG_BLE_MESH_EXT_ADV */ #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_rm(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_rm(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_RELAY_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_rm(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ - bt_mesh_adv_inst_deinit(BLE_MESH_RELAY_ADV_INS); -#else + bt_mesh_adv_inst_deinit(BLE_MESH_RELAY_ADV_INST); +#else /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -704,16 +696,19 @@ void bt_mesh_relay_adv_deinit(void) #endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_FRIEND -struct net_buf_pool *bt_mesh_frnd_adv_pool_get(void) +static struct bt_mesh_adv *bt_mesh_frnd_adv_buf_get(int idx, enum bt_mesh_adv_type type) { - return &friend_buf_pool; + memset(&frnd_adv_pool[idx].adv, 0, sizeof(struct bt_mesh_adv)); + init_adv_with_defaults(&frnd_adv_pool[idx].adv, type); + frnd_adv_pool[idx].app_idx = BLE_MESH_KEY_UNUSED; + return &frnd_adv_pool[idx].adv; } void bt_mesh_frnd_adv_init(void) { bt_mesh_adv_type_init(BLE_MESH_ADV_FRIEND, &adv_queue, &friend_buf_pool, bt_mesh_frnd_adv_buf_get); #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_FRIEND); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_FRIEND); #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ } @@ -722,7 +717,7 @@ void bt_mesh_frnd_adv_deinit(void) bt_mesh_adv_type_deinit(BLE_MESH_ADV_FRIEND); #if CONFIG_BLE_MESH_FRIEND && CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_FRIEND); + bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_FRIEND); #endif /* CONFIG_BLE_MESH_FRIEND */ bt_mesh_unref_buf_from_pool(&friend_buf_pool); @@ -731,7 +726,7 @@ void bt_mesh_frnd_adv_deinit(void) #endif /* CONFIG_BLE_MESH_FRIEND */ static ALWAYS_INLINE -uint16_t ble_mesh_adv_buf_count_get(void) +uint16_t bt_mesh_adv_buf_count_get(void) { uint16_t adv_count = 2 + CONFIG_BLE_MESH_ADV_BUF_COUNT; @@ -739,15 +734,15 @@ uint16_t ble_mesh_adv_buf_count_get(void) adv_count += CONFIG_BLE_MESH_EXT_ADV_BUF_COUNT; #if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY adv_count += CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT; -#endif -#endif +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ #if CONFIG_BLE_MESH_LONG_PACKET adv_count += CONFIG_BLE_MESH_LONG_PACKET_ADV_BUF_COUNT; #if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY adv_count += CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT; -#endif -#endif +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY */ +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ #if (CONFIG_BLE_MESH_SUPPORT_BLE_ADV && \ !(CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE)) @@ -768,24 +763,29 @@ void bt_mesh_adv_task_init(void adv_thread(void *p)) (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \ CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY) adv_task.task = heap_caps_calloc(1, sizeof(StaticTask_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); - __ASSERT(adv_task.task, "Failed to create adv thread task"); - adv_task.stack = heap_caps_calloc_prefer(1, BLE_MESH_ADV_TASK_STACK_SIZE * sizeof(StackType_t), 2, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT, MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); - __ASSERT(adv_task.stack, "Failed to create adv thread stack"); - adv_task.handle = xTaskCreateStaticPinnedToCore(adv_thread, BLE_MESH_ADV_TASK_NAME, BLE_MESH_ADV_TASK_STACK_SIZE, NULL, - BLE_MESH_ADV_TASK_PRIO, adv_task.stack, adv_task.task, BLE_MESH_ADV_TASK_CORE); - __ASSERT(adv_task.handle, "Failed to create static adv thread"); + assert(adv_task.task); + + adv_task.stack = heap_caps_calloc_prefer(1, BLE_MESH_ADV_TASK_STACK_SIZE * sizeof(StackType_t), + 2, MALLOC_CAP_SPIRAM|MALLOC_CAP_8BIT, + MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + assert(adv_task.stack); + + adv_task.handle = xTaskCreateStaticPinnedToCore(adv_thread, BLE_MESH_ADV_TASK_NAME, + BLE_MESH_ADV_TASK_STACK_SIZE, NULL, + BLE_MESH_ADV_TASK_PRIO, adv_task.stack, + adv_task.task, BLE_MESH_ADV_TASK_CORE); + assert(adv_task.handle); #else /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */ int ret = xTaskCreatePinnedToCore(adv_thread, BLE_MESH_ADV_TASK_NAME, BLE_MESH_ADV_TASK_STACK_SIZE, NULL, BLE_MESH_ADV_TASK_PRIO, &adv_task.handle, BLE_MESH_ADV_TASK_CORE); - __ASSERT(ret == pdTRUE, "Failed to create adv thread"); - (void)ret; + assert(ret == pdTRUE); #endif /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */ } void bt_mesh_adv_common_init(void) { bt_mesh_r_mutex_create(&adv_buf_alloc_lock); - bt_mesh_adv_queue_init(&adv_queue, ble_mesh_adv_buf_count_get(), bt_mesh_task_post); + bt_mesh_adv_queue_init(&adv_queue, bt_mesh_adv_buf_count_get(), bt_mesh_task_post); bt_mesh_adv_type_init(BLE_MESH_ADV_PROV, &adv_queue, &adv_buf_pool, adv_alloc); bt_mesh_adv_type_init(BLE_MESH_ADV_DATA, &adv_queue, &adv_buf_pool, adv_alloc); bt_mesh_adv_type_init(BLE_MESH_ADV_BEACON, &adv_queue, &adv_buf_pool, adv_alloc); @@ -795,7 +795,7 @@ void bt_mesh_adv_common_init(void) #endif #if CONFIG_BLE_MESH_USE_BLE_50 - bt_mesh_adv_inst_init(BLE_MESH_ADV_INS, CONFIG_BLE_MESH_ADV_INST_ID); + bt_mesh_adv_inst_init(BLE_MESH_ADV_INST, CONFIG_BLE_MESH_ADV_INST_ID); #if CONFIG_BLE_MESH_EXT_ADV bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_PROV, &adv_queue, &ext_adv_buf_pool, ext_adv_alloc); bt_mesh_adv_type_init(BLE_MESH_ADV_EXT_DATA, &adv_queue, &ext_adv_buf_pool, ext_adv_alloc); @@ -818,24 +818,24 @@ void bt_mesh_adv_common_init(void) * it is not possible to use multiple advertising instances to process * data from the same message queue when sending mesh packets. * - * Therefore, shall to check whether there are - * duplicates in the queue buffer corresponding to each advertising instance. - */ - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_PROV); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_DATA); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_BEACON); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_URI); + * Therefore, shall to check whether there are duplicates in the queue + * buffer corresponding to each advertising instance. + */ + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_PROV); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_BEACON); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_URI); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_PROV); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_PROV); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_DATA); #if CONFIG_BLE_MESH_RELAY && !CONFIG_BLE_MESH_RELAY_ADV_BUF - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #endif #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_PROV); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_PROV); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_DATA); #if CONFIG_BLE_MESH_RELAY && !CONFIG_BLE_MESH_RELAY_ADV_BUF - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ @@ -886,7 +886,7 @@ void bt_mesh_adv_common_deinit(void) bt_mesh_adv_queue_deinit(&adv_queue); #if CONFIG_BLE_MESH_USE_BLE_50 - bt_mesh_adv_inst_deinit(BLE_MESH_ADV_INS); + bt_mesh_adv_inst_deinit(BLE_MESH_ADV_INST); #endif bt_mesh_unref_buf_from_pool(&adv_buf_pool); diff --git a/components/bt/esp_ble_mesh/core/adv_common.h b/components/bt/esp_ble_mesh/core/adv_common.h index 23372d404c..d5172a676a 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.h +++ b/components/bt/esp_ble_mesh/core/adv_common.h @@ -46,7 +46,7 @@ extern "C" { #define BLE_MESH_MSG_NET_BUF(msg) ((struct net_buf *)(msg->arg)) -#define BLE_MESH_ADV_INS_UNUSED 0xFF +#define BLE_MESH_ADV_INST_UNUSED 0xFF struct bt_mesh_adv { const struct bt_mesh_send_cb *cb; @@ -128,7 +128,7 @@ struct bt_mesh_adv_inst { bool busy; struct net_buf *sending_buf; - /* indicates that which adv_type is supported by this instance */ + /* Indicate which adv_type is supported by this instance */ uint32_t spt_mask; #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ }; @@ -212,10 +212,26 @@ static inline TickType_t K_WAIT(int32_t val) return (val == K_FOREVER) ? portMAX_DELAY : (val / portTICK_PERIOD_MS); } +static inline void adv_send_start(uint16_t duration, int err, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + if (cb && cb->start) { + cb->start(duration, err, cb_data); + } +} + +static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + if (cb && cb->end) { + cb->end(err, cb_data); + } +} + struct bt_mesh_adv_queue *bt_mesh_adv_queue_get(void); -struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, - int32_t timeout); +struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, int32_t timeout); static inline struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, int32_t timeout) { @@ -225,13 +241,20 @@ static inline struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, int void bt_mesh_adv_buf_ref_debug(const char *func, struct net_buf *buf, uint8_t ref_cmp, bt_mesh_buf_ref_flag_t flag); -struct bt_mesh_adv_type_manager *bt_mesh_adv_types_mgnt_get(enum bt_mesh_adv_type adv_type); +struct bt_mesh_adv_type_manager *bt_mesh_adv_types_mgmt_get(enum bt_mesh_adv_type adv_type); void bt_mesh_generic_adv_send(struct net_buf *buf, uint8_t xmit, const struct bt_mesh_send_cb *cb, void *cb_data, uint16_t src, uint16_t dst, bool front); +static inline void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + bt_mesh_generic_adv_send(buf, xmit, cb, cb_data, BLE_MESH_ADDR_UNASSIGNED, BLE_MESH_ADDR_UNASSIGNED, false); +} + void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool); void bt_mesh_unref_buf(bt_mesh_msg_t *msg); @@ -252,15 +275,16 @@ void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front); #if CONFIG_BLE_MESH_USE_BLE_50 struct bt_mesh_adv_inst * bt_mesh_get_adv_insts_set(void); +bool bt_mesh_is_adv_inst_used(uint8_t adv_inst_id); int bt_mesh_adv_inst_init(enum bt_mesh_adv_inst_type inst_type, uint8_t inst_id); int bt_mesh_adv_inst_deinit(enum bt_mesh_adv_inst_type inst_type); #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV -void bt_mesh_adv_inst_supported_adv_type_add(enum bt_mesh_adv_inst_type inst_type, +void bt_mesh_adv_inst_type_add(enum bt_mesh_adv_inst_type inst_type, enum bt_mesh_adv_type adv_type); -void bt_mesh_adv_inst_supported_adv_type_rm(enum bt_mesh_adv_inst_type inst_type, +void bt_mesh_adv_inst_type_rm(enum bt_mesh_adv_inst_type inst_type, enum bt_mesh_adv_type adv_type); void bt_mesh_adv_inst_supported_adv_type_clear(enum bt_mesh_adv_inst_type inst_type, @@ -270,7 +294,6 @@ void bt_mesh_adv_inst_supported_adv_type_clear(enum bt_mesh_adv_inst_type inst_t #if CONFIG_BLE_MESH_RELAY_ADV_BUF void bt_mesh_relay_adv_init(void); bool bt_mesh_ignore_relay_packet(uint32_t timestamp); -struct net_buf *bt_mesh_relay_adv_create(enum bt_mesh_adv_type type, int32_t timeout); static inline void bt_mesh_relay_adv_send(struct net_buf *buf, uint8_t xmit, uint16_t src, uint16_t dst, @@ -288,8 +311,6 @@ void bt_mesh_relay_adv_deinit(void); #endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_FRIEND -struct bt_mesh_adv *bt_mesh_frnd_adv_buf_get(int id, enum bt_mesh_adv_type type); -struct net_buf_pool *bt_mesh_frnd_adv_pool_get(void); void bt_mesh_frnd_adv_init(void); #if CONFIG_BLE_MESH_DEINIT void bt_mesh_frnd_adv_deinit(void); @@ -305,14 +326,19 @@ void bt_mesh_adv_common_deinit(void); #endif #if CONFIG_BLE_MESH_USE_BLE_50 -bool bt_mesh_is_adv_inst_used(uint8_t adv_inst_id); -bool ble_mesh_adv_task_wait(uint32_t wait_bits, TickType_t timeout, uint32_t *notify); -int ble_mesh_adv_task_wakeup(uint32_t evt); +int bt_mesh_adv_task_wakeup(uint32_t evt); +bool bt_mesh_adv_task_wait(uint32_t wait_bits, TickType_t timeout, uint32_t *notify); #else -bool ble_mesh_adv_task_wait(uint32_t timeout); +bool bt_mesh_adv_task_wait(uint32_t timeout); #endif #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV +static inline void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, + void *cb_data, bool front) +{ + bt_mesh_generic_adv_send(buf, 0, cb, cb_data, BLE_MESH_ADDR_UNASSIGNED, BLE_MESH_ADDR_UNASSIGNED, front); +} + int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, const struct bt_mesh_ble_adv_data *data, uint8_t *index); diff --git a/components/bt/esp_ble_mesh/core/ble_adv.c b/components/bt/esp_ble_mesh/core/ble_adv.c index 110e52e220..e27109c047 100644 --- a/components/bt/esp_ble_mesh/core/ble_adv.c +++ b/components/bt/esp_ble_mesh/core/ble_adv.c @@ -14,14 +14,14 @@ #include "mesh/common.h" #include "mesh/buf.h" -#if CONFIG_BLE_MESH_SUPPORT_BLE_ADV #if CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE /* Use independent ble adv queue only if multi adv instance is used */ static struct bt_mesh_adv_queue ble_adv_queue; static void bt_mesh_ble_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front); #endif + static struct bt_mesh_adv_queue *p_ble_adv_queue; -#define BLE_MESH_BLE_ADV_QUEUE_SIZE (CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT + 1) + /* length + advertising data + length + scan response data */ NET_BUF_POOL_DEFINE(ble_adv_buf_pool, CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT, ((BLE_MESH_ADV_DATA_SIZE + 3) << 1), BLE_MESH_ADV_USER_DATA_SIZE, NULL); @@ -64,17 +64,6 @@ static void bt_mesh_ble_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool fro } #endif -static struct net_buf *bt_mesh_ble_adv_create(enum bt_mesh_adv_type type, int32_t timeout) -{ - return bt_mesh_adv_create_from_pool(type, timeout); -} - -inline void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, - void *cb_data, bool front) -{ - bt_mesh_generic_adv_send(buf, 0, cb, cb_data, BLE_MESH_ADDR_UNASSIGNED, BLE_MESH_ADDR_UNASSIGNED, front); -} - static void ble_adv_tx_reset(struct bt_mesh_ble_adv_tx *tx, bool unref) { if (tx->buf == NULL) { @@ -211,7 +200,7 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, return -EINVAL; } - buf = bt_mesh_ble_adv_create(BLE_MESH_ADV_BLE, K_NO_WAIT); + buf = bt_mesh_adv_create(BLE_MESH_ADV_BLE, K_NO_WAIT); if (!buf) { BT_ERR("No empty ble adv buffer"); return -ENOBUFS; @@ -303,11 +292,11 @@ void bt_mesh_ble_adv_init(void) bt_mesh_adv_type_init(BLE_MESH_ADV_BLE, p_ble_adv_queue, &ble_adv_buf_pool, ble_adv_alloc); #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE - bt_mesh_adv_inst_init(BLE_MESH_BLE_ADV_INS, CONFIG_BLE_MESH_BLE_ADV_INST_ID); - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_BLE_ADV_INS, BLE_MESH_ADV_BLE); + bt_mesh_adv_inst_init(BLE_MESH_BLE_ADV_INST, CONFIG_BLE_MESH_BLE_ADV_INST_ID); + bt_mesh_adv_inst_type_add(BLE_MESH_BLE_ADV_INST, BLE_MESH_ADV_BLE); #else #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_add(BLE_MESH_ADV_INS, BLE_MESH_ADV_BLE); + bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_BLE); #endif #endif /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ @@ -317,8 +306,7 @@ void bt_mesh_ble_adv_init(void) void bt_mesh_ble_adv_deinit(void) { for (int i = 0; i < ARRAY_SIZE(ble_adv_tx); i++) { - struct bt_mesh_ble_adv_tx *tx = &ble_adv_tx[i]; - ble_adv_tx_reset(tx, false); + ble_adv_tx_reset(&ble_adv_tx[i], false); } bt_mesh_unref_buf_from_pool(&ble_adv_buf_pool); memset(ble_adv_pool, 0, sizeof(ble_adv_pool)); @@ -331,14 +319,13 @@ void bt_mesh_ble_adv_deinit(void) bt_mesh_adv_type_deinit(BLE_MESH_ADV_BLE); #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE - bt_mesh_adv_inst_deinit(BLE_MESH_BLE_ADV_INS); - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_BLE_ADV_INS, BLE_MESH_ADV_BLE); + bt_mesh_adv_inst_deinit(BLE_MESH_BLE_ADV_INST); + bt_mesh_adv_inst_type_rm(BLE_MESH_BLE_ADV_INST, BLE_MESH_ADV_BLE); #else #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_supported_adv_type_rm(BLE_MESH_ADV_INS, BLE_MESH_ADV_BLE); + bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_BLE); #endif #endif /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ } #endif /* CONFIG_BLE_MESH_DEINIT */ -#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ diff --git a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c index fd42502fda..0520ca7a11 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -396,11 +396,11 @@ void ble_mesh_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event, goto transfer_to_user; } #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(params->adv_term.adv_handle)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(params->adv_term.adv_handle)); #else /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ if (params->adv_term.status == 0x43 || /* Limit reached */ params->adv_term.status == 0x3C) { /* Advertising timeout */ - ble_mesh_adv_task_wakeup(ADV_TASK_MESH_ADV_INST_EVT); + bt_mesh_adv_task_wakeup(ADV_TASK_MESH_ADV_INST_EVT); } #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV /** @@ -423,7 +423,7 @@ void ble_mesh_5_gap_callback(tBTA_DM_BLE_5_GAP_EVENT event, * could lead to resource contention issues. */ bt_mesh_unset_ble_adv_running(); - ble_mesh_adv_task_wakeup(ADV_TASK_MESH_ADV_INST_EVT); + bt_mesh_adv_task_wakeup(ADV_TASK_MESH_ADV_INST_EVT); } #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -655,7 +655,7 @@ static void bt_mesh_scan_result_callback(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARC static struct { bool set; tBTA_DM_BLE_GAP_EXT_ADV_PARAMS param; -} last_param[BLE_MESH_ADV_INS_TYPES_NUM]; +} last_param[BLE_MESH_ADV_INST_TYPES_NUM]; int bt_le_ext_adv_start(const uint8_t inst_id, const struct bt_mesh_adv_param *param, diff --git a/components/bt/esp_ble_mesh/core/ext_adv.c b/components/bt/esp_ble_mesh/core/ext_adv.c index ebc2851777..4958e5686d 100644 --- a/components/bt/esp_ble_mesh/core/ext_adv.c +++ b/components/bt/esp_ble_mesh/core/ext_adv.c @@ -28,28 +28,9 @@ #include "adv_common.h" #include "ble_adv.h" -static struct bt_mesh_adv_queue *adv_queue; - static struct bt_mesh_adv_inst *adv_insts; -static inline void adv_send_start(uint16_t duration, int err, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->start) { - cb->start(duration, err, cb_data); - } -} - -static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->end) { - cb->end(err, cb_data); - } -} - -static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) +static int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) { struct net_buf *buf = inst->sending_buf; const struct bt_mesh_send_cb *cb = BLE_MESH_ADV(buf)->cb; @@ -205,40 +186,40 @@ static inline int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration return 0; } -static inline int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_msg_t *msg) +static int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_msg_t *msg) { while(uxQueueMessagesWaiting(msg_queue->handle)) { xQueueReceive(msg_queue->handle, msg, K_WAIT(K_FOREVER)); - /* In the previous adv task design, only - * the *buf of messages pushed to the queue - * by adv_update would be empty, but in the - * new design, there is a new processing method - * for adv_update's messages, - * so *buf here cannot be empty. */ + /* In the previous adv task design, only the *buf of messages pushed to the queue + * by adv_update would be empty, but in the new design, there is a new processing + * method for adv_update's messages, so *buf here cannot be empty. + */ assert(msg->arg); - /* If the message is canceled for advertising, - * then continue to retrieve the next message - * from that queue. */ + /* If the message is cancelled for advertising, then continue to retrieve the next + * message from that queue. + */ if (!bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(BLE_MESH_MSG_NET_BUF(msg)), 1, 0)) { bt_mesh_adv_buf_ref_debug(__func__, BLE_MESH_MSG_NET_BUF(msg), 1U, BLE_MESH_BUF_REF_EQUAL); /* Cancel the adv task's reference to this data packet. - * tips: The reference of buffer by adv_task occurs - * when the buffer is pushed into the queue. + * Tips: + * The reference of buffer by adv_task occurs when the buffer is pushed into + * the queue. */ net_buf_unref(BLE_MESH_MSG_NET_BUF(msg)); - /* Avoid reading the last message in the queue, which could lead - * to pointing to an invalid buffer due to the absence of other - * messages in the queue. */ + + /* Avoid reading the last message in the queue, which could lead to pointing + * to an invalid buffer due to the absence of other messages in the queue. + */ msg->arg = NULL; continue; } #if CONFIG_BLE_MESH_RELAY_ADV_BUF - /* If the relay message should be ignored, - * then continue to retrieve the next message - * from that queue. */ + /* If the relay message should be ignored, then continue to retrieve the next message + * from that queue. + */ if (msg->relay && bt_mesh_ignore_relay_packet(msg->timestamp)) { /* If the interval between "current time - msg.timestamp" is bigger than * BLE_MESH_RELAY_TIME_INTERVAL, this relay packet will not be sent. @@ -259,32 +240,32 @@ static inline int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_ return 0; } -static inline int active_idle_adv_instance(uint32_t *update_evts, uint16_t *min_duration) +static int activate_idle_adv_instance(uint32_t *update_evts, uint16_t *min_duration) { - uint32_t evts = 0; - uint16_t duration = K_FOREVER; uint16_t cur_min_duration = K_FOREVER; enum bt_mesh_adv_type adv_type = 0; - struct bt_mesh_adv_inst *instance = NULL; bt_mesh_queue_t *msg_queue = NULL; + uint16_t duration = K_FOREVER; bt_mesh_msg_t msg = {0}; uint32_t spt_mask = 0; + uint32_t evts = 0; #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER - if (!adv_insts[BLE_MESH_ADV_PROXY_INS].busy) { + if (!adv_insts[BLE_MESH_ADV_PROXY_INST].busy) { BT_DBG("Mesh Proxy Advertising start"); duration = bt_mesh_proxy_server_adv_start(); if (duration < cur_min_duration) { cur_min_duration = duration; } - adv_insts[BLE_MESH_ADV_PROXY_INS].busy = true; - evts |= ADV_TASK_ADV_INST_EVT(adv_insts[BLE_MESH_ADV_PROXY_INS].id); + adv_insts[BLE_MESH_ADV_PROXY_INST].busy = true; + evts |= ADV_TASK_ADV_INST_EVT(adv_insts[BLE_MESH_ADV_PROXY_INST].id); } #endif - for (int i = BLE_MESH_ADV_INS; i < BLE_MESH_ADV_INS_TYPES_NUM; i++) { - instance = &adv_insts[i]; + for (int i = BLE_MESH_ADV_INST; i < BLE_MESH_ADV_INST_TYPES_NUM; i++) { + struct bt_mesh_adv_inst *instance = &adv_insts[i]; + if (instance->busy #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER @@ -300,10 +281,9 @@ static inline int active_idle_adv_instance(uint32_t *update_evts, uint16_t *min_ while(spt_mask) { adv_type = find_lsb_set(spt_mask) - 1; spt_mask &= ~BIT(adv_type); - msg_queue = &(bt_mesh_adv_types_mgnt_get(adv_type)->adv_q->q); + msg_queue = &(bt_mesh_adv_types_mgmt_get(adv_type)->adv_q->q); - /* When there is no new message in the queue, *buf (aka: msg.arg) - * will be empty. */ + /* If no new message in the queue, the *buf (aka: msg.arg) will be empty */ if (find_valid_msg_from_queue(msg_queue, &msg)) { BT_DBG("no valid message for instance %d", instance->id); continue; @@ -312,15 +292,17 @@ static inline int active_idle_adv_instance(uint32_t *update_evts, uint16_t *min_ instance->sending_buf = (struct net_buf *)msg.arg; if (adv_send(instance, &duration)) { BT_ERR("adv start failed"); + /* When this adv instance fails to broadcast, it could be due to some + * persistent issues, such as incorrect adv parameter settings, or it + * could be due to some temporary issues, such as memory allocation + * failure. + * + * Therefore, it is advisable to skip subsequent queue reads for this + * instance and attempt to broadcast subsequent data again next time, + * rather than disabling the adv instance. + */ net_buf_unref(instance->sending_buf); instance->sending_buf = NULL; - /* When this adv instance fails to broadcast, it could be - * due to some persistent issues, such as incorrect adv - * parameter settings, or it could be due to some temporary - * issues, such as memory allocation failure. Therefore, it - * is advisable to skip subsequent queue reads for this instance - * and attempt to broadcast subsequent data again next time, - * rather than disabling the adv instance. */ break; } @@ -331,9 +313,9 @@ static inline int active_idle_adv_instance(uint32_t *update_evts, uint16_t *min_ instance->busy = true; evts |= ADV_TASK_ADV_INST_EVT(adv_insts[i].id); - /* Must be nullified to avoid affecting the next adv - * instance's judgment on whether the message queue - * is empty. */ + /* Must be nullified to avoid affecting the next adv instance's judgment + * on whether the message queue is empty. + */ msg.arg = NULL; break; } @@ -347,19 +329,18 @@ static inline int active_idle_adv_instance(uint32_t *update_evts, uint16_t *min_ static uint32_t received_adv_evts_handle(uint32_t recv_evts) { - uint32_t evt = 0; - if (!recv_evts) { return 0; } - for (int i = 0; recv_evts && i < BLE_MESH_ADV_INS_TYPES_NUM; i++) { - evt = ADV_TASK_ADV_INST_EVT(adv_insts[i].id); + for (int i = 0; recv_evts && i < BLE_MESH_ADV_INST_TYPES_NUM; i++) { + uint32_t evt = ADV_TASK_ADV_INST_EVT(adv_insts[i].id); + if (recv_evts & evt) { recv_evts &= ~evt; #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER - if (unlikely(i == BLE_MESH_ADV_PROXY_INS)) { + if (unlikely(i == BLE_MESH_ADV_PROXY_INST)) { BT_DBG("Mesh Proxy Advertising auto stop"); bt_mesh_proxy_server_adv_flag_set(false); } else @@ -390,24 +371,23 @@ static void adv_thread(void *p) adv_duration = K_FOREVER; wait_evts |= ADV_TASK_PKT_SEND_EVT; - active_idle_adv_instance(&wait_evts, &adv_duration); + activate_idle_adv_instance(&wait_evts, &adv_duration); - ble_mesh_adv_task_wait(wait_evts, adv_duration, &recv_evts); + bt_mesh_adv_task_wait(wait_evts, adv_duration, &recv_evts); wait_evts &= ~recv_evts; #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER if (recv_evts & ADV_TASK_PROXY_ADV_UPD_EVT) { - adv_insts[BLE_MESH_ADV_PROXY_INS].busy = false; + adv_insts[BLE_MESH_ADV_PROXY_INST].busy = false; recv_evts &= ~ADV_TASK_PROXY_ADV_UPD_EVT; } #endif - /** - * `recv_evts == ADV_TASK_PKT_SEND_EVT` indicates that new packets - * have been placed into the queue, and the advertising instances started - * previous have not yet stopped. + /* The `recv_evts == ADV_TASK_PKT_SEND_EVT` indicates that new packets + * have been put into the queue, and the advertising instances started + * previously have not yet been stopped. */ if (recv_evts == ADV_TASK_PKT_SEND_EVT) { continue; @@ -431,8 +411,8 @@ void bt_mesh_adv_update(void) CONFIG_BLE_MESH_GATT_PROXY_SERVER BT_DBG("Mesh Proxy Advertising stopped manually"); bt_mesh_proxy_server_adv_stop(); - if (adv_insts[BLE_MESH_ADV_PROXY_INS].busy) { - ble_mesh_adv_task_wakeup(ADV_TASK_PROXY_ADV_UPD_EVT); + if (adv_insts[BLE_MESH_ADV_PROXY_INST].busy) { + bt_mesh_adv_task_wakeup(ADV_TASK_PROXY_ADV_UPD_EVT); } #endif } @@ -442,7 +422,6 @@ void bt_mesh_adv_init(void) bt_mesh_adv_common_init(); adv_insts = bt_mesh_get_adv_insts_set(); - adv_queue = bt_mesh_adv_queue_get(); #if CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_relay_adv_init(); diff --git a/components/bt/esp_ble_mesh/core/ext_adv.h b/components/bt/esp_ble_mesh/core/ext_adv.h index 3004db27cd..3d4820a8d6 100644 --- a/components/bt/esp_ble_mesh/core/ext_adv.h +++ b/components/bt/esp_ble_mesh/core/ext_adv.h @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,13 +20,6 @@ extern "C" { #endif -static inline void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - bt_mesh_generic_adv_send(buf, xmit, cb, cb_data, BLE_MESH_ADDR_UNASSIGNED, BLE_MESH_ADDR_UNASSIGNED, false); -} - void bt_mesh_adv_update(void); void bt_mesh_adv_init(void); diff --git a/components/bt/esp_ble_mesh/core/friend.c b/components/bt/esp_ble_mesh/core/friend.c index 99e41cd099..eae9f9471d 100644 --- a/components/bt/esp_ble_mesh/core/friend.c +++ b/components/bt/esp_ble_mesh/core/friend.c @@ -346,7 +346,7 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd, { struct net_buf *buf = NULL; - buf = bt_mesh_adv_create_from_pool(BLE_MESH_ADV_FRIEND, K_NO_WAIT); + buf = bt_mesh_adv_create(BLE_MESH_ADV_FRIEND, K_NO_WAIT); if (!buf) { return NULL; } diff --git a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h index de8b01c95f..39c359d695 100644 --- a/components/bt/esp_ble_mesh/core/include/mesh/adapter.h +++ b/components/bt/esp_ble_mesh/core/include/mesh/adapter.h @@ -512,20 +512,20 @@ struct bt_mesh_adv_param { #define ADV_TASK_ADV_INST_EVT(inst_id) BIT(inst_id) enum bt_mesh_adv_inst_type { - BLE_MESH_ADV_INS, + BLE_MESH_ADV_INST, #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER - BLE_MESH_ADV_PROXY_INS, + BLE_MESH_ADV_PROXY_INST, #endif #if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE - BLE_MESH_RELAY_ADV_INS, + BLE_MESH_RELAY_ADV_INST, #endif #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE - BLE_MESH_BLE_ADV_INS, + BLE_MESH_BLE_ADV_INST, #endif #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ - BLE_MESH_ADV_INS_TYPES_NUM, + BLE_MESH_ADV_INST_TYPES_NUM, }; #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index c81b15d37d..3d14092704 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.c @@ -1679,7 +1679,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, if (rx->ctx.enh.long_pkt_cfg) { buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_LONG_RELAY_DATA, K_NO_WAIT); } else -#endif +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ { buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_DATA, K_NO_WAIT); } @@ -1690,11 +1690,11 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, EXT_ADV(buf)->tx_power = rx->ctx.enh.ext_adv_cfg.tx_power; } } else -#endif +#endif /* CONFIG_BLE_MESH_EXT_ADV */ { buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, K_NO_WAIT); } -#else +#else /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ /* Check if the number of relay packets in queue is too large, if so * use minimum relay retransmit value for later relay packets. */ @@ -1707,7 +1707,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, if (rx->ctx.enh.long_pkt_cfg) { buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_LONG_RELAY_DATA, K_NO_WAIT); } else -#endif +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ { buf = bt_mesh_adv_create(BLE_MESH_ADV_EXT_DATA, K_NO_WAIT); } @@ -1718,11 +1718,11 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, EXT_ADV(buf)->tx_power = rx->ctx.enh.ext_adv_cfg.tx_power; } } else -#endif +#endif /* CONFIG_BLE_MESH_EXT_ADV */ { - buf = bt_mesh_relay_adv_create(BLE_MESH_ADV_RELAY_DATA, K_NO_WAIT); + buf = bt_mesh_adv_create(BLE_MESH_ADV_RELAY_DATA, K_NO_WAIT); } -#endif +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ if (!buf) { BT_INFO("Out of relay buffers"); diff --git a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c index f5fd0279fc..d89c63b349 100644 --- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c @@ -997,12 +997,12 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) event->adv_complete.reason); #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); #else /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ assert(CONFIG_BLE_MESH_ADV_INST_ID == event->adv_complete.instance); /* Limit Reached (0x43) and Advertising Timeout (0x3C) will cause BLE_HS_ETIMEOUT to be set. */ if (event->adv_complete.reason == BLE_HS_ETIMEOUT) { - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); } #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV /** @@ -1020,12 +1020,12 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) */ if (bt_mesh_is_ble_adv_running() && event->adv_complete.reason == 0) { - /* The unset operation must be performed before waking up the - * adv task; performing the unset after waking up the adv task - * could lead to resource contention issues. - */ + /* The unset operation must be performed before waking up the + * adv task; performing the unset after waking up the adv task + * could lead to resource contention issues. + */ bt_mesh_unset_ble_adv_running(); - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); } #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -1124,12 +1124,12 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) BT_DBG("Provisioner advertise complete; reason=%d", event->adv_complete.reason); #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); #else /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ assert(CONFIG_BLE_MESH_ADV_INST_ID == event->adv_complete.instance); /* Limit Reached (0x43) and Advertising Timeout (0x3C) will cause BLE_HS_ETIMEOUT to be set. */ if (event->adv_complete.reason == BLE_HS_ETIMEOUT) { - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(CONFIG_BLE_MESH_ADV_INST_ID)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(CONFIG_BLE_MESH_ADV_INST_ID)); } #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV /** @@ -1152,7 +1152,7 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) * could lead to resource contention issues. */ bt_mesh_unset_ble_adv_running(); - ble_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(CONFIG_BLE_MESH_ADV_INST_ID)); + bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(CONFIG_BLE_MESH_ADV_INST_ID)); } #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -1167,7 +1167,7 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) static struct { bool set; struct ble_gap_ext_adv_params param; -} last_param[BLE_MESH_ADV_INS_TYPES_NUM]; +} last_param[BLE_MESH_ADV_INST_TYPES_NUM]; int bt_le_ext_adv_start(const uint8_t inst_id, const struct bt_mesh_adv_param *param, @@ -2516,8 +2516,7 @@ void bt_mesh_gatt_init(void) static bool init = false; if (init == false) { - - __ASSERT(g_gatts_svcs_add, "func bt_mesh_gatts_svcs_add should be called before mesh init"); + assert(g_gatts_svcs_add); ble_gatts_svc_set_visibility(prov_svc_start_handle, 1); ble_gatts_svc_set_visibility(proxy_svc_start_handle, 0); diff --git a/components/bt/esp_ble_mesh/core/proxy_server.c b/components/bt/esp_ble_mesh/core/proxy_server.c index 062bb9b247..c6cc15cab6 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.c +++ b/components/bt/esp_ble_mesh/core/proxy_server.c @@ -1598,8 +1598,13 @@ static int private_node_id_adv(struct bt_mesh_subnet *sub) memcpy(proxy_svc_data + 3, tmp + 8, 8); proxy_sd_len = gatt_proxy_adv_create(&proxy_sd); +#if CONFIG_BLE_MESH_USE_BLE_50 + err = bt_le_ext_adv_start(proxy_adv_inst, &fast_adv_param, private_node_id_ad, + ARRAY_SIZE(private_node_id_ad), &proxy_sd, proxy_sd_len); +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_start(&fast_adv_param, private_node_id_ad, ARRAY_SIZE(private_node_id_ad), &proxy_sd, proxy_sd_len); +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_WARN("Failed to advertise with Private Node ID (err %d)", err); return err; @@ -1642,8 +1647,13 @@ static int private_net_id_adv(struct bt_mesh_subnet *sub) proxy_sd_len = gatt_proxy_adv_create(&proxy_sd); +#if CONFIG_BLE_MESH_USE_BLE_50 + err = bt_le_ext_adv_start(proxy_adv_inst, &fast_adv_param, private_net_id_ad, + ARRAY_SIZE(private_net_id_ad), &proxy_sd, proxy_sd_len); +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_start(&fast_adv_param, private_net_id_ad, ARRAY_SIZE(private_net_id_ad), &proxy_sd, proxy_sd_len); +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_WARN("Failed to advertise with Private Net ID (err %d)", err); return err; diff --git a/components/bt/esp_ble_mesh/core/scan.c b/components/bt/esp_ble_mesh/core/scan.c index df6f22e117..c298f18456 100644 --- a/components/bt/esp_ble_mesh/core/scan.c +++ b/components/bt/esp_ble_mesh/core/scan.c @@ -43,18 +43,18 @@ static struct bt_mesh_scan_param scan_param = { #if CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN - .type = BLE_MESH_SCAN_ACTIVE, + .type = BLE_MESH_SCAN_ACTIVE, #else - .type = BLE_MESH_SCAN_PASSIVE, + .type = BLE_MESH_SCAN_PASSIVE, #endif #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN - .filter_dup = BLE_MESH_SCAN_FILTER_DUP_ENABLE, + .filter_dup = BLE_MESH_SCAN_FILTER_DUP_ENABLE, #else - .filter_dup = BLE_MESH_SCAN_FILTER_DUP_DISABLE, + .filter_dup = BLE_MESH_SCAN_FILTER_DUP_DISABLE, #endif - .interval = SCAN_INTERVAL, - .window = SCAN_WINDOW, - .scan_fil_policy = BLE_MESH_SP_ADV_ALL, + .interval = SCAN_INTERVAL, + .window = SCAN_WINDOW, + .scan_fil_policy = BLE_MESH_SP_ADV_ALL, }; #if (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) @@ -115,21 +115,21 @@ int bt_mesh_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], if (!memcmp(unprov_dev_info_fifo.info[idx].addr, addr, 6)) { if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_EXISTS) { return 0; - } else { - memcpy(uuid, unprov_dev_info_fifo.info[idx].uuid, 16); - *adv_type = unprov_dev_info_fifo.info[idx].adv_type; - break; } + + memcpy(uuid, unprov_dev_info_fifo.info[idx].uuid, 16); + *adv_type = unprov_dev_info_fifo.info[idx].adv_type; + break; } } else { if (!memcmp(unprov_dev_info_fifo.info[idx].uuid, uuid, 16)) { if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_EXISTS) { return 0; - } else { - memcpy(addr, unprov_dev_info_fifo.info[idx].addr, 6); - *adv_type = unprov_dev_info_fifo.info[idx].adv_type; - break; } + + memcpy(addr, unprov_dev_info_fifo.info[idx].addr, 6); + *adv_type = unprov_dev_info_fifo.info[idx].adv_type; + break; } } cnt++; @@ -458,12 +458,12 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) */ if (rpr_ext_scan_handle_adv_pkt(&adv_rpt->addr, adv_data, adv_len)) { return; - } else { -#if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN - callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif - net_buf_simple_restore(buf, &buf_state); } + +#if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN + callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); +#endif + net_buf_simple_restore(buf, &buf_state); } #endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ diff --git a/components/bt/esp_ble_mesh/core/transport.c b/components/bt/esp_ble_mesh/core/transport.c index 88a6158b89..797ff2a1ad 100644 --- a/components/bt/esp_ble_mesh/core/transport.c +++ b/components/bt/esp_ble_mesh/core/transport.c @@ -177,74 +177,6 @@ int32_t bt_mesh_get_seg_rtx_timeout(uint16_t dst, uint8_t ttl) return SEG_RETRANSMIT_TIMEOUT_UNICAST(&tx); } -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) -{ - if (bt_mesh_is_provisioned()) { -#if CONFIG_BLE_MESH_NODE - if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { - for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && - bt_mesh.app_keys[i].app_idx == app_idx) { - return &bt_mesh.app_keys[i]; - } - } - } else { - return bt_mesh_fast_prov_app_key_find(app_idx); - } -#endif - } else if (bt_mesh_is_provisioner_en()) { -#if CONFIG_BLE_MESH_PROVISIONER - for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { - if (bt_mesh.p_app_keys[i] && - bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && - bt_mesh.p_app_keys[i]->app_idx == app_idx) { - return bt_mesh.p_app_keys[i]; - } - } -#endif - } - - return NULL; -} - -int bt_mesh_upper_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, - const uint8_t **key, uint8_t *aid, uint16_t dst) -{ - struct bt_mesh_app_key *app_key = NULL; - - if (app_idx == BLE_MESH_KEY_DEV) { - *key = bt_mesh_dev_key_get(dst); - if (!*key) { - BT_ERR("DevKey of 0x%04x not found", dst); - return -EINVAL; - } - - *aid = 0U; - return 0; - } - - if (!subnet) { - BT_ERR("Invalid subnet"); - return -EINVAL; - } - - app_key = bt_mesh_app_key_get(app_idx); - if (!app_key) { - BT_ERR("AppKey 0x%04x not found", app_idx); - return -ENOENT; - } - - if (subnet->kr_phase == BLE_MESH_KR_PHASE_2 && app_key->updated) { - *key = app_key->keys[1].val; - *aid = app_key->keys[1].id; - } else { - *key = app_key->keys[0].val; - *aid = app_key->keys[0].id; - } - - return 0; -} - static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) @@ -442,7 +374,6 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err) static void schedule_retransmit(struct seg_tx *tx) { - bt_mesh_seg_tx_lock(tx); /* It's possible that a segment broadcast hasn't finished, * but the tx are already released. Only the seg_pending * of this segment remains unprocessed. So, here, we @@ -450,27 +381,29 @@ static void schedule_retransmit(struct seg_tx *tx) * destination (dst) is unassigned, and then process * the seg_pending of this segment. * See BLEMESH25-92 for details */ + + bt_mesh_seg_tx_lock(tx); + if (tx->dst == BLE_MESH_ADDR_UNASSIGNED) { if (tx->seg_pending) { tx->seg_pending--; } - bt_mesh_seg_tx_unlock(tx); - return; + goto end; } if (--tx->seg_pending) { - bt_mesh_seg_tx_unlock(tx); - return; + goto end; } if (!BLE_MESH_ADDR_IS_UNICAST(tx->dst) && !tx->attempts) { BT_INFO("Complete tx sdu to group"); seg_tx_complete(tx, 0); - bt_mesh_seg_tx_unlock(tx); - return; + goto end; } k_delayed_work_submit(&tx->rtx_timer, SEG_RETRANSMIT_TIMEOUT(tx)); + +end: bt_mesh_seg_tx_unlock(tx); } diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c index 318b21bb09..583f83e6a3 100644 --- a/components/bt/esp_ble_mesh/core/transport.enh.c +++ b/components/bt/esp_ble_mesh/core/transport.enh.c @@ -209,74 +209,6 @@ uint32_t bt_mesh_seg_ack_period(void) return (uint32_t)(val * bt_mesh_seg_rx_interval()); } -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) -{ - if (bt_mesh_is_provisioned()) { -#if CONFIG_BLE_MESH_NODE - if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { - for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { - if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && - bt_mesh.app_keys[i].app_idx == app_idx) { - return &bt_mesh.app_keys[i]; - } - } - } else { - return bt_mesh_fast_prov_app_key_find(app_idx); - } -#endif - } else if (bt_mesh_is_provisioner_en()) { -#if CONFIG_BLE_MESH_PROVISIONER - for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { - if (bt_mesh.p_app_keys[i] && - bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && - bt_mesh.p_app_keys[i]->app_idx == app_idx) { - return bt_mesh.p_app_keys[i]; - } - } -#endif - } - - return NULL; -} - -int bt_mesh_upper_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, - const uint8_t **key, uint8_t *aid, uint16_t dst) -{ - struct bt_mesh_app_key *app_key = NULL; - - if (app_idx == BLE_MESH_KEY_DEV) { - *key = bt_mesh_dev_key_get(dst); - if (!*key) { - BT_ERR("DevKey of 0x%04x not found", dst); - return -EINVAL; - } - - *aid = 0U; - return 0; - } - - if (!subnet) { - BT_ERR("Invalid subnet"); - return -EINVAL; - } - - app_key = bt_mesh_app_key_get(app_idx); - if (!app_key) { - BT_ERR("AppKey 0x%04x not found", app_idx); - return -ENOENT; - } - - if (subnet->kr_phase == BLE_MESH_KR_PHASE_2 && app_key->updated) { - *key = app_key->keys[1].val; - *aid = app_key->keys[1].id; - } else { - *key = app_key->keys[0].val; - *aid = app_key->keys[0].id; - } - - return 0; -} - static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, const uint8_t *ctl_op) diff --git a/components/bt/esp_ble_mesh/models/client/client_common.c b/components/bt/esp_ble_mesh/models/client/client_common.c index 5917b69cdf..8c8afdd563 100644 --- a/components/bt/esp_ble_mesh/models/client/client_common.c +++ b/components/bt/esp_ble_mesh/models/client/client_common.c @@ -20,7 +20,7 @@ #define HCI_TIME_FOR_START_ADV K_MSEC(5) /* Three adv related hci commands may take 4 ~ 5ms */ -static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, uint16_t tx_dst) +static bt_mesh_client_node_t *client_pick_node(sys_slist_t *list, uint16_t tx_dst) { bt_mesh_client_node_t *node = NULL; sys_snode_t *cur = NULL; @@ -86,7 +86,7 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * return NULL; } - if ((node = bt_mesh_client_pick_node(&data->queue, ctx->addr)) == NULL) { + if ((node = client_pick_node(&data->queue, ctx->addr)) == NULL) { BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); @@ -113,32 +113,8 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * return node; } -static bool bt_mesh_client_check_node_in_list(sys_slist_t *list, uint16_t tx_dst) -{ - bt_mesh_client_node_t *node = NULL; - sys_snode_t *cur = NULL; - - bt_mesh_list_lock(); - if (sys_slist_is_empty(list)) { - bt_mesh_list_unlock(); - return false; - } - - for (cur = sys_slist_peek_head(list); - cur != NULL; cur = sys_slist_peek_next(cur)) { - node = (bt_mesh_client_node_t *)cur; - if (node->ctx.addr == tx_dst) { - bt_mesh_list_unlock(); - return true; - } - } - - bt_mesh_list_unlock(); - return false; -} - -static uint32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_pair, - int size, uint32_t opcode) +static uint32_t client_get_status_op(const bt_mesh_client_op_pair_t *op_pair, + int size, uint32_t opcode) { if (!op_pair || size == 0) { return 0; @@ -155,7 +131,7 @@ static uint32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_ return 0; } -static int32_t bt_mesh_get_adv_duration(struct bt_mesh_msg_ctx *ctx) +static int32_t client_get_adv_duration(struct bt_mesh_msg_ctx *ctx) { uint16_t duration = 0, adv_int = 0; uint8_t xmit = 0; @@ -177,9 +153,9 @@ static int32_t bt_mesh_get_adv_duration(struct bt_mesh_msg_ctx *ctx) return (int32_t)duration; } -static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *msg, - uint32_t opcode, int32_t timeout) +static int32_t client_calc_timeout(struct bt_mesh_msg_ctx *ctx, + struct net_buf_simple *msg, + uint32_t opcode, int32_t timeout) { int32_t seg_rtx_to = 0, duration = 0, time = 0; uint8_t seg_count = 0, seg_rtx_num = 0; @@ -228,7 +204,7 @@ static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx, seg_count = (msg->len + mic_size - 1) / 12U + 1U; } - duration = bt_mesh_get_adv_duration(ctx); + duration = client_get_adv_duration(ctx); /* Currently only consider the time consumption of the same segmented * messages, but if there are other messages between any two retrans- @@ -334,7 +310,7 @@ int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, return -EINVAL; } - if (bt_mesh_client_check_node_in_list(&internal->queue, param->ctx.addr)) { + if (client_pick_node(&internal->queue, param->ctx.addr)) { BT_ERR("Busy sending message to DST 0x%04x", param->ctx.addr); return -EBUSY; } @@ -349,14 +325,15 @@ int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, memcpy(&node->ctx, ¶m->ctx, sizeof(struct bt_mesh_msg_ctx)); node->model = param->model; node->opcode = param->opcode; - node->op_pending = bt_mesh_client_get_status_op(client->op_pair, client->op_pair_size, param->opcode); + node->op_pending = client_get_status_op(client->op_pair, client->op_pair_size, param->opcode); if (node->op_pending == 0U) { BT_ERR("Status opcode not found in op_pair list, opcode 0x%08x", param->opcode); bt_mesh_free(node); return -EINVAL; } - node->timeout = bt_mesh_client_calc_timeout(¶m->ctx, msg, param->opcode, - param->msg_timeout ? param->msg_timeout : CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT); + node->timeout = client_calc_timeout(¶m->ctx, msg, param->opcode, + (param->msg_timeout ? param->msg_timeout : + CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT)); if (k_delayed_work_init(&node->timer, timer_handler)) { BT_ERR("Failed to create a timer"); From 92cc62a2b9006e827a4feec0cdd20061ca3a5616 Mon Sep 17 00:00:00 2001 From: Liu Linyan Date: Tue, 26 Aug 2025 18:18:42 +0800 Subject: [PATCH 142/156] feat(ble_mesh): Miscellaneous log enhancement for BLE Mesh --- components/bt/esp_ble_mesh/core/access.c | 234 +++++-- components/bt/esp_ble_mesh/core/adv.c | 54 +- components/bt/esp_ble_mesh/core/adv.h | 3 + components/bt/esp_ble_mesh/core/adv_common.c | 192 ++++-- components/bt/esp_ble_mesh/core/adv_common.h | 53 +- components/bt/esp_ble_mesh/core/beacon.c | 113 ++- components/bt/esp_ble_mesh/core/ble_adv.c | 56 +- .../core/bluedroid_host/adapter.c | 18 +- components/bt/esp_ble_mesh/core/cfg_cli.c | 292 ++++++-- components/bt/esp_ble_mesh/core/cfg_srv.c | 642 ++++++++++++------ components/bt/esp_ble_mesh/core/crypto.c | 53 +- components/bt/esp_ble_mesh/core/ext_adv.c | 101 ++- components/bt/esp_ble_mesh/core/ext_adv.h | 1 + components/bt/esp_ble_mesh/core/fast_prov.c | 36 + components/bt/esp_ble_mesh/core/foundation.h | 1 + components/bt/esp_ble_mesh/core/friend.c | 314 ++++++--- components/bt/esp_ble_mesh/core/health_cli.c | 50 +- components/bt/esp_ble_mesh/core/health_srv.c | 77 ++- components/bt/esp_ble_mesh/core/heartbeat.c | 44 +- components/bt/esp_ble_mesh/core/local.c | 97 +-- components/bt/esp_ble_mesh/core/lpn.c | 156 +++-- components/bt/esp_ble_mesh/core/main.c | 98 ++- components/bt/esp_ble_mesh/core/net.c | 374 ++++++---- components/bt/esp_ble_mesh/core/net.h | 28 +- .../esp_ble_mesh/core/nimble_host/adapter.c | 4 +- components/bt/esp_ble_mesh/core/prov_common.c | 6 + .../bt/esp_ble_mesh/core/proxy_client.c | 161 +++-- .../bt/esp_ble_mesh/core/proxy_server.c | 353 +++++++--- .../bt/esp_ble_mesh/core/proxy_server.h | 2 +- components/bt/esp_ble_mesh/core/rpl.c | 29 +- components/bt/esp_ble_mesh/core/scan.c | 218 ++++-- .../bt/esp_ble_mesh/core/storage/settings.c | 330 +++++++-- .../esp_ble_mesh/core/storage/settings_nvs.c | 123 +++- .../esp_ble_mesh/core/storage/settings_uid.c | 72 +- components/bt/esp_ble_mesh/core/test.c | 10 +- components/bt/esp_ble_mesh/core/transport.c | 313 ++++++--- .../bt/esp_ble_mesh/core/transport.enh.c | 433 +++++++++--- .../models/client/client_common.c | 70 +- 38 files changed, 3815 insertions(+), 1396 deletions(-) diff --git a/components/bt/esp_ble_mesh/core/access.c b/components/bt/esp_ble_mesh/core/access.c index 44b7009d8e..0804bca4ed 100644 --- a/components/bt/esp_ble_mesh/core/access.c +++ b/components/bt/esp_ble_mesh/core/access.c @@ -25,7 +25,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #define BLE_MESH_SDU_MAX_LEN 384 @@ -50,6 +50,8 @@ void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, { int i, j; + BT_DBG("ModelForeach"); + if (comp_0 == NULL) { BT_ERR("Invalid device composition"); return; @@ -58,15 +60,21 @@ void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, for (i = 0; i < comp_0->elem_count; i++) { struct bt_mesh_elem *elem = &comp_0->elem[i]; + BT_DBG("Element %u", i); + for (j = 0; j < elem->model_count; j++) { struct bt_mesh_model *model = &elem->models[j]; + BT_DBG("ID 0x%04x", model->id); + func(model, elem, false, i == 0, user_data); } for (j = 0; j < elem->vnd_model_count; j++) { struct bt_mesh_model *model = &elem->vnd_models[j]; + BT_DBG("ID 0x%04x CID 0x%04x", model->vnd.id, model->vnd.company); + func(model, elem, true, i == 0, user_data); } } @@ -76,6 +84,8 @@ int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) { int period = 0; + BT_DBG("ModelPubPeriodGet"); + if (!mod->pub) { BT_ERR("Model has no publication support"); return 0; @@ -103,6 +113,9 @@ int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod) return 0; } + BT_DBG("Period %ld FastPeriod %u PeriodDiv %u", + period, mod->pub->fast_period, mod->pub->period_div); + if (mod->pub->fast_period) { return period >> mod->pub->period_div; } @@ -115,6 +128,8 @@ static int32_t next_period(struct bt_mesh_model *mod) struct bt_mesh_model_pub *pub = mod->pub; uint32_t elapsed = 0U, period = 0U; + BT_DBG("NextPeriod"); + if (!pub) { BT_ERR("Model has no publication support"); return 0; @@ -122,12 +137,13 @@ static int32_t next_period(struct bt_mesh_model *mod) period = bt_mesh_model_pub_period_get(mod); if (!period) { + BT_DBG("PeriodZero"); return 0; } elapsed = k_uptime_get_32() - pub->period_start; - BT_INFO("Publishing took %ums", elapsed); + BT_INFO("Elapsed %u Period %u", elapsed, period); if (elapsed >= period) { BT_WARN("Publication sending took longer than the period"); @@ -143,7 +159,7 @@ static void publish_sent(int err, void *user_data) struct bt_mesh_model *mod = user_data; int32_t delay = 0; - BT_DBG("err %d", err); + BT_DBG("PublishSent, Err %d", err); if (!mod->pub) { BT_ERR("Model has no publication support"); @@ -156,8 +172,9 @@ static void publish_sent(int err, void *user_data) delay = next_period(mod); } + BT_DBG("PubCount %u PubDelay %ld", mod->pub->count, delay); + if (delay) { - BT_INFO("Publishing next time in %dms", delay); k_delayed_work_submit(&mod->pub->timer, delay); } } @@ -167,6 +184,8 @@ static void publish_start(uint16_t duration, int err, void *user_data) struct bt_mesh_model *mod = user_data; struct bt_mesh_model_pub *pub = mod->pub; + BT_DBG("PublishStart, Err %d", err); + if (err) { BT_ERR("Failed to publish: err %d", err); return; @@ -196,6 +215,8 @@ static int publish_retransmit(struct bt_mesh_model *mod) }; int err = 0; + BT_DBG("PublishRetransmit"); + if (!pub || !pub->msg) { BT_ERR("Model has no publication support"); return -ENOTSUP; @@ -224,9 +245,14 @@ static int publish_retransmit(struct bt_mesh_model *mod) ctx.send_tag |= BLE_MESH_TAG_SEND_SEGMENTED; } + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Dst 0x%04x", + ctx.net_idx, ctx.app_idx, ctx.addr); + BT_DBG("TTL %u SendCred %u SendRel %u PubCount %u", + ctx.send_ttl, ctx.send_cred, pub->send_rel, pub->count); + #if CONFIG_BLE_MESH_DF_SRV bt_mesh_model_pub_use_directed(&tx, pub->directed_pub_policy); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ sdu = bt_mesh_alloc_buf(pub->msg->len + BLE_MESH_MIC_LONG); if (!sdu) { @@ -246,8 +272,11 @@ static int publish_retransmit(struct bt_mesh_model *mod) static void publish_retransmit_end(int err, struct bt_mesh_model_pub *pub) { + BT_DBG("PublishRetransmitEnd, Err %d", err); + /* Cancel all retransmits for this publish attempt */ pub->count = 0U; + /* Make sure the publish timer gets reset */ publish_sent(err, pub->mod); } @@ -261,7 +290,8 @@ static void mod_publish(struct k_work *work) int err = 0; period_ms = bt_mesh_model_pub_period_get(pub->mod); - BT_INFO("Publish period %u ms", period_ms); + + BT_INFO("ModPublish, Period %u", period_ms); if (pub->count) { err = publish_retransmit(pub->mod); @@ -289,6 +319,7 @@ static void mod_publish(struct k_work *work) if (pub->update && pub->update(pub->mod)) { /* Cancel this publish attempt. */ BT_ERR("Update failed, skipping publish (err %d)", err); + pub->period_start = k_uptime_get_32(); publish_retransmit_end(err, pub); return; @@ -302,6 +333,8 @@ static void mod_publish(struct k_work *work) struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod) { + BT_DBG("ModelElem, ElemIdx %u", mod->elem_idx); + return &comp_0->elem[mod->elem_idx]; } @@ -309,6 +342,8 @@ struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_ { struct bt_mesh_elem *elem = NULL; + BT_DBG("ModelGet, ElemIdx %u ModIdx %u Vnd %u", elem_idx, mod_idx, vnd); + if (!comp_0) { BT_ERR("comp_0 not initialized"); return NULL; @@ -344,6 +379,8 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, int *err = user_data; int i; + BT_DBG("ModInit, Vnd %u Primary %u", vnd, primary); + if (!user_data) { BT_ERR("Invalid model init user data"); return; @@ -373,6 +410,8 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, mod->model_idx = mod - elem->models; } + BT_DBG("ElemIdx %u ModelIdx %u", mod->elem_idx, mod->model_idx); + if (vnd) { return; } @@ -386,6 +425,8 @@ int bt_mesh_comp_register(const struct bt_mesh_comp *comp) { int err = 0; + BT_DBG("CompRegister, ElemCount %u", comp->elem_count); + /* There must be at least one element */ if (!comp->elem_count) { return -EINVAL; @@ -405,6 +446,8 @@ static void mod_deinit(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, int *err = user_data; int i; + BT_DBG("ModDeinit, Vnd %u Primary %u", vnd, primary); + if (!user_data) { BT_ERR("Invalid model deinit user data"); return; @@ -443,6 +486,8 @@ int bt_mesh_comp_deregister(void) { int err = 0; + BT_DBG("CompDeregister"); + if (comp_0 == NULL) { return -EINVAL; } @@ -461,25 +506,29 @@ void bt_mesh_comp_provision(uint16_t addr) dev_primary_addr = addr; - BT_INFO("Primary address 0x%04x, element count %u", addr, comp_0->elem_count); + BT_INFO("CompProvision, PrimaryAddr 0x%04x ElemCount %u", addr, comp_0->elem_count); for (i = 0; i < comp_0->elem_count; i++) { struct bt_mesh_elem *elem = &comp_0->elem[i]; elem->addr = addr++; - BT_DBG("addr 0x%04x mod_count %u vnd_mod_count %u", + BT_DBG("ElemAddr 0x%04x ModCount %u VndModCount %u", elem->addr, elem->model_count, elem->vnd_model_count); } } void bt_mesh_comp_unprovision(void) { + BT_DBG("CompUnprovision"); + dev_primary_addr = BLE_MESH_ADDR_UNASSIGNED; } uint16_t bt_mesh_primary_addr(void) { + BT_DBG("PrimaryAddr 0x%04x", dev_primary_addr); + return dev_primary_addr; } @@ -487,12 +536,16 @@ uint16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, uint16_t addr) { int i; + BT_DBG("ModelFindGroup, Addr 0x%04x", addr); + for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { if (mod->groups[i] == addr) { + BT_DBG("ModGroupFound"); return &mod->groups[i]; } } + BT_DBG("ModGroupNotFound"); return NULL; } @@ -503,6 +556,8 @@ static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem, uint16_t *match = NULL; int i; + BT_DBG("ElemFindGroup, Addr 0x%04x", group_addr); + for (i = 0; i < elem->model_count; i++) { model = &elem->models[i]; @@ -528,6 +583,8 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) { uint16_t index = 0U; + BT_DBG("ElemFind, Addr 0x%04x", addr); + if (BLE_MESH_ADDR_IS_UNICAST(addr)) { index = (addr - comp_0->elem[0].addr); if (index < comp_0->elem_count) { @@ -550,6 +607,8 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) uint8_t bt_mesh_elem_count(void) { + BT_DBG("ElemCount %u", comp_0->elem_count); + return comp_0->elem_count; } @@ -557,6 +616,8 @@ static bool model_has_key(struct bt_mesh_model *mod, uint16_t key) { int i; + BT_DBG("ModelHasKey, AppIdx 0x%04x", key); + for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { if (mod->keys[i] == key) { return true; @@ -570,6 +631,8 @@ static bool model_has_dst(struct bt_mesh_model *model, struct bt_mesh_subnet *sub, uint16_t dst) { + BT_DBG("ModelHasDst, Dst 0x%04x", dst); + if (BLE_MESH_ADDR_IS_UNICAST(dst)) { return (comp_0->elem[model->elem_idx].addr == dst); } @@ -588,6 +651,8 @@ static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, { int i; + BT_DBG("FindOp, ModelCount %u Opcode 0x%08lx", model_count, opcode); + for (i = 0; i < model_count; i++) { const struct bt_mesh_model_op *op; @@ -606,6 +671,8 @@ static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_buf) { + BT_DBG("GetOpCode, PullBuf %u", pull_buf); + switch (buf->data[0] >> 6) { case 0x00: case 0x01: @@ -651,6 +718,8 @@ static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_bu int bt_mesh_get_opcode(struct net_buf_simple *buf, uint32_t *opcode, bool pull_buf) { + BT_DBG("GetOpCode"); + if (buf == NULL || buf->len == 0 || opcode == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -661,6 +730,8 @@ int bt_mesh_get_opcode(struct net_buf_simple *buf, bool bt_mesh_fixed_group_match(uint16_t addr) { + BT_DBG("FixedGroupMatch, Addr 0x%04x", addr); + /* Check for fixed group addresses */ switch (addr) { case BLE_MESH_ADDR_ALL_NODES: @@ -682,12 +753,14 @@ bool bt_mesh_fixed_direct_match(struct bt_mesh_subnet *sub, uint16_t addr) * shall be processed by the primary element of all nodes that * have directed forwarding functionality enabled. */ + BT_DBG("FixedDirectMatch, Addr 0x%04x", addr); + #if CONFIG_BLE_MESH_DF_SRV if (addr == BLE_MESH_ADDR_DIRECTS && sub && sub->directed_forwarding == BLE_MESH_DIRECTED_FORWARDING_ENABLED) { return true; } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ return false; } @@ -700,16 +773,17 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) uint8_t count = 0U; int i; - BT_INFO("recv, app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx, - rx->ctx.addr, rx->ctx.recv_dst); - BT_INFO("recv, len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_INFO("ModelRecv"); + BT_INFO("AppIdx 0x%04x Src 0x%04x Dst 0x%04x", + rx->ctx.app_idx, rx->ctx.addr, rx->ctx.recv_dst); + BT_INFO("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (get_opcode(buf, &opcode, true) < 0) { BT_WARN("Unable to decode OpCode"); return; } - BT_DBG("OpCode 0x%08x", opcode); + BT_DBG("OpCode 0x%08lx RecvCred %u", opcode, rx->ctx.recv_cred); for (i = 0; i < comp_0->elem_count; i++) { struct bt_mesh_elem *elem = &comp_0->elem[i]; @@ -734,10 +808,12 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } if (!model_has_key(model, rx->ctx.app_idx)) { + BT_DBG("ModelNotHasKey"); continue; } if (!model_has_dst(model, rx->sub, rx->ctx.recv_dst)) { + BT_DBG("ModelNotHasDst"); continue; } @@ -781,6 +857,8 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) { + BT_DBG("ModelMsgInit, OpCode 0x%08lx", opcode); + net_buf_simple_init(msg, 0); switch (BLE_MESH_MODEL_OP_LEN(opcode)) { @@ -806,6 +884,8 @@ void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) static bool ready_to_send(uint16_t dst) { + BT_DBG("IsReadyToSend, Dst 0x%04x", dst); + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { return true; } @@ -813,7 +893,7 @@ static bool ready_to_send(uint16_t dst) if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { if (bt_mesh_provisioner_check_msg_dst(dst) == false && bt_mesh_elem_find(dst) == false) { - BT_ERR("Failed to find DST 0x%04x", dst); + BT_ERR("Failed to find Dst 0x%04x", dst); return false; } return true; @@ -825,15 +905,19 @@ static bool ready_to_send(uint16_t dst) #if !CONFIG_BLE_MESH_V11_SUPPORT static bool use_friend_cred(uint16_t net_idx, uint16_t dst) { + BT_DBG("IsFrndCredUsed, NetIdx 0x%04x Dst 0x%04x", net_idx, dst); + /* Currently LPN only supports using NetKey in bt_mesh.sub[0] */ if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && net_idx == 0 && bt_mesh_lpn_match(dst)) { + BT_DBG("LPNMatch"); return true; } if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && bt_mesh_friend_match(net_idx, dst)) { + BT_DBG("FrndMatch"); return true; } @@ -848,6 +932,9 @@ bool bt_mesh_valid_security_cred(struct bt_mesh_net_tx *tx) * If not, later a better security credentials could be * chosen for the message. */ + BT_DBG("IsValidSecCred, NetIdx 0x%04x Tag 0x%02x Cred %u", + tx->ctx->net_idx, tx->ctx->send_tag, tx->ctx->send_cred); + if (!bt_mesh_tag_immutable_cred(tx->ctx->send_tag)) { return true; } @@ -876,22 +963,27 @@ void bt_mesh_choose_better_security_cred(struct bt_mesh_net_tx *tx) net_idx = tx->ctx->net_idx; addr = tx->ctx->addr; + BT_DBG("ChooseBetterSecCred"); + BT_DBG("NetIdx 0x%04x Dst 0x%04x Tag 0x%02x Cred %u", + net_idx, addr, send_tag, send_cred); + /* If the message is tagged with immutable-credentials, * then the security credentials shall not be changed. */ if (bt_mesh_tag_immutable_cred(send_tag)) { + BT_DBG("ImmutableCred"); return; } if (send_cred > BLE_MESH_FRIENDSHIP_CRED) { - BT_INFO("Use managed flooding security credentials"); + BT_INFO("UseFloodingSecCred"); tx->ctx->send_cred = BLE_MESH_FLOODING_CRED; return; } if (send_cred == BLE_MESH_FRIENDSHIP_CRED) { if (!use_friend_cred(net_idx, addr)) { - BT_INFO("Use managed flooding security credentials"); + BT_INFO("UseFloodingSecCred"); tx->ctx->send_cred = BLE_MESH_FLOODING_CRED; tx->ctx->send_tag = send_tag | BLE_MESH_TAG_IMMUTABLE_CRED; } else { @@ -916,14 +1008,13 @@ void bt_mesh_choose_better_security_cred(struct bt_mesh_net_tx *tx) if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && BLE_MESH_ADDR_IS_UNICAST(addr) && bt_mesh_friend_match(net_idx, addr)) { - BT_INFO("Use friendship security credentials"); + BT_INFO("UseFrndSecCred"); tx->ctx->send_cred = BLE_MESH_FRIENDSHIP_CRED; tx->ctx->send_tag = send_tag | BLE_MESH_TAG_IMMUTABLE_CRED; return; } - /** - * Spec 3.7.3.1 + /* Spec 3.7.3.1 * The Low power node in friendship should use friendship security * material. * @@ -943,11 +1034,12 @@ void bt_mesh_choose_better_security_cred(struct bt_mesh_net_tx *tx) if (BLE_MESH_ADDR_IS_UNICAST(addr) && bt_mesh.lpn.frnd == addr && !bt_mesh_tag_immutable_cred(send_tag)) { + BT_INFO("UseFrndSecCred"); tx->ctx->send_cred = BLE_MESH_FRIENDSHIP_CRED; tx->ctx->send_tag = send_tag | BLE_MESH_TAG_IMMUTABLE_CRED; return; } -#endif +#endif /* CONFIG_BLE_MESH_LOW_POWER */ } #endif /* !CONFIG_BLE_MESH_V11_SUPPORT */ @@ -958,9 +1050,10 @@ static int model_send(struct bt_mesh_model *model, { int err = 0; - BT_INFO("send, app_idx 0x%04x src 0x%04x dst 0x%04x", - tx->ctx->app_idx, tx->src, tx->ctx->addr); - BT_INFO("send, len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + BT_INFO("ModelSend"); + BT_INFO("AppIdx 0x%04x Src 0x%04x Dst 0x%04x TTL %u", + tx->ctx->app_idx, tx->src, tx->ctx->addr, tx->ctx->send_ttl); + BT_INFO("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); if (ready_to_send(tx->ctx->addr) == false) { BT_ERR("Not ready to send"); @@ -1013,7 +1106,7 @@ static int model_send(struct bt_mesh_model *model, #if CONFIG_BLE_MESH_DF_SRV bt_mesh_is_directed_path_needed(tx); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ return err; } @@ -1025,9 +1118,11 @@ int bt_mesh_model_send_implicit(struct bt_mesh_model *model, { struct bt_mesh_subnet *sub = NULL; + BT_DBG("ModelSendImplicit"); + sub = bt_mesh_subnet_get(ctx->net_idx); if (!sub) { - BT_ERR("Send, NetKey 0x%04x not found", ctx->net_idx); + BT_ERR("NetIdx 0x%04x not found", ctx->net_idx); return -EADDRNOTAVAIL; } @@ -1048,9 +1143,11 @@ int bt_mesh_model_send(struct bt_mesh_model *model, { struct bt_mesh_subnet *sub = NULL; + BT_DBG("ModelSend, NetIdx 0x%04x", ctx->net_idx); + sub = bt_mesh_subnet_get(ctx->net_idx); if (!sub) { - BT_ERR("Send, NetKey 0x%04x not found", ctx->net_idx); + BT_ERR("NetIdx 0x%04x not found", ctx->net_idx); return -EADDRNOTAVAIL; } @@ -1077,6 +1174,8 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) }; int err = 0; + BT_DBG("ModelPublish"); + if (!pub || !pub->msg) { BT_ERR("Model has no publication support"); return -ENOTSUP; @@ -1125,12 +1224,12 @@ int bt_mesh_model_publish(struct bt_mesh_model *model) #if CONFIG_BLE_MESH_DF_SRV bt_mesh_model_pub_use_directed(&tx, pub->directed_pub_policy); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ pub->count = BLE_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); - BT_INFO("Publish Retransmit Count %u Interval %ums", pub->count, - BLE_MESH_PUB_TRANSMIT_INT(pub->retransmit)); + BT_INFO("PubCount %u PubInterval %u", + pub->count, BLE_MESH_PUB_TRANSMIT_INT(pub->retransmit)); sdu = bt_mesh_alloc_buf(pub->msg->len + BLE_MESH_MIC_LONG); if (!sdu) { @@ -1154,6 +1253,8 @@ struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem, { int i; + BT_DBG("ModelFindVnd, ID 0x%04x CID 0x%04x", id, company); + for (i = 0; i < elem->vnd_model_count; i++) { if (elem->vnd_models[i].vnd.company == company && elem->vnd_models[i].vnd.id == id) { @@ -1168,6 +1269,8 @@ struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem, uint16_t id) { int i; + BT_DBG("ModelFind, ID 0x%04x", id); + for (i = 0; i < elem->model_count; i++) { if (elem->models[i].id == id) { return &elem->models[i]; @@ -1179,6 +1282,8 @@ struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem, uint16_t id) const struct bt_mesh_comp *bt_mesh_comp_get(void) { + BT_DBG("CompGet %p", comp_0); + return comp_0; } @@ -1196,6 +1301,8 @@ const uint8_t *bt_mesh_dev_key_get(uint16_t dst) key = bt_mesh_provisioner_dev_key_get(dst); } + BT_DBG("Dst 0x%04x DevKey %s", dst, key ? bt_hex(key, 16) : ""); + return key; } @@ -1207,20 +1314,22 @@ size_t bt_mesh_rx_netkey_size(void) if (bt_mesh_is_provisioned()) { size = ARRAY_SIZE(bt_mesh.sub); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { size = ARRAY_SIZE(bt_mesh.p_sub); } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER size = ARRAY_SIZE(bt_mesh.sub); if (bt_mesh_is_provisioner_en()) { size += ARRAY_SIZE(bt_mesh.p_sub); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxNetKeySize %u", size); return size; } @@ -1233,13 +1342,13 @@ struct bt_mesh_subnet *bt_mesh_rx_netkey_get(size_t index) if (bt_mesh_is_provisioned()) { sub = &bt_mesh.sub[index]; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { sub = bt_mesh.p_sub[index]; } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (index < ARRAY_SIZE(bt_mesh.sub)) { @@ -1247,7 +1356,10 @@ struct bt_mesh_subnet *bt_mesh_rx_netkey_get(size_t index) } else { sub = bt_mesh.p_sub[index - ARRAY_SIZE(bt_mesh.sub)]; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxNetKeyGet, Index %u NetIdx 0x%04x", + index, sub ? sub->net_idx : BLE_MESH_KEY_ANY); return sub; } @@ -1271,7 +1383,7 @@ size_t bt_mesh_rx_devkey_size(void) if (bt_mesh_is_provisioner_en()) { size = 1; } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER size = 1; @@ -1283,7 +1395,9 @@ size_t bt_mesh_rx_devkey_size(void) if (bt_mesh_is_provisioner_en()) { size += 1; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxDevKeySize %u", size); return size; } @@ -1300,13 +1414,13 @@ const uint8_t *bt_mesh_rx_devkey_get(size_t index, uint16_t src) key = bt_mesh.dev_key_ca; } } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { key = bt_mesh_provisioner_dev_key_get(src); } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (index == 0) { @@ -1324,11 +1438,13 @@ const uint8_t *bt_mesh_rx_devkey_get(size_t index, uint16_t src) */ key = bt_mesh.dev_key_ca; } else -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ { key = bt_mesh_provisioner_dev_key_get(src); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxDevKeyGet, Index %u Src 0x%04x", index, src); return key; } @@ -1341,20 +1457,22 @@ size_t bt_mesh_rx_appkey_size(void) if (bt_mesh_is_provisioned()) { size = ARRAY_SIZE(bt_mesh.app_keys); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { size = ARRAY_SIZE(bt_mesh.p_app_keys); } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER size = ARRAY_SIZE(bt_mesh.app_keys); if (bt_mesh_is_provisioner_en()) { size += ARRAY_SIZE(bt_mesh.p_app_keys); } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxAppKeySize %u", size); return size; } @@ -1367,13 +1485,13 @@ struct bt_mesh_app_key *bt_mesh_rx_appkey_get(size_t index) if (bt_mesh_is_provisioned()) { key = &bt_mesh.app_keys[index]; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && !CONFIG_BLE_MESH_PROVISIONER */ #if !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (bt_mesh_is_provisioner_en()) { key = bt_mesh.p_app_keys[index]; } -#endif +#endif /* !CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ #if CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER if (index < ARRAY_SIZE(bt_mesh.app_keys)) { @@ -1381,36 +1499,44 @@ struct bt_mesh_app_key *bt_mesh_rx_appkey_get(size_t index) } else { key = bt_mesh.p_app_keys[index - ARRAY_SIZE(bt_mesh.app_keys)]; } -#endif +#endif /* CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PROVISIONER */ + + BT_DBG("RxAppKeyGet, Index %u AppIdx 0x%04x", + index, key ? key->app_idx : BLE_MESH_KEY_ANY); return key; } struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) { + BT_DBG("AppKeyGet, AppIdx 0x%04x", app_idx); + if (bt_mesh_is_provisioned()) { #if CONFIG_BLE_MESH_NODE if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { for (int i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && bt_mesh.app_keys[i].app_idx == app_idx) { + BT_DBG("NodeAppKey"); return &bt_mesh.app_keys[i]; } } } else { + BT_DBG("FastProvAppKey"); return bt_mesh_fast_prov_app_key_find(app_idx); } -#endif +#endif /* CONFIG_BLE_MESH_NODE */ } else if (bt_mesh_is_provisioner_en()) { #if CONFIG_BLE_MESH_PROVISIONER for (int i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { if (bt_mesh.p_app_keys[i] && bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && bt_mesh.p_app_keys[i]->app_idx == app_idx) { + BT_DBG("PvnrAppKey"); return bt_mesh.p_app_keys[i]; } } -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ } return NULL; @@ -1421,10 +1547,12 @@ int bt_mesh_upper_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, { struct bt_mesh_app_key *app_key = NULL; + BT_DBG("UpperKeyGet, AppIdx 0x%04x Dst 0x%04x", app_idx, dst); + if (app_idx == BLE_MESH_KEY_DEV) { *key = bt_mesh_dev_key_get(dst); if (!*key) { - BT_ERR("DevKey of 0x%04x not found", dst); + BT_ERR("DevKeyNotFound 0x%04x", dst); return -EINVAL; } @@ -1433,20 +1561,22 @@ int bt_mesh_upper_key_get(const struct bt_mesh_subnet *subnet, uint16_t app_idx, } if (!subnet) { - BT_ERR("Invalid subnet"); + BT_ERR("InvalidSubnet"); return -EINVAL; } app_key = bt_mesh_app_key_get(app_idx); if (!app_key) { - BT_ERR("AppKey 0x%04x not found", app_idx); + BT_ERR("AppKeyNotFound 0x%04x", app_idx); return -ENOENT; } if (subnet->kr_phase == BLE_MESH_KR_PHASE_2 && app_key->updated) { + BT_DBG("NewAppKey"); *key = app_key->keys[1].val; *aid = app_key->keys[1].id; } else { + BT_DBG("OldAppKey"); *key = app_key->keys[0].val; *aid = app_key->keys[0].id; } diff --git a/components/bt/esp_ble_mesh/core/adv.c b/components/bt/esp_ble_mesh/core/adv.c index d9096caa13..bb7b9771ca 100644 --- a/components/bt/esp_ble_mesh/core/adv.c +++ b/components/bt/esp_ble_mesh/core/adv.c @@ -29,12 +29,10 @@ static struct bt_mesh_adv_queue *adv_queue; #if CONFIG_BLE_MESH_RELAY_ADV_BUF - #define BLE_MESH_RELAY_QUEUE_SIZE CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT static QueueSetHandle_t mesh_queue_set; #define BLE_MESH_QUEUE_SET_SIZE (BLE_MESH_ADV_QUEUE_SIZE + BLE_MESH_RELAY_QUEUE_SIZE) - #endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ static int adv_send(struct net_buf *buf) @@ -47,8 +45,8 @@ static int adv_send(struct net_buf *buf) struct bt_mesh_adv_data ad = {0}; int err = 0; - BT_DBG("type %u len %u: %s", BLE_MESH_ADV(buf)->type, - buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("LegacyAdvSend, Type %u", BLE_MESH_ADV(buf)->type); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV if (BLE_MESH_ADV(buf)->type != BLE_MESH_ADV_BLE) { @@ -116,10 +114,12 @@ static int adv_send(struct net_buf *buf) #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX if (BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_PROXY_SOLIC) { bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); + struct bt_mesh_adv_data solic_ad[2] = { BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x59, 0x18), BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, buf->data, buf->len), }; + #if CONFIG_BLE_MESH_USE_BLE_50 param.primary_phy = BLE_MESH_ADV_PHY_1M; param.secondary_phy = BLE_MESH_ADV_PHY_1M; @@ -128,9 +128,10 @@ static int adv_send(struct net_buf *buf) err = bt_le_adv_start(¶m, solic_ad, ARRAY_SIZE(solic_ad), NULL, 0); #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ } else -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ { bt_mesh_adv_buf_ref_debug(__func__, buf, 4U, BLE_MESH_BUF_REF_SMALL); + #if CONFIG_BLE_MESH_USE_BLE_50 param.primary_phy = BLE_MESH_ADV_PHY_1M; param.secondary_phy = BLE_MESH_ADV_PHY_1M; @@ -151,8 +152,8 @@ static int adv_send(struct net_buf *buf) } BT_DBG("interval %dms, duration %dms, period %dms, count %d", - ADV_SCAN_INT(tx->param.interval), tx->param.duration, - tx->param.period, tx->param.count); + ADV_SCAN_INT(tx->param.interval), tx->param.duration, + tx->param.period, tx->param.count); data.adv_data_len = tx->buf->data[0]; if (data.adv_data_len) { @@ -175,6 +176,7 @@ static int adv_send(struct net_buf *buf) #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ net_buf_unref(buf); + adv_send_start(duration, err, cb, cb_data); if (err) { BT_ERR("Start advertising failed: err %d", err); @@ -209,9 +211,12 @@ static QueueHandle_t relay_adv_handle_get(void) { struct bt_mesh_adv_type_manager *adv_type = NULL; + BT_DBG("RelayAdvHandleGet"); + adv_type = bt_mesh_adv_types_mgmt_get(BLE_MESH_ADV_RELAY_DATA); if (adv_type->adv_q == NULL) { + BT_DBG("HandleNotFound"); return NULL; } @@ -224,7 +229,7 @@ static void adv_thread(void *p) #if CONFIG_BLE_MESH_RELAY_ADV_BUF QueueHandle_t relay_adv_handle = NULL; QueueSetMemberHandle_t handle = NULL; -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ struct net_buf **buf = NULL; bt_mesh_msg_t msg = {0}; @@ -235,24 +240,29 @@ static void adv_thread(void *p) buf = (struct net_buf **)(&msg.arg); - BT_DBG("%s, starts", __func__); + BT_DBG("LegacyAdvThread"); while (1) { *buf = NULL; + #if !CONFIG_BLE_MESH_RELAY_ADV_BUF #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER xQueueReceive(adv_queue->q.handle, &msg, K_NO_WAIT); while (!(*buf)) { int32_t timeout = 0; + BT_DBG("Mesh Proxy Advertising start"); + timeout = bt_mesh_proxy_server_adv_start(); BT_DBG("Mesh Proxy Advertising up to %d ms", timeout); + xQueueReceive(adv_queue->q.handle, &msg, K_WAIT(timeout)); + BT_DBG("Mesh Proxy Advertising stop"); bt_mesh_proxy_server_adv_stop(); } -#else +#else /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ xQueueReceive(adv_queue->q.handle, &msg, portMAX_DELAY); #endif /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #else /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ @@ -268,12 +278,17 @@ static void adv_thread(void *p) } else { while (!(*buf)) { int32_t timeout = 0; + BT_DBG("Mesh Proxy Advertising start"); + timeout = bt_mesh_proxy_server_adv_start(); BT_DBG("Mesh Proxy Advertising up to %d ms", timeout); + handle = xQueueSelectFromSet(mesh_queue_set, K_WAIT(timeout)); + BT_DBG("Mesh Proxy Advertising stop"); bt_mesh_proxy_server_adv_stop(); + if (handle) { if (uxQueueMessagesWaiting(adv_queue->q.handle)) { xQueueReceive(adv_queue->q.handle, &msg, K_NO_WAIT); @@ -283,7 +298,7 @@ static void adv_thread(void *p) } } } -#else +#else /* (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || CONFIG_BLE_MESH_GATT_PROXY_SERVER */ handle = xQueueSelectFromSet(mesh_queue_set, portMAX_DELAY); if (handle) { if (uxQueueMessagesWaiting(adv_queue->q.handle)) { @@ -311,6 +326,7 @@ static void adv_thread(void *p) * BLE_MESH_RELAY_TIME_INTERVAL, this relay packet will not be sent. */ BT_INFO("Ignore relay packet"); + net_buf_unref(*buf); } else { if (adv_send(*buf)) { @@ -323,6 +339,8 @@ static void adv_thread(void *p) net_buf_unref(*buf); } + BT_DBG("Yield"); + /* Give other threads a chance to run */ taskYIELD(); } @@ -335,11 +353,14 @@ void bt_mesh_adv_update(void) .arg = NULL, }; + BT_DBG("LegacyAdvUpdate"); + bt_mesh_task_post(&msg, K_NO_WAIT, false); } void bt_mesh_adv_init(void) { + BT_DBG("LegacyAdvInit"); bt_mesh_adv_common_init(); adv_queue = bt_mesh_adv_queue_get(); @@ -347,20 +368,22 @@ void bt_mesh_adv_init(void) #if CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_relay_adv_init(); -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV bt_mesh_ble_adv_init(); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ #if CONFIG_BLE_MESH_RELAY_ADV_BUF QueueHandle_t relay_adv_handle = relay_adv_handle_get(); assert(relay_adv_handle); + mesh_queue_set = xQueueCreateSet(BLE_MESH_QUEUE_SET_SIZE); assert(mesh_queue_set); + xQueueAddToSet(adv_queue->q.handle, mesh_queue_set); xQueueAddToSet(relay_adv_handle, mesh_queue_set); -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ bt_mesh_adv_task_init(adv_thread); } @@ -368,6 +391,8 @@ void bt_mesh_adv_init(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_adv_deinit(void) { + BT_DBG("LegacyAdvDeinit"); + /* Adv task must be deinit first */ bt_mesh_adv_task_deinit(); @@ -377,6 +402,7 @@ void bt_mesh_adv_deinit(void) xQueueRemoveFromSet(adv_queue->q.handle, mesh_queue_set); xQueueRemoveFromSet(relay_adv_handle, mesh_queue_set); + vQueueDelete(mesh_queue_set); mesh_queue_set = NULL; diff --git a/components/bt/esp_ble_mesh/core/adv.h b/components/bt/esp_ble_mesh/core/adv.h index a2c8dd0330..79f8ca2991 100644 --- a/components/bt/esp_ble_mesh/core/adv.h +++ b/components/bt/esp_ble_mesh/core/adv.h @@ -26,10 +26,13 @@ extern "C" { void bt_mesh_adv_update(void); void bt_mesh_adv_init(void); + void bt_mesh_adv_deinit(void); #ifdef __cplusplus } #endif + #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ + #endif /* _ADV_H_ */ diff --git a/components/bt/esp_ble_mesh/core/adv_common.c b/components/bt/esp_ble_mesh/core/adv_common.c index ec1e3b68db..193dcf4c43 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.c +++ b/components/bt/esp_ble_mesh/core/adv_common.c @@ -31,8 +31,7 @@ struct bt_mesh_adv_queue relay_adv_queue; #define BLE_MESH_RELAY_TIME_INTERVAL K_SECONDS(6) #define BLE_MESH_MAX_TIME_INTERVAL 0xFFFFFFFF - -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ static bt_mesh_mutex_t adv_buf_alloc_lock; #if CONFIG_BLE_MESH_EXT_ADV @@ -77,7 +76,7 @@ NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, BLE_MESH_ADV_DATA_SIZE, NULL); static bt_mesh_friend_adv_t frnd_adv_pool[FRIEND_BUF_COUNT]; -#endif +#endif /* CONFIG_BLE_MESH_FRIEND */ struct bt_mesh_adv_task { TaskHandle_t handle; @@ -90,6 +89,7 @@ struct bt_mesh_adv_task { }; static struct bt_mesh_adv_task adv_task; + static struct bt_mesh_adv_type_manager adv_types[BLE_MESH_ADV_TYPES_NUM]; #if CONFIG_BLE_MESH_USE_BLE_50 @@ -98,7 +98,7 @@ static struct bt_mesh_adv_inst adv_insts[] = { .id = CONFIG_BLE_MESH_ADV_INST_ID, #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV .busy = false, -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ }, #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ @@ -113,24 +113,27 @@ static struct bt_mesh_adv_inst adv_insts[] = { .id = CONFIG_BLE_MESH_RELAY_ADV_INST_ID, .busy = false, }, -#endif +#endif /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE [BLE_MESH_BLE_ADV_INST] = { .id = CONFIG_BLE_MESH_BLE_ADV_INST_ID, .busy = false, }, -#endif +#endif /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ }; static struct bt_mesh_adv_inst *find_adv_inst_with_inst_id(uint8_t id) { + BT_DBG("FindAdvInstWithID, InstID %u", id); + for (int i = 0; i < ARRAY_SIZE(adv_insts); i++) { if (adv_insts[i].id == id) { return &adv_insts[i]; } } + BT_WARN("NotFoundAdvInst, InstID %u", id); return NULL; } @@ -139,47 +142,57 @@ struct bt_mesh_adv_inst *bt_mesh_get_adv_insts_set(void) return adv_insts; } -bool bt_mesh_is_adv_inst_used(uint8_t adv_inst_id) +bool bt_mesh_is_adv_inst_used(uint8_t inst_id) { - return (find_adv_inst_with_inst_id(adv_inst_id) != NULL); + BT_DBG("IsAdvInstUsed, InstID %u", inst_id); + + return (find_adv_inst_with_inst_id(inst_id) != NULL); } int bt_mesh_adv_inst_init(enum bt_mesh_adv_inst_type inst_type, uint8_t inst_id) { + BT_DBG("AdvInstInit, InstType %u InstID %u", inst_type, inst_id); + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_ERR("InvalidAdvInstType %u", inst_type); return -EINVAL; } if (inst_id == BLE_MESH_ADV_INS_UNUSED) { - BT_ERR("Invalid instance id %d", inst_id); + BT_ERR("UnusedAdvInstID"); return -EINVAL; } adv_insts[inst_type].id = inst_id; + return 0; } int bt_mesh_adv_inst_deinit(enum bt_mesh_adv_inst_type inst_type) { + BT_DBG("AdvInstDeinit, InstType %u", inst_type); + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_ERR("Invalid adv inst type %d", inst_type); return -EINVAL; } + BT_DBG("InstID %u", adv_insts[inst_type].id); + bt_le_ext_adv_stop(adv_insts[inst_type].id); adv_insts[inst_type].id = BLE_MESH_ADV_INS_UNUSED; #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV adv_insts[inst_type].spt_mask = 0; -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ + return 0; } - #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ static struct bt_mesh_adv *adv_alloc(int id, enum bt_mesh_adv_type type) { + BT_DBG("AdvAlloc, ID %d", id); init_adv_with_defaults(&adv_pool[id], type); return &adv_pool[id]; } @@ -232,6 +245,8 @@ struct bt_mesh_adv *ext_long_relay_adv_alloc(int id, enum bt_mesh_adv_type type) struct bt_mesh_adv_type_manager *bt_mesh_adv_types_mgnt_get(enum bt_mesh_adv_type adv_type) { + BT_DBG("AdvTypeMgmtGet, AdvType %u", adv_type); + return &adv_types[adv_type]; } @@ -243,6 +258,8 @@ void bt_mesh_adv_buf_ref_debug(const char *func, struct net_buf *buf, return; } + BT_DBG("AdvBufRefDebug, BufRef %u RefCmp %u", buf->ref, ref_cmp); + switch (flag) { case BLE_MESH_BUF_REF_EQUAL: if (buf->ref != ref_cmp) { @@ -263,8 +280,10 @@ void bt_mesh_adv_buf_ref_debug(const char *func, struct net_buf *buf, void bt_mesh_adv_inst_type_add(enum bt_mesh_adv_inst_type inst_type, enum bt_mesh_adv_type adv_type) { + BT_DBG("AdvInstTypeAdd, InstType %u AdvType %u", inst_type, adv_type); + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_ERR("Invalid adv inst type %d", inst_type); return; } @@ -276,11 +295,13 @@ void bt_mesh_adv_inst_type_add(enum bt_mesh_adv_inst_type inst_type, adv_insts[inst_type].spt_mask |= BIT(adv_type); } -void bt_mesh_adv_inst_type_rm(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type) +void bt_mesh_adv_inst_type_rem(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type) { + BT_DBG("AdvInstTypeRem, InstType %u AdvType %u", inst_type, adv_type); + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_ERR("Invalid adv inst type %d", inst_type); return; } @@ -292,11 +313,13 @@ void bt_mesh_adv_inst_type_rm(enum bt_mesh_adv_inst_type inst_type, adv_insts[inst_type].spt_mask &= ~BIT(adv_type); } -void bt_mesh_adv_inst_supported_adv_type_clear(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type) +void bt_mesh_adv_inst_type_clear(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type) { + BT_DBG("AdvInstTypeClear, InstType %u AdvType %u", inst_type, adv_type); + if (inst_type >= BLE_MESH_ADV_INST_TYPES_NUM) { - BT_ERR("Invalid instance type %d", inst_type); + BT_ERR("Invalid adv inst type %d", inst_type); return; } @@ -307,18 +330,19 @@ void bt_mesh_adv_inst_supported_adv_type_clear(enum bt_mesh_adv_inst_type inst_t adv_insts[inst_type].spt_mask = 0; } -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ int bt_mesh_adv_queue_init(struct bt_mesh_adv_queue *adv_queue, uint16_t queue_size, bt_mesh_adv_queue_send_cb_t cb) { + BT_DBG("AdvQueueInit, QueueSize %u", queue_size); + if (!adv_queue || !queue_size || !cb) { - BT_ERR("Invalid param %s", __func__); + BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } bt_mesh_queue_init(&adv_queue->q, queue_size, sizeof(bt_mesh_msg_t)); - adv_queue->send = cb; return 0; @@ -326,13 +350,14 @@ int bt_mesh_adv_queue_init(struct bt_mesh_adv_queue *adv_queue, uint16_t queue_s int bt_mesh_adv_queue_deinit(struct bt_mesh_adv_queue *adv_queue) { + BT_DBG("AdvQueueDeinit"); + if (!adv_queue) { - BT_ERR("Invalid param %s", __func__); + BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } bt_mesh_queue_deinit(&adv_queue->q); - adv_queue->send = NULL; return 0; @@ -343,13 +368,15 @@ void bt_mesh_adv_type_init(enum bt_mesh_adv_type adv_type, struct net_buf_pool *buf_pool, bt_mesh_pool_allocator_t adv_alloc) { + BT_DBG("AdvTypeInit, AdvType %u", adv_type); + if (adv_type >= BLE_MESH_ADV_TYPES_NUM) { - BT_ERR("%s Invalid adv type %d",__func__, adv_type); + BT_ERR("%s, Invalid adv type %d", __func__, adv_type); return; } if (!adv_queue || !buf_pool || !adv_alloc) { - BT_ERR("Invalid parameters %s", __func__); + BT_ERR("%s, Invalid parameter", __func__); return; } @@ -360,8 +387,10 @@ void bt_mesh_adv_type_init(enum bt_mesh_adv_type adv_type, void bt_mesh_adv_type_deinit(enum bt_mesh_adv_type adv_type) { + BT_DBG("AdvTypeDeinit, AdvType %u", adv_type); + if (adv_type >= BLE_MESH_ADV_TYPES_NUM) { - BT_ERR("%s Invalid adv type %d",__func__, adv_type); + BT_ERR("%s, Invalid adv type %d", __func__, adv_type); return; } @@ -373,17 +402,23 @@ void bt_mesh_adv_type_deinit(enum bt_mesh_adv_type adv_type) #if CONFIG_BLE_MESH_USE_BLE_50 int bt_mesh_adv_task_wakeup(uint32_t evt) { + BT_DBG("AdvTypeWakeup, Evt 0x%08lx", evt); + xTaskNotify(adv_task.handle, evt, eSetBits); return 0; } bool bt_mesh_adv_task_wait(uint32_t wait_bits, uint32_t timeout, uint32_t *notify) { + BT_DBG("AdvTypeWait, WaitBits 0x%08lx Timeout %lu", wait_bits, timeout); + return (xTaskNotifyWait(wait_bits, UINT32_MAX, notify, K_WAIT(timeout)) == pdTRUE); } #else /* CONFIG_BLE_MESH_USE_BLE_50 */ bool bt_mesh_adv_task_wait(uint32_t timeout) { + BT_DBG("AdvTypeWait, Timeout %lu", timeout); + vTaskDelay(K_WAIT(timeout)); return true; } @@ -397,6 +432,8 @@ uint16_t bt_mesh_pdu_duration(uint8_t xmit) adv_int = MAX(ADV_ITVL_MIN, BLE_MESH_TRANSMIT_INT(xmit)); duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10); + BT_DBG("PDUDuration %u", duration); + return duration; } @@ -405,6 +442,8 @@ struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, int32_t struct bt_mesh_adv *adv = NULL; struct net_buf *buf = NULL; + BT_DBG("AdvCreateFromPool, Type %u", type); + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_SUSPENDED)) { BT_WARN("Refusing to allocate buffer while suspended"); return NULL; @@ -424,23 +463,27 @@ struct net_buf *bt_mesh_adv_create_from_pool(enum bt_mesh_adv_type type, int32_t buf = net_buf_alloc(adv_types[type].pool, timeout); if (!buf) { + BT_WARN("net buf alloc failed"); bt_mesh_r_mutex_unlock(&adv_buf_alloc_lock); - BT_WARN("Buf alloc failed"); return NULL; } - BT_DBG("pool %p, buf_count %d, uinit_count %d, ref %d", - adv_types[type].pool, adv_types[type].pool->buf_count, - adv_types[type].pool->uninit_count, buf->ref); + BT_DBG("Pool %p BufCount %u UinitCount %u BufID %d Ref %u", + adv_types[type].pool, adv_types[type].pool->buf_count, + adv_types[type].pool->uninit_count, net_buf_id(buf), + buf->ref); adv = adv_types[type].pool_allocator(net_buf_id(buf), type); BLE_MESH_ADV(buf) = adv; bt_mesh_r_mutex_unlock(&adv_buf_alloc_lock); + return buf; } void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool) { + BT_DBG("UnrefBufFromPool"); + if (pool == NULL) { BT_ERR("%s, Invalid parameter", __func__); return; @@ -448,6 +491,9 @@ void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool) for (int i = 0; i < pool->buf_count; i++) { struct net_buf *buf = &pool->__bufs[i]; + + BT_DBG("%u: Buf %p Ref %u", i, buf, buf->ref); + if (buf->ref > 1U) { buf->ref = 1U; } @@ -459,8 +505,13 @@ void bt_mesh_unref_buf(bt_mesh_msg_t *msg) { struct net_buf *buf = msg->arg; + BT_DBG("UnRefBuf %p", buf); + if (buf) { + BT_DBG("Ref %u", buf->ref); + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0); + if (buf->ref > 1U) { buf->ref = 1U; } @@ -477,8 +528,10 @@ void bt_mesh_generic_adv_send(struct net_buf *buf, uint8_t xmit, .relay = false, /* useless flag in multi-instance mode */ }; - BT_DBG("type 0x%02x len %u: %s", BLE_MESH_ADV(buf)->type, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("GenericAdvSend"); + BT_DBG("Src 0x%04x Dst 0x%04x Type 0x%02x", + src, dst, BLE_MESH_ADV(buf)->type); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; @@ -495,8 +548,10 @@ void bt_mesh_generic_adv_send(struct net_buf *buf, uint8_t xmit, msg.src = src; msg.dst = dst; msg.timestamp = k_uptime_get_32(); + + BT_DBG("RelayAdvData, Timestamp %lu", msg.timestamp); } -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ assert(adv_types[BLE_MESH_ADV(buf)->type].adv_q); assert(adv_types[BLE_MESH_ADV(buf)->type].adv_q->send); @@ -505,7 +560,7 @@ void bt_mesh_generic_adv_send(struct net_buf *buf, uint8_t xmit, #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV bt_mesh_adv_task_wakeup(ADV_TASK_PKT_SEND_EVT); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ } struct bt_mesh_adv_queue *bt_mesh_adv_queue_get(void) @@ -515,6 +570,8 @@ struct bt_mesh_adv_queue *bt_mesh_adv_queue_get(void) void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) { + BT_DBG("TaskPost, Front %u", front); + if (adv_queue.q.handle == NULL) { BT_ERR("Invalid adv queue"); return; @@ -545,11 +602,15 @@ bool bt_mesh_ignore_relay_packet(uint32_t timestamp) interval = BLE_MESH_MAX_TIME_INTERVAL - (timestamp - now) + 1; } + BT_DBG("IgnoreRelayPacket"); + BT_DBG("Now %lu Timestamp %lu Interval %lu", now, timestamp, interval); + return ((interval >= BLE_MESH_RELAY_TIME_INTERVAL) ? true : false); } static struct bt_mesh_adv *relay_adv_alloc(int id, enum bt_mesh_adv_type type) { + BT_DBG("RelayAdvAlloc, ID %d", id); memset(&relay_adv_pool[id], 0, sizeof(struct bt_mesh_adv)); init_adv_with_defaults(&relay_adv_pool[id], type); return &relay_adv_pool[id]; @@ -559,7 +620,7 @@ static void bt_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool f { bt_mesh_msg_t old_msg = {0}; - ARG_UNUSED(front); + BT_DBG("RelayTaskPost, Front %u", front); if (relay_adv_queue.q.handle == NULL) { BT_ERR("Invalid relay queue"); @@ -575,14 +636,17 @@ static void bt_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool f */ if (uxQueueMessagesWaiting(relay_adv_queue.q.handle)) { BT_INFO("Full queue, remove the oldest relay packet"); + /* Remove the oldest relay packet from queue */ if (xQueueReceive(relay_adv_queue.q.handle, &old_msg, K_NO_WAIT) != pdTRUE) { BT_ERR("Failed to remove item from relay queue"); bt_mesh_unref_buf(msg); return; } + /* Unref buf used for the oldest relay packet */ bt_mesh_unref_buf(&old_msg); + /* Send the latest relay packet to queue */ if (xQueueSend(relay_adv_queue.q.handle, msg, K_NO_WAIT) != pdTRUE) { BT_ERR("Failed to send item to relay queue"); @@ -597,7 +661,11 @@ static void bt_mesh_relay_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool f uint16_t bt_mesh_get_stored_relay_count(void) { - return (uint16_t)uxQueueMessagesWaiting(relay_adv_queue.q.handle); + uint16_t count = (uint16_t)uxQueueMessagesWaiting(relay_adv_queue.q.handle); + + BT_DBG("StoredRelayCount %u", count); + + return count; } static ALWAYS_INLINE @@ -617,6 +685,7 @@ uint16_t bt_mesh_relay_adv_buf_count_get(void) void bt_mesh_relay_adv_init(void) { + BT_DBG("RelayAdvInit"); bt_mesh_adv_queue_init(&relay_adv_queue, bt_mesh_relay_adv_buf_count_get(), bt_mesh_relay_task_post); bt_mesh_adv_type_init(BLE_MESH_ADV_RELAY_DATA, &relay_adv_queue, @@ -655,10 +724,14 @@ void bt_mesh_relay_adv_init(void) #endif /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ } + #if CONFIG_BLE_MESH_DEINIT void bt_mesh_relay_adv_deinit(void) { + BT_DBG("RelayAdvDeinit"); + bt_mesh_adv_queue_deinit(&relay_adv_queue); + bt_mesh_adv_type_deinit(BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV bt_mesh_adv_type_deinit(BLE_MESH_ADV_EXT_RELAY_DATA); @@ -669,26 +742,27 @@ void bt_mesh_relay_adv_deinit(void) #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE - bt_mesh_adv_inst_type_rm(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_type_rm(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_type_rm(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_RELAY_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ bt_mesh_adv_inst_deinit(BLE_MESH_RELAY_ADV_INST); #else /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_RELAY_DATA); #if CONFIG_BLE_MESH_EXT_ADV - bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_RELAY_DATA); #if CONFIG_BLE_MESH_LONG_PACKET - bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_EXT_LONG_RELAY_DATA); #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ #endif /* CONFIG_BLE_MESH_SEPARATE_RELAY_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ + bt_mesh_unref_buf_from_pool(&relay_adv_buf_pool); memset(relay_adv_pool, 0, sizeof(relay_adv_pool)); } @@ -698,6 +772,8 @@ void bt_mesh_relay_adv_deinit(void) #if CONFIG_BLE_MESH_FRIEND static struct bt_mesh_adv *bt_mesh_frnd_adv_buf_get(int idx, enum bt_mesh_adv_type type) { + BT_DBG("FrndAdvBufGet, Idx %d", idx); + memset(&frnd_adv_pool[idx].adv, 0, sizeof(struct bt_mesh_adv)); init_adv_with_defaults(&frnd_adv_pool[idx].adv, type); frnd_adv_pool[idx].app_idx = BLE_MESH_KEY_UNUSED; @@ -706,7 +782,10 @@ static struct bt_mesh_adv *bt_mesh_frnd_adv_buf_get(int idx, enum bt_mesh_adv_ty void bt_mesh_frnd_adv_init(void) { + BT_DBG("FrndAdvInit"); + bt_mesh_adv_type_init(BLE_MESH_ADV_FRIEND, &adv_queue, &friend_buf_pool, bt_mesh_frnd_adv_buf_get); + #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_FRIEND); #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -714,10 +793,12 @@ void bt_mesh_frnd_adv_init(void) void bt_mesh_frnd_adv_deinit(void) { + BT_DBG("FrndAdvDeinit"); + bt_mesh_adv_type_deinit(BLE_MESH_ADV_FRIEND); #if CONFIG_BLE_MESH_FRIEND && CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_FRIEND); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_FRIEND); #endif /* CONFIG_BLE_MESH_FRIEND */ bt_mesh_unref_buf_from_pool(&friend_buf_pool); @@ -754,13 +835,15 @@ uint16_t bt_mesh_adv_buf_count_get(void) void bt_mesh_adv_task_init(void adv_thread(void *p)) { + BT_DBG("AdvTaskInit"); + if (!adv_thread) { - BT_ERR("Invalid param %s", __func__); + BT_ERR("%s, Invalid parameter", __func__); return; } #if (CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && \ - (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \ + (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \ CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY) adv_task.task = heap_caps_calloc(1, sizeof(StaticTask_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); assert(adv_task.task); @@ -784,6 +867,8 @@ void bt_mesh_adv_task_init(void adv_thread(void *p)) void bt_mesh_adv_common_init(void) { + BT_DBG("AdvCommonInit"); + bt_mesh_r_mutex_create(&adv_buf_alloc_lock); bt_mesh_adv_queue_init(&adv_queue, bt_mesh_adv_buf_count_get(), bt_mesh_task_post); bt_mesh_adv_type_init(BLE_MESH_ADV_PROV, &adv_queue, &adv_buf_pool, adv_alloc); @@ -792,7 +877,7 @@ void bt_mesh_adv_common_init(void) bt_mesh_adv_type_init(BLE_MESH_ADV_URI, &adv_queue, &adv_buf_pool, adv_alloc); #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX bt_mesh_adv_type_init(BLE_MESH_ADV_PROXY_SOLIC, &adv_queue, &adv_buf_pool, adv_alloc); -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ #if CONFIG_BLE_MESH_USE_BLE_50 bt_mesh_adv_inst_init(BLE_MESH_ADV_INST, CONFIG_BLE_MESH_ADV_INST_ID); @@ -813,8 +898,7 @@ void bt_mesh_adv_common_init(void) #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - /** - * Due to the limitation of the sequence number in the network layer, + /* Due to the limitation of the sequence number in the network layer, * it is not possible to use multiple advertising instances to process * data from the same message queue when sending mesh packets. * @@ -845,6 +929,8 @@ void bt_mesh_adv_common_init(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_adv_task_deinit(void) { + BT_DBG("AdvTaskDeinit"); + vTaskDelete(adv_task.handle); adv_task.handle = NULL; @@ -860,6 +946,8 @@ void bt_mesh_adv_task_deinit(void) void bt_mesh_adv_common_deinit(void) { + BT_DBG("AdvCommonDeinit"); + bt_mesh_adv_type_deinit(BLE_MESH_ADV_PROV); bt_mesh_adv_type_deinit(BLE_MESH_ADV_DATA); bt_mesh_adv_type_deinit(BLE_MESH_ADV_BEACON); @@ -885,12 +973,14 @@ void bt_mesh_adv_common_deinit(void) #endif /* CONFIG_BLE_MESH_EXT_ADV */ bt_mesh_adv_queue_deinit(&adv_queue); + #if CONFIG_BLE_MESH_USE_BLE_50 bt_mesh_adv_inst_deinit(BLE_MESH_ADV_INST); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ bt_mesh_unref_buf_from_pool(&adv_buf_pool); memset(adv_pool, 0, sizeof(adv_pool)); + bt_mesh_r_mutex_free(&adv_buf_alloc_lock); } #endif /* CONFIG_BLE_MESH_DEINIT */ diff --git a/components/bt/esp_ble_mesh/core/adv_common.h b/components/bt/esp_ble_mesh/core/adv_common.h index d5172a676a..f77079a648 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.h +++ b/components/bt/esp_ble_mesh/core/adv_common.h @@ -31,9 +31,9 @@ extern "C" { #endif /* Convert from ms to 0.625ms units */ -#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) +#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) /* Convert from 0.625ms units to interval(ms) */ -#define ADV_SCAN_INT(val) ((val) * 5 / 8) +#define ADV_SCAN_INT(val) ((val) * 5 / 8) /* Maximum advertising data payload for a single data type */ #define BLE_MESH_ADV_DATA_SIZE 29 @@ -75,15 +75,13 @@ typedef struct { #endif #if CONFIG_BLE_MESH_FRIEND - #define FRIEND_ADV(buf) CONTAINER_OF(BLE_MESH_ADV(buf), bt_mesh_friend_adv_t, adv) typedef struct { struct bt_mesh_adv adv; uint16_t app_idx; } bt_mesh_friend_adv_t; - -#endif +#endif /* CONFIG_BLE_MESH_FRIEND */ enum { #if CONFIG_BLE_MESH_USE_BLE_50 @@ -103,12 +101,15 @@ enum { ADV_TASK_BLE_ADV_INST_EVT = BIT(CONFIG_BLE_MESH_BLE_ADV_INST_ID), #endif #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ + #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER ADV_TASK_PROXY_ADV_UPD_EVT = BIT(30), #endif #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ + ADV_TASK_PKT_SEND_EVT = BIT(31), + ADV_TASK_EVT_MAX, }; @@ -124,6 +125,7 @@ typedef struct bt_mesh_msg { struct bt_mesh_adv_inst { uint8_t id; + #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV bool busy; struct net_buf *sending_buf; @@ -184,13 +186,13 @@ static const uint8_t adv_type[] = { #endif /* CONFIG_BLE_MESH_LONG_PACKET */ #endif /* CONFIG_BLE_MESH_EXT_ADV */ #if CONFIG_BLE_MESH_FRIEND - [BLE_MESH_ADV_FRIEND] = BLE_MESH_DATA_MESH_MESSAGE, + [BLE_MESH_ADV_FRIEND] = BLE_MESH_DATA_MESH_MESSAGE, #endif #if CONFIG_BLE_MESH_RELAY_ADV_BUF [BLE_MESH_ADV_RELAY_DATA] = BLE_MESH_DATA_MESH_MESSAGE, #endif - [BLE_MESH_ADV_BEACON] = BLE_MESH_DATA_MESH_BEACON, - [BLE_MESH_ADV_URI] = BLE_MESH_DATA_URI, + [BLE_MESH_ADV_BEACON] = BLE_MESH_DATA_MESH_BEACON, + [BLE_MESH_ADV_URI] = BLE_MESH_DATA_URI, }; typedef struct bt_mesh_adv *(*bt_mesh_pool_allocator_t)(int id, enum bt_mesh_adv_type type); @@ -256,6 +258,7 @@ static inline void bt_mesh_adv_send(struct net_buf *buf, uint8_t xmit, } void bt_mesh_unref_buf_from_pool(struct net_buf_pool *pool); + void bt_mesh_unref_buf(bt_mesh_msg_t *msg); int bt_mesh_adv_queue_init(struct bt_mesh_adv_queue *adv_queue, @@ -265,34 +268,38 @@ int bt_mesh_adv_queue_init(struct bt_mesh_adv_queue *adv_queue, int bt_mesh_adv_queue_deinit(struct bt_mesh_adv_queue *adv_queue); void bt_mesh_adv_type_init(enum bt_mesh_adv_type adv_type, - struct bt_mesh_adv_queue *adv_queue, - struct net_buf_pool *buf_pool, - bt_mesh_pool_allocator_t adv_alloc); + struct bt_mesh_adv_queue *adv_queue, + struct net_buf_pool *buf_pool, + bt_mesh_pool_allocator_t adv_alloc); void bt_mesh_adv_type_deinit(enum bt_mesh_adv_type adv_type); void bt_mesh_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front); #if CONFIG_BLE_MESH_USE_BLE_50 -struct bt_mesh_adv_inst * bt_mesh_get_adv_insts_set(void); -bool bt_mesh_is_adv_inst_used(uint8_t adv_inst_id); +struct bt_mesh_adv_inst *bt_mesh_get_adv_insts_set(void); + +bool bt_mesh_is_adv_inst_used(uint8_t inst_id); + int bt_mesh_adv_inst_init(enum bt_mesh_adv_inst_type inst_type, uint8_t inst_id); + int bt_mesh_adv_inst_deinit(enum bt_mesh_adv_inst_type inst_type); #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV void bt_mesh_adv_inst_type_add(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type); + enum bt_mesh_adv_type adv_type); -void bt_mesh_adv_inst_type_rm(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type); +void bt_mesh_adv_inst_type_rem(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type); -void bt_mesh_adv_inst_supported_adv_type_clear(enum bt_mesh_adv_inst_type inst_type, - enum bt_mesh_adv_type adv_type); -#endif +void bt_mesh_adv_inst_type_clear(enum bt_mesh_adv_inst_type inst_type, + enum bt_mesh_adv_type adv_type); +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ #if CONFIG_BLE_MESH_RELAY_ADV_BUF void bt_mesh_relay_adv_init(void); + bool bt_mesh_ignore_relay_packet(uint32_t timestamp); static inline void bt_mesh_relay_adv_send(struct net_buf *buf, uint8_t xmit, @@ -312,25 +319,29 @@ void bt_mesh_relay_adv_deinit(void); #if CONFIG_BLE_MESH_FRIEND void bt_mesh_frnd_adv_init(void); + #if CONFIG_BLE_MESH_DEINIT void bt_mesh_frnd_adv_deinit(void); #endif /* CONFIG_BLE_MESH_DEINIT */ #endif /* CONFIG_BLE_MESH_FRIEND */ void bt_mesh_adv_task_init(void adv_thread(void *p)); + void bt_mesh_adv_common_init(void); #if CONFIG_BLE_MESH_DEINIT void bt_mesh_adv_task_deinit(void); + void bt_mesh_adv_common_deinit(void); #endif #if CONFIG_BLE_MESH_USE_BLE_50 int bt_mesh_adv_task_wakeup(uint32_t evt); + bool bt_mesh_adv_task_wait(uint32_t wait_bits, TickType_t timeout, uint32_t *notify); -#else +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ bool bt_mesh_adv_task_wait(uint32_t timeout); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV static inline void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, diff --git a/components/bt/esp_ble_mesh/core/beacon.c b/components/bt/esp_ble_mesh/core/beacon.c index 97ec6ebd82..32e31f10a9 100644 --- a/components/bt/esp_ble_mesh/core/beacon.c +++ b/components/bt/esp_ble_mesh/core/beacon.c @@ -27,19 +27,19 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ -#if defined(CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL) +#if CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL #define UNPROV_BEACON_INTERVAL K_SECONDS(CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL) -#else +#else /* CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL */ #define UNPROV_BEACON_INTERVAL K_SECONDS(5) -#endif +#endif /* CONFIG_BLE_MESH_UNPROVISIONED_BEACON_INTERVAL */ #if CONFIG_BLE_MESH_BQB_TEST #define SECURE_BEACON_INTERVAL K_SECONDS(3) -#else +#else /* CONFIG_BLE_MESH_BQB_TEST */ #define SECURE_BEACON_INTERVAL K_SECONDS(10) -#endif +#endif /* CONFIG_BLE_MESH_BQB_TEST */ /* 3 transmissions, 20ms interval */ #define UNPROV_XMIT BLE_MESH_TRANSMIT(2, 20) @@ -58,6 +58,8 @@ struct bt_mesh_subnet *cache_check(uint8_t data[21], bool private_beacon) uint8_t *cache = NULL; int i = 0; + BT_DBG("CacheCheck, PrivateBeacon %u", private_beacon); + subnet_size = bt_mesh_rx_netkey_size(); for (i = 0; i < subnet_size; i++) { @@ -69,11 +71,12 @@ struct bt_mesh_subnet *cache_check(uint8_t data[21], bool private_beacon) #if CONFIG_BLE_MESH_PRIVATE_BEACON cache = private_beacon ? sub->mpb_cache : sub->snb_cache; -#else +#else /* CONFIG_BLE_MESH_PRIVATE_BEACON */ cache = sub->snb_cache; -#endif +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ if (!memcmp(cache, data, 21)) { + BT_DBG("BeaconSubFound, NetIdx 0x%04x", sub->net_idx); return sub; } } @@ -83,11 +86,13 @@ struct bt_mesh_subnet *cache_check(uint8_t data[21], bool private_beacon) void cache_add(uint8_t data[21], struct bt_mesh_subnet *sub, bool private_beacon) { + BT_DBG("CacheAdd, NetIdx 0x%04x PrivateBeacon %u", sub->net_idx, private_beacon); + #if CONFIG_BLE_MESH_PRIVATE_BEACON if (private_beacon) { memcpy(sub->mpb_cache, data, 21); } else -#endif +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ { memcpy(sub->snb_cache, data, 21); } @@ -98,10 +103,10 @@ static void secure_beacon_complete(int err, void *user_data) struct bt_mesh_subnet *sub = NULL; uint16_t net_idx = BLE_MESH_KEY_UNUSED; - BT_DBG("err %d", err); - net_idx = (uint16_t)NET_IDX_GET(user_data); + BT_DBG("SecureBeaconComplete, NetIdx 0x%04x Err %d", net_idx, err); + /* For node, directly updating the "beacon_sent" timestamp is fine, * since the subnet is pre-allocated. * For Provisioner, before updating the "beacon_sent" timestamp, we @@ -112,6 +117,8 @@ static void secure_beacon_complete(int err, void *user_data) sub = bt_mesh_subnet_get(net_idx); if (sub) { sub->snb_sent = k_uptime_get_32(); + + BT_DBG("SnbSent %lu", sub->snb_sent); } } @@ -121,6 +128,8 @@ void bt_mesh_secure_beacon_create(struct bt_mesh_subnet *sub, uint8_t flags = bt_mesh_net_flags(sub); struct bt_mesh_subnet_keys *keys = NULL; + BT_DBG("SecureBeaconCreate"); + net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE); if (sub->kr_flag) { @@ -139,10 +148,10 @@ void bt_mesh_secure_beacon_create(struct bt_mesh_subnet *sub, net_buf_simple_add_mem(buf, sub->auth, 8); - BT_DBG("SNB: net_idx 0x%03x iv_index 0x%08x flags 0x%02x", - sub->net_idx, bt_mesh.iv_index, flags); - BT_DBG("SNB: NetID %s Auth %s", bt_hex(keys->net_id, 8), - bt_hex(sub->auth, 8)); + BT_DBG("NetIdx 0x%04x IVIndex 0x%08x Flags 0x%02x", + sub->net_idx, bt_mesh.iv_index, flags); + BT_DBG("NetID %s Auth %s", bt_hex(keys->net_id, 8), + bt_hex(sub->auth, 8)); } static int secure_beacon_send(void) @@ -154,6 +163,8 @@ static int secure_beacon_send(void) size_t subnet_size = 0U; int i = 0; + BT_DBG("SecureBeaconSend"); + subnet_size = bt_mesh_rx_netkey_size(); for (i = 0; i < subnet_size; i++) { @@ -165,6 +176,8 @@ static int secure_beacon_send(void) continue; } + BT_DBG("Now %lu SnbSent %lu SnbLast %u", now, sub->snb_sent, sub->snb_last); + time_diff = now - sub->snb_sent; if (time_diff < K_SECONDS(600) && time_diff < BEACON_THRESHOLD(sub->snb_last)) { @@ -178,9 +191,10 @@ static int secure_beacon_send(void) */ #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT if (bt_mesh_proxy_client_beacon_send(sub, false)) { + BT_DBG("ProxyClientBeaconSend"); continue; } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ buf = bt_mesh_adv_create(BLE_MESH_ADV_BEACON, K_NO_WAIT); if (!buf) { @@ -201,6 +215,7 @@ static int secure_beacon_send(void) * updating its "snb_sent" timestamp. */ bt_mesh_adv_send(buf, SNB_XMIT, &send_cb, NET_IDX_SET(sub->net_idx)); + net_buf_unref(buf); } @@ -214,6 +229,8 @@ static int unprovisioned_beacon_send(void) struct net_buf *buf = NULL; uint16_t oob_info = 0U; + BT_DBG("UnprovisionedBeaconSend"); + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return -EINVAL; @@ -252,6 +269,8 @@ static int unprovisioned_beacon_send(void) len = strlen(bt_mesh_prov_get()->uri); + BT_DBG("URI %u: %s", len, bt_mesh_prov_get()->uri); + if (net_buf_tailroom(buf) < len) { BT_WARN("Too long URI to fit advertising data"); } else { @@ -277,6 +296,8 @@ void update_beacon_observation(bool private_beacon) size_t subnet_size = 0U; int i = 0; + BT_DBG("UpdateBeaconObservation, PrivateBeacon %u", private_beacon); + /* Observation period is 20 seconds, whereas the beacon timer * runs every 10 seconds. We process what's happened during * the window only after the second half. @@ -287,13 +308,15 @@ void update_beacon_observation(bool private_beacon) if (private_beacon) { mpb_first_half = !mpb_first_half; if (mpb_first_half) { + BT_DBG("MpbFirstHalf"); return; } } else -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ { snb_first_half = !snb_first_half; if (snb_first_half) { + BT_DBG("SnbFirstHalf"); return; } } @@ -309,11 +332,15 @@ void update_beacon_observation(bool private_beacon) #if CONFIG_BLE_MESH_PRB_SRV if (private_beacon) { + BT_DBG("NetIdx 0x%04x MpbCur %u", sub->net_idx, sub->mpb_cur); + sub->mpb_last = sub->mpb_cur; sub->mpb_cur = 0U; } else -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ { + BT_DBG("NetIdx 0x%04x SnbCur %u", sub->net_idx, sub->snb_cur); + sub->snb_last = sub->snb_cur; sub->snb_cur = 0U; } @@ -330,9 +357,12 @@ static bool ready_to_send(void) static void secure_beacon_send_timeout(struct k_work *work) { + BT_DBG("SecureBeaconSendTimeout"); + /* Don't send anything if we have an active provisioning link */ if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node() && IS_ENABLED(CONFIG_BLE_MESH_PROV) && bt_mesh_prov_active()) { + BT_DBG("ProvActive"); k_delayed_work_submit(&snb_timer, UNPROV_BEACON_INTERVAL); return; } @@ -345,11 +375,14 @@ static void secure_beacon_send_timeout(struct k_work *work) /* Only resubmit if beaconing is still enabled */ if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED || bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)) { + BT_DBG("Resubmit, SecureBeacon %u", bt_mesh_secure_beacon_get()); + k_delayed_work_submit(&snb_timer, SECURE_BEACON_INTERVAL); } } else { if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node()) { unprovisioned_beacon_send(); + k_delayed_work_submit(&snb_timer, UNPROV_BEACON_INTERVAL); } } @@ -365,6 +398,8 @@ static void secure_beacon_recv(struct net_buf_simple *buf) bool new_key = false; uint8_t flags = 0U; + BT_DBG("SecureBeaconRecv"); + if (buf->len != 21) { BT_ERR("Malformed secure beacon (len %u)", buf->len); return; @@ -384,7 +419,7 @@ static void secure_beacon_recv(struct net_buf_simple *buf) iv_index = net_buf_simple_pull_be32(buf); auth = buf->data; - BT_DBG("flags 0x%02x id %s iv_index 0x%08x", + BT_DBG("Flags 0x%02x NetID %s IVIndex 0x%08x", flags, bt_hex(net_id, 8), iv_index); sub = bt_mesh_subnet_find_with_snb(net_id, flags, iv_index, auth, &new_key); @@ -393,6 +428,9 @@ static void secure_beacon_recv(struct net_buf_simple *buf) return; } + BT_DBG("NetIdx 0x%04x KrPhase %u NewKey %u", + sub->net_idx, sub->kr_phase, new_key); + if (sub->kr_phase == BLE_MESH_KR_PHASE_2 && !new_key) { BT_WARN("Ignoring Phase 2 KR Update secured using old key"); return; @@ -417,8 +455,7 @@ static void secure_beacon_recv(struct net_buf_simple *buf) goto update_stats; } - BT_DBG("SNB: net_idx 0x%03x iv_index 0x%08x current iv_index 0x%08x", - sub->net_idx, iv_index, bt_mesh.iv_index); + BT_DBG("IVIndex 0x%08lx CurIVIndex 0x%08lx", iv_index, bt_mesh.iv_index); if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR) && (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) == @@ -452,6 +489,7 @@ static void secure_beacon_recv(struct net_buf_simple *buf) update_stats: if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED && sub->snb_cur < 0xff) { + BT_DBG("SnbCurInc %u", sub->snb_cur); sub->snb_cur++; } } @@ -460,7 +498,8 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) { uint8_t type = 0U; - BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("BeaconRecv"); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->len < 1) { BT_ERR("Too short beacon"); @@ -470,7 +509,7 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) type = net_buf_simple_pull_u8(buf); switch (type) { case BEACON_TYPE_UNPROVISIONED: - BT_DBG("Unprovisioned device beacon received"); + BT_DBG("UnprovDevBeaconRecv, Rssi %d", rssi); if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && @@ -480,11 +519,16 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_is_provisioned()) { - const bt_mesh_addr_t *addr = bt_mesh_get_unprov_dev_addr(); + const bt_mesh_addr_t *addr = NULL; + + addr = bt_mesh_get_unprov_dev_addr(); + assert(addr); + bt_mesh_unprov_dev_fifo_enqueue(buf->data, addr->val, bt_mesh_get_adv_type()); + bt_mesh_rpr_srv_unprov_beacon_recv(buf, bt_mesh_get_adv_type(), addr, rssi); } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ break; case BEACON_TYPE_SECURE: secure_beacon_recv(buf); @@ -493,7 +537,7 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf, int8_t rssi) case BEACON_TYPE_PRIVATE: bt_mesh_private_beacon_recv(buf); break; -#endif +#endif /* CONFIG_BLE_MESH_PRIVATE_BEACON */ default: BT_DBG("Unknown beacon type 0x%02x", type); break; @@ -514,7 +558,7 @@ void bt_mesh_beacon_init(void) BT_ERR("Failed to create a mpb_timer"); return; } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } #if CONFIG_BLE_MESH_DEINIT @@ -532,24 +576,28 @@ void bt_mesh_beacon_deinit(void) void bt_mesh_beacon_ivu_initiator(bool enable) { + BT_DBG("BeaconIVUInitiator, IVUInitiator %u", enable); + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_INITIATOR, enable); if (enable) { k_delayed_work_submit(&snb_timer, K_NO_WAIT); + #if CONFIG_BLE_MESH_PRB_SRV if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_timer_submit(K_NO_WAIT); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } else { if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_DISABLED) { k_delayed_work_cancel(&snb_timer); } + #if CONFIG_BLE_MESH_PRB_SRV if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_DISABLED) { bt_mesh_private_beacon_timer_cancel(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } } @@ -558,8 +606,12 @@ void bt_mesh_secure_beacon_enable(void) size_t subnet_size = 0U; int i = 0; + BT_DBG("SecureBeaconEnable"); + if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node() && !bt_mesh_is_provisioned()) { + BT_DBG("NodeNotProvisioned"); + k_delayed_work_submit(&snb_timer, K_NO_WAIT); return; } @@ -584,6 +636,9 @@ void bt_mesh_secure_beacon_enable(void) void bt_mesh_secure_beacon_disable(void) { + BT_DBG("SecureBeaconDisable, IVUInitiator %u", + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)); + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_INITIATOR)) { k_delayed_work_cancel(&snb_timer); } diff --git a/components/bt/esp_ble_mesh/core/ble_adv.c b/components/bt/esp_ble_mesh/core/ble_adv.c index e27109c047..aaaa4b4290 100644 --- a/components/bt/esp_ble_mesh/core/ble_adv.c +++ b/components/bt/esp_ble_mesh/core/ble_adv.c @@ -30,10 +30,11 @@ static struct bt_mesh_adv ble_adv_pool[CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT]; static struct bt_mesh_ble_adv_tx ble_adv_tx[CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT]; -#define SEND_BLE_ADV_INFINITE 0xFFFF +#define SEND_BLE_ADV_INFINITE 0xFFFF static struct bt_mesh_adv *ble_adv_alloc(int id, enum bt_mesh_adv_type type) { + BT_DBG("BLEAdvAlloc, ID %d", id); memset(&ble_adv_pool[id], 0, sizeof(struct bt_mesh_adv)); ble_adv_pool[id].type = type; return &ble_adv_pool[id]; @@ -43,7 +44,7 @@ static struct bt_mesh_adv *ble_adv_alloc(int id, enum bt_mesh_adv_type type) /* A separate post function is required only when using a separate queue */ static void bt_mesh_ble_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool front) { - BT_DBG("%s", __func__); + BT_DBG("BLETaskPost, Front %u", front); if (p_ble_adv_queue->q.handle == NULL) { BT_ERR("Invalid adv queue"); @@ -66,7 +67,10 @@ static void bt_mesh_ble_task_post(bt_mesh_msg_t *msg, uint32_t timeout, bool fro static void ble_adv_tx_reset(struct bt_mesh_ble_adv_tx *tx, bool unref) { + BT_DBG("BLEAdvTxReset, Unref %u", unref); + if (tx->buf == NULL) { + BT_DBG("NullTxBuf"); return; } @@ -74,7 +78,13 @@ static void ble_adv_tx_reset(struct bt_mesh_ble_adv_tx *tx, bool unref) k_delayed_work_free(&tx->resend); } bt_mesh_atomic_set(tx->flags, 0); + memset(&tx->param, 0, sizeof(tx->param)); + + BT_DBG("Buf %p Ref %u Busy %u", + tx->buf, tx->buf->ref, + !!bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(tx->buf))); + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(tx->buf), 0); if (unref) { net_buf_unref(tx->buf); @@ -86,7 +96,7 @@ static void ble_adv_send_start(uint16_t duration, int err, void *cb_data) { struct bt_mesh_ble_adv_tx *tx = cb_data; - BT_DBG("%s, duration %d, err %d", __func__, duration, err); + BT_DBG("BLEAdvSendStart, Duration %u Err %d", duration, err); /* If failed to send BLE adv packet, and param->count is not 0 * which means the timer has been initialized, here we need to @@ -101,13 +111,15 @@ static void ble_adv_send_end(int err, void *cb_data) { struct bt_mesh_ble_adv_tx *tx = cb_data; - BT_DBG("%s, err %d", __func__, err); + BT_DBG("BLEAdvSendEnd, Err %d", err); if (err) { ble_adv_tx_reset(tx, true); return; } + BT_DBG("Count %u Period %u", tx->param.count, tx->param.period); + if (tx->param.count) { if (tx->param.period) { k_delayed_work_submit(&tx->resend, tx->param.period); @@ -129,12 +141,18 @@ static void ble_adv_resend(struct k_work *work) struct bt_mesh_ble_adv_tx *tx = CONTAINER_OF(work, struct bt_mesh_ble_adv_tx, resend.work); bool front = false; + BT_DBG("BLEAdvResend"); + if (tx->buf == NULL) { /* The advertising has been cancelled */ + BT_INFO("%s, cancelled", __func__); return; } + BT_DBG("Priority %u Count %u Buf %p", tx->param.priority, tx->param.count, tx->buf); + front = (tx->param.priority == BLE_MESH_BLE_ADV_PRIO_HIGH) ? true : false; + bt_mesh_ble_adv_send(tx->buf, &ble_adv_send_cb, tx, front); if (tx->param.count == SEND_BLE_ADV_INFINITE) { @@ -154,6 +172,8 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, struct net_buf *buf = NULL; bool front = false; + BT_DBG("StartBLEAdv"); + if (param == NULL || index == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -206,6 +226,12 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, return -ENOBUFS; } + BT_DBG("AdvType 0x%02x Interval 0x%04x AddrType 0x%02x/0x%02x", + param->adv_type, param->interval, param->own_addr_type, param->peer_addr_type); + BT_DBG("DataLen %u/%u Priority %u Count %u Duration %u", + (data ? data->adv_data_len : 0), (data ? data->scan_rsp_data_len : 0), + param->priority, param->count, param->duration); + /* Set advertising data and scan response data */ memset(buf->data, 0, buf->size); if (data) { @@ -226,6 +252,7 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, front = (tx->param.priority == BLE_MESH_BLE_ADV_PRIO_HIGH) ? true : false; bt_mesh_ble_adv_send(buf, &ble_adv_send_cb, tx, front); + if (param->count) { if (k_delayed_work_init(&tx->resend, ble_adv_resend)) { /* If failed to create a timer, the BLE adv packet will be @@ -233,10 +260,12 @@ int bt_mesh_start_ble_advertising(const struct bt_mesh_ble_adv_param *param, * BLE adv packet can be sent, return 0 here. */ BT_WARN("Send BLE adv packet only once"); + tx->param.count = 0; net_buf_unref(buf); return 0; } + bt_mesh_atomic_set_bit(tx->flags, TIMER_INIT); } else { /* Send the BLE advertising packet only once */ @@ -251,6 +280,8 @@ int bt_mesh_stop_ble_advertising(uint8_t index) struct bt_mesh_ble_adv_tx *tx = NULL; bool unref = true; + BT_DBG("StopBLEAdv, Index %u", index); + if (index >= ARRAY_SIZE(ble_adv_tx)) { BT_ERR("Invalid adv index %d", index); return -EINVAL; @@ -263,6 +294,10 @@ int bt_mesh_stop_ble_advertising(uint8_t index) return 0; } + BT_DBG("Busy %u Ref %u", + !!bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(tx->buf)), + tx->buf->ref); + /* busy 1, ref 1; busy 1, ref 2; * busy 0, ref 0; busy 0, ref 1; */ @@ -288,16 +323,17 @@ struct bt_mesh_adv_queue *bt_mesh_ble_adv_queue_get(void) void bt_mesh_ble_adv_init(void) { + BT_DBG("BLEAdvInit"); p_ble_adv_queue = bt_mesh_ble_adv_queue_get(); bt_mesh_adv_type_init(BLE_MESH_ADV_BLE, p_ble_adv_queue, &ble_adv_buf_pool, ble_adv_alloc); #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE bt_mesh_adv_inst_init(BLE_MESH_BLE_ADV_INST, CONFIG_BLE_MESH_BLE_ADV_INST_ID); bt_mesh_adv_inst_type_add(BLE_MESH_BLE_ADV_INST, BLE_MESH_ADV_BLE); -#else +#else /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV bt_mesh_adv_inst_type_add(BLE_MESH_ADV_INST, BLE_MESH_ADV_BLE); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ #endif /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ } @@ -305,9 +341,12 @@ void bt_mesh_ble_adv_init(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_ble_adv_deinit(void) { + BT_DBG("BLEAdvDeinit"); + for (int i = 0; i < ARRAY_SIZE(ble_adv_tx); i++) { ble_adv_tx_reset(&ble_adv_tx[i], false); } + bt_mesh_unref_buf_from_pool(&ble_adv_buf_pool); memset(ble_adv_pool, 0, sizeof(ble_adv_pool)); @@ -317,13 +356,14 @@ void bt_mesh_ble_adv_deinit(void) bt_mesh_adv_queue_deinit(p_ble_adv_queue); #endif bt_mesh_adv_type_deinit(BLE_MESH_ADV_BLE); + #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE bt_mesh_adv_inst_deinit(BLE_MESH_BLE_ADV_INST); - bt_mesh_adv_inst_type_rm(BLE_MESH_BLE_ADV_INST, BLE_MESH_ADV_BLE); + bt_mesh_adv_inst_type_rem(BLE_MESH_BLE_ADV_INST, BLE_MESH_ADV_BLE); #else #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV - bt_mesh_adv_inst_type_rm(BLE_MESH_ADV_INST, BLE_MESH_ADV_BLE); + bt_mesh_adv_inst_type_rem(BLE_MESH_ADV_INST, BLE_MESH_ADV_BLE); #endif #endif /* CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE */ #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ diff --git a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c index 0520ca7a11..e31d4186e7 100644 --- a/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/bluedroid_host/adapter.c @@ -1615,7 +1615,7 @@ int bt_mesh_gatts_service_register(struct bt_mesh_gatt_service *svc) svc->attrs[i].handle = char_handle - 1; svc->attrs[i + 1].handle = char_handle; BT_DBG("Add characteristic, uuid 0x%04x, handle %d, perm %d, properties %d", - BLE_MESH_UUID_16(gatts_chrc->uuid)->val, char_handle, svc->attrs[i + 1].perm, gatts_chrc->properties); + BLE_MESH_UUID_16(gatts_chrc->uuid)->val, char_handle, svc->attrs[i + 1].perm, gatts_chrc->properties); break; } case BLE_MESH_UUID_GATT_CEP_VAL: @@ -1803,7 +1803,7 @@ uint16_t bt_mesh_gattc_get_service_uuid(struct bt_mesh_conn *conn) int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) { - tBTA_BLE_CONN_PARAMS conn_1m_param = {0}; + tBTA_BLE_CONN_PARAMS conn_1m_param = {0}; uint8_t zero[6] = {0}; int i; @@ -1872,9 +1872,10 @@ int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) conn_1m_param.max_ce_len = 0; BTA_GATTC_Enh_Open(bt_mesh_gattc_if, bt_mesh_gattc_info[i].addr.val, - bt_mesh_gattc_info[i].addr.type, true, BTA_GATT_TRANSPORT_LE, TRUE, BLE_ADDR_UNKNOWN_TYPE, - BTA_BLE_PHY_1M_MASK, &conn_1m_param, NULL, NULL); -#else + bt_mesh_gattc_info[i].addr.type, true, + BTA_GATT_TRANSPORT_LE, TRUE, BLE_ADDR_UNKNOWN_TYPE, + BTA_BLE_PHY_1M_MASK, &conn_1m_param, NULL, NULL); +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ /* Min_interval: 15ms * Max_interval: 15ms * Slave_latency: 0x0 @@ -1886,9 +1887,10 @@ int bt_mesh_gattc_conn_create(const bt_mesh_addr_t *addr, uint16_t service_uuid) conn_1m_param.supervision_timeout = 0x64; BTA_GATTC_Enh_Open(bt_mesh_gattc_if, bt_mesh_gattc_info[i].addr.val, - bt_mesh_gattc_info[i].addr.type, true, BTA_GATT_TRANSPORT_LE, FALSE, BLE_ADDR_UNKNOWN_TYPE, - BTA_BLE_PHY_1M_MASK, &conn_1m_param, NULL, NULL); -#endif + bt_mesh_gattc_info[i].addr.type, true, + BTA_GATT_TRANSPORT_LE, FALSE, BLE_ADDR_UNKNOWN_TYPE, + BTA_BLE_PHY_1M_MASK, &conn_1m_param, NULL, NULL); +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ return 0; } diff --git a/components/bt/esp_ble_mesh/core/cfg_cli.c b/components/bt/esp_ble_mesh/core/cfg_cli.c index 3aedd3644b..e04588fab7 100644 --- a/components/bt/esp_ble_mesh/core/cfg_cli.c +++ b/components/bt/esp_ble_mesh/core/cfg_cli.c @@ -110,6 +110,8 @@ static void cfg_client_recv_status(struct bt_mesh_model *model, struct net_buf_simple buf = {0}; uint8_t evt_type = 0xFF; + BT_DBG("CfgClientRecvStatus"); + if (!model || !ctx) { BT_ERR("%s, Invalid parameter", __func__); return; @@ -125,6 +127,8 @@ static void cfg_client_recv_status(struct bt_mesh_model *model, if (!node) { BT_DBG("Unexpected Config Status 0x%04x", ctx->recv_op); } else { + BT_DBG("OpCode 0x%08lx RecvOp 0x%08lx", node->opcode, ctx->recv_op); + switch (node->opcode) { case OP_BEACON_GET: case OP_COMP_DATA_GET: @@ -230,9 +234,10 @@ static void comp_data_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_comp_data_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("CompDataStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.page = net_buf_simple_pull_u8(buf); status.comp_data = bt_mesh_alloc_buf(buf->len); @@ -252,9 +257,10 @@ static void state_status_u8(struct bt_mesh_model *model, { uint8_t status = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("StateStatusU8"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); @@ -265,6 +271,8 @@ static void beacon_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("BeaconStatus"); + state_status_u8(model, ctx, buf); } @@ -272,6 +280,8 @@ static void ttl_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("TTLStatus"); + state_status_u8(model, ctx, buf); } @@ -279,6 +289,8 @@ static void friend_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("FrndStatus"); + state_status_u8(model, ctx, buf); } @@ -286,6 +298,8 @@ static void gatt_proxy_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("GattProxyStatus"); + state_status_u8(model, ctx, buf); } @@ -295,9 +309,10 @@ static void relay_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_relay_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("RelayStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.relay = net_buf_simple_pull_u8(buf); status.retransmit = net_buf_simple_pull_u8(buf); @@ -311,9 +326,10 @@ static void net_key_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_netkey_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NetKeyStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.net_idx = net_buf_simple_pull_le16(buf) & 0xfff; @@ -327,9 +343,10 @@ static void app_key_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_appkey_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("AppKeyStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); key_idx_unpack(buf, &status.net_idx, &status.app_idx); @@ -343,9 +360,10 @@ static void mod_app_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_app_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModAppStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.elem_addr = net_buf_simple_pull_le16(buf); @@ -366,9 +384,10 @@ static void mod_pub_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_pub_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModPubStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.elem_addr = net_buf_simple_pull_le16(buf); @@ -395,9 +414,10 @@ static void mod_sub_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_sub_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModSubStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.elem_addr = net_buf_simple_pull_le16(buf); @@ -418,9 +438,10 @@ static void hb_sub_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_hb_sub_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HbSubStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.src = net_buf_simple_pull_le16(buf); @@ -439,9 +460,10 @@ static void hb_pub_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_hb_pub_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HbPubStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.dst = net_buf_simple_pull_le16(buf); @@ -458,9 +480,10 @@ static void node_reset_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NodeResetStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); cfg_client_recv_status(model, ctx, NULL, 0); } @@ -471,9 +494,10 @@ static void mod_sub_list(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_sub_list list = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModSubList"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); list.status = net_buf_simple_pull_u8(buf); list.elem_addr = net_buf_simple_pull_le16(buf); @@ -500,9 +524,10 @@ static void net_key_list(struct bt_mesh_model *model, { struct bt_mesh_cfg_net_key_list list = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NetKeyList"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); list.net_idx = bt_mesh_alloc_buf(buf->len); if (!list.net_idx) { @@ -520,9 +545,10 @@ static void app_key_list(struct bt_mesh_model *model, { struct bt_mesh_cfg_app_key_list list = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("AppKeyList"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); list.status = net_buf_simple_pull_u8(buf); list.net_idx = net_buf_simple_pull_le16(buf); @@ -542,9 +568,10 @@ static void node_id_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_node_id_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NodeIDStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.net_idx = net_buf_simple_pull_le16(buf); @@ -559,9 +586,10 @@ static void mod_app_list(struct bt_mesh_model *model, { struct bt_mesh_cfg_mod_app_list list = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("ModAppList"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); list.status = net_buf_simple_pull_u8(buf); list.elem_addr = net_buf_simple_pull_le16(buf); @@ -588,9 +616,10 @@ static void kr_phase_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_key_refresh_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("KrPhaseStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.net_idx = net_buf_simple_pull_le16(buf); @@ -605,9 +634,10 @@ static void lpn_pollto_status(struct bt_mesh_model *model, { struct bt_mesh_cfg_lpn_pollto_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("LPNPollToStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.lpn_addr = net_buf_simple_pull_le16(buf); status.timeout = net_buf_simple_pull_u8(buf); @@ -621,6 +651,8 @@ static void net_trans_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("NetTransStatus"); + state_status_u8(model, ctx, buf); } @@ -656,6 +688,9 @@ static int send_msg_with_none(bt_mesh_client_common_param_t *param, uint32_t op) { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 0); + BT_DBG("SendMsgWithNone"); + BT_DBG("Dst 0x%04x Op 0x%08lx", param->ctx.addr, op); + bt_mesh_model_msg_init(&msg, op); return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); @@ -665,6 +700,9 @@ static int send_msg_with_u8(bt_mesh_client_common_param_t *param, uint32_t op, u { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 1); + BT_DBG("SendMsgWithU8"); + BT_DBG("Dst 0x%04x Op 0x%08lx Val 0x%02x", param->ctx.addr, op, val); + bt_mesh_model_msg_init(&msg, op); net_buf_simple_add_u8(&msg, val); @@ -675,6 +713,9 @@ static int send_msg_with_le16(bt_mesh_client_common_param_t *param, uint32_t op, { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 2); + BT_DBG("SendMsgWithLE16"); + BT_DBG("Dst 0x%04x Op 0x%08lx Val 0x%04x", param->ctx.addr, op, val); + bt_mesh_model_msg_init(&msg, op); net_buf_simple_add_le16(&msg, val); @@ -683,55 +724,76 @@ static int send_msg_with_le16(bt_mesh_client_common_param_t *param, uint32_t op, int bt_mesh_cfg_comp_data_get(bt_mesh_client_common_param_t *param, uint8_t page) { + BT_DBG("CompDataGet, Page %u", page); + return send_msg_with_u8(param, OP_COMP_DATA_GET, page); } int bt_mesh_cfg_beacon_get(bt_mesh_client_common_param_t *param) { + BT_DBG("BeaconGet"); + return send_msg_with_none(param, OP_BEACON_GET); } int bt_mesh_cfg_beacon_set(bt_mesh_client_common_param_t *param, uint8_t val) { + BT_DBG("BeaconSet, Val 0x%02x", val); + if (val > 0x01) { BT_ERR("Invalid beacon state 0x%02x", val); return -EINVAL; } + return send_msg_with_u8(param, OP_BEACON_SET, val); } int bt_mesh_cfg_ttl_get(bt_mesh_client_common_param_t *param) { + BT_DBG("TTLGet"); + return send_msg_with_none(param, OP_DEFAULT_TTL_GET); } int bt_mesh_cfg_ttl_set(bt_mesh_client_common_param_t *param, uint8_t val) { + BT_DBG("TTLSet, Val 0x%02x", val); + return send_msg_with_u8(param, OP_DEFAULT_TTL_SET, val); } int bt_mesh_cfg_friend_get(bt_mesh_client_common_param_t *param) { + BT_DBG("FrndGet"); + return send_msg_with_none(param, OP_FRIEND_GET); } int bt_mesh_cfg_friend_set(bt_mesh_client_common_param_t *param, uint8_t val) { + BT_DBG("FrndSet, Val 0x%02x", val); + return send_msg_with_u8(param, OP_FRIEND_SET, val); } int bt_mesh_cfg_gatt_proxy_get(bt_mesh_client_common_param_t *param) { + BT_DBG("GattProxyGet"); + return send_msg_with_none(param, OP_GATT_PROXY_GET); } int bt_mesh_cfg_gatt_proxy_set(bt_mesh_client_common_param_t *param, uint8_t val) { + BT_DBG("GattProxySet, Val 0x%02x", val); + return send_msg_with_u8(param, OP_GATT_PROXY_SET, val); } int bt_mesh_cfg_relay_get(bt_mesh_client_common_param_t *param) { + BT_DBG("RelayGet"); + return send_msg_with_none(param, OP_RELAY_GET); } @@ -740,6 +802,8 @@ int bt_mesh_cfg_relay_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_RELAY_SET, 2); + BT_DBG("RelaySet, Relay 0x%02x Retransmit 0x%02x", relay, retransmit); + bt_mesh_model_msg_init(&msg, OP_RELAY_SET); net_buf_simple_add_u8(&msg, relay); net_buf_simple_add_u8(&msg, retransmit); @@ -752,11 +816,15 @@ int bt_mesh_cfg_net_key_add(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_KEY_ADD, 18); + BT_DBG("NetKeyAdd"); + if (!net_key) { BT_ERR("Invalid NetKey"); return -EINVAL; } + BT_DBG("NetIdx 0x%04x NetKey %s", net_idx, bt_hex(net_key, 16)); + bt_mesh_model_msg_init(&msg, OP_NET_KEY_ADD); net_buf_simple_add_le16(&msg, net_idx); net_buf_simple_add_mem(&msg, net_key, 16); @@ -770,11 +838,16 @@ int bt_mesh_cfg_app_key_add(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_ADD, 19); + BT_DBG("AppKeyAdd"); + if (!app_key) { BT_ERR("Invalid AppKey"); return -EINVAL; } + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x AppKey %s", + net_idx, app_idx, bt_hex(app_key, 16)); + bt_mesh_model_msg_init(&msg, OP_APP_KEY_ADD); key_idx_pack(&msg, net_idx, app_idx); net_buf_simple_add_mem(&msg, app_key, 16); @@ -788,6 +861,10 @@ int bt_mesh_cfg_mod_app_bind(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_APP_BIND, 8); + BT_DBG("ModAppBind"); + BT_DBG("ElemAddr 0x%04x AppIdx 0x%04x ModID 0x%04x CID 0x%04x", + elem_addr, app_idx, mod_id, cid); + bt_mesh_model_msg_init(&msg, OP_MOD_APP_BIND); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_le16(&msg, app_idx); @@ -805,6 +882,10 @@ static int mod_sub(bt_mesh_client_common_param_t *param, uint32_t op, { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 8); + BT_DBG("ModSub"); + BT_DBG("ElemAddr 0x%04x SubAddr 0x%04x ModID 0x%04x CID 0x%04x", + elem_addr, sub_addr, mod_id, cid); + bt_mesh_model_msg_init(&msg, op); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_le16(&msg, sub_addr); @@ -820,6 +901,8 @@ int bt_mesh_cfg_mod_sub_add(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubAdd"); + return mod_sub(param, OP_MOD_SUB_ADD, elem_addr, sub_addr, mod_id, cid); } @@ -827,6 +910,8 @@ int bt_mesh_cfg_mod_sub_del(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubDel"); + return mod_sub(param, OP_MOD_SUB_DEL, elem_addr, sub_addr, mod_id, cid); } @@ -834,6 +919,8 @@ int bt_mesh_cfg_mod_sub_overwrite(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubOverwrite"); + return mod_sub(param, OP_MOD_SUB_OVERWRITE, elem_addr, sub_addr, mod_id, cid); } @@ -843,13 +930,15 @@ static int mod_sub_va(bt_mesh_client_common_param_t *param, uint32_t op, { BLE_MESH_MODEL_BUF_DEFINE(msg, op, 22); + BT_DBG("ModSubVa"); + if (!label) { BT_ERR("Invalid label uuid"); return -EINVAL; } - BT_DBG("elem_addr 0x%04x label %s", elem_addr, bt_hex(label, 16)); - BT_DBG("mod_id 0x%04x cid 0x%04x", mod_id, cid); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + BT_DBG("Label %s", bt_hex(label, 16)); bt_mesh_model_msg_init(&msg, op); net_buf_simple_add_le16(&msg, elem_addr); @@ -866,6 +955,8 @@ int bt_mesh_cfg_mod_sub_va_add(bt_mesh_client_common_param_t *param, uint16_t elem_addr, const uint8_t label[16], uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubVaAdd"); + return mod_sub_va(param, OP_MOD_SUB_VA_ADD, elem_addr, label, mod_id, cid); } @@ -873,6 +964,8 @@ int bt_mesh_cfg_mod_sub_va_del(bt_mesh_client_common_param_t *param, uint16_t elem_addr, const uint8_t label[16], uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubVaDel"); + return mod_sub_va(param, OP_MOD_SUB_VA_DEL, elem_addr, label, mod_id, cid); } @@ -880,6 +973,8 @@ int bt_mesh_cfg_mod_sub_va_overwrite(bt_mesh_client_common_param_t *param, uint16_t elem_addr, const uint8_t label[16], uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubVaOverwrite"); + return mod_sub_va(param, OP_MOD_SUB_VA_OVERWRITE, elem_addr, label, mod_id, cid); } @@ -888,6 +983,9 @@ int bt_mesh_cfg_mod_pub_get(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_GET, 6); + BT_DBG("ModPubGet"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_GET); net_buf_simple_add_le16(&msg, elem_addr); if (cid != BLE_MESH_CID_NVAL) { @@ -904,11 +1002,17 @@ int bt_mesh_cfg_mod_pub_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_SET, 13); + BT_DBG("ModPubSet"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + if (!pub) { BT_ERR("Invalid model pub set"); return -EINVAL; } + BT_DBG("Addr 0x%04x AppIdx 0x%04x TTL %u Period 0x%02x Transmit 0x%02x", + pub->addr, pub->app_idx, pub->ttl, pub->period, pub->transmit); + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_SET); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_le16(&msg, pub->addr); @@ -929,11 +1033,15 @@ int bt_mesh_cfg_hb_sub_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_SUB_SET, 5); + BT_DBG("HbSubSet"); + if (!sub) { BT_ERR("Invalid heartbeat sub set"); return -EINVAL; } + BT_DBG("Src 0x%04x Dst 0x%04x Period 0x%02x", sub->src, sub->dst, sub->period); + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_SUB_SET); net_buf_simple_add_le16(&msg, sub->src); net_buf_simple_add_le16(&msg, sub->dst); @@ -944,6 +1052,8 @@ int bt_mesh_cfg_hb_sub_set(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_hb_sub_get(bt_mesh_client_common_param_t *param) { + BT_DBG("HbSubGet"); + return send_msg_with_none(param, OP_HEARTBEAT_SUB_GET); } @@ -952,11 +1062,16 @@ int bt_mesh_cfg_hb_pub_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_PUB_SET, 9); + BT_DBG("HbPubSet"); + if (!pub) { BT_ERR("Invalid heartbeat pub set"); return -EINVAL; } + BT_DBG("Dst 0x%04x Count 0x%02x Period 0x%02x TTL %u Feat 0x%04x NetIdx 0x%04x", + pub->dst, pub->count, pub->period, pub->ttl, pub->feat, pub->net_idx); + bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_PUB_SET); net_buf_simple_add_le16(&msg, pub->dst); net_buf_simple_add_u8(&msg, pub->count); @@ -970,11 +1085,15 @@ int bt_mesh_cfg_hb_pub_set(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_hb_pub_get(bt_mesh_client_common_param_t *param) { + BT_DBG("HbPubGet"); + return send_msg_with_none(param, OP_HEARTBEAT_PUB_GET); } int bt_mesh_cfg_node_reset(bt_mesh_client_common_param_t *param) { + BT_DBG("NodeReset"); + return send_msg_with_none(param, OP_NODE_RESET); } @@ -985,11 +1104,18 @@ int bt_mesh_cfg_mod_pub_va_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_VA_SET, 27); + BT_DBG("ModPubVaSet"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + if (!label || !pub) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } + BT_DBG("Label %s", bt_hex(label, 16)); + BT_DBG("AppIdx 0x%04x TTL %u Period 0x%02x Transmit 0x%02x", + pub->app_idx, pub->ttl, pub->period, pub->transmit); + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_VA_SET); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_mem(&msg, label, 16); @@ -1010,6 +1136,9 @@ int bt_mesh_cfg_mod_sub_del_all(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_SUB_DEL_ALL, 6); + BT_DBG("ModSubDelAll"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + bt_mesh_model_msg_init(&msg, OP_MOD_SUB_DEL_ALL); net_buf_simple_add_le16(&msg, elem_addr); if (cid != BLE_MESH_CID_NVAL) { @@ -1038,12 +1167,18 @@ static int mod_sub_get(bt_mesh_client_common_param_t *param, uint32_t op, int bt_mesh_cfg_mod_sub_get(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t mod_id) { + BT_DBG("ModSubGet"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x", elem_addr, mod_id); + return mod_sub_get(param, OP_MOD_SUB_GET, elem_addr, mod_id, BLE_MESH_CID_NVAL); } int bt_mesh_cfg_mod_sub_get_vnd(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModSubGetVnd"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + if (cid == BLE_MESH_CID_NVAL) { BT_ERR("Invalid company id"); return -EINVAL; @@ -1056,11 +1191,15 @@ int bt_mesh_cfg_net_key_update(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_KEY_UPDATE, 18); + BT_DBG("NetKeyUpdate"); + if (!net_key) { BT_ERR("Invalid NetKey"); return -EINVAL; } + BT_DBG("NetIdx 0x%04x NetKey %s", net_idx, bt_hex(net_key, 16)); + bt_mesh_model_msg_init(&msg, OP_NET_KEY_UPDATE); net_buf_simple_add_le16(&msg, net_idx); net_buf_simple_add_mem(&msg, net_key, 16); @@ -1070,11 +1209,15 @@ int bt_mesh_cfg_net_key_update(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_net_key_delete(bt_mesh_client_common_param_t *param, uint16_t net_idx) { + BT_DBG("NetKeyDelete, NetIdx 0x%04x", net_idx); + return send_msg_with_le16(param, OP_NET_KEY_DEL, net_idx); } int bt_mesh_cfg_net_key_get(bt_mesh_client_common_param_t *param) { + BT_DBG("NetKeyGet"); + return send_msg_with_none(param, OP_NET_KEY_GET); } @@ -1084,11 +1227,16 @@ int bt_mesh_cfg_app_key_update(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_UPDATE, 19); + BT_DBG("AppKeyUpdate"); + if (!app_key) { BT_ERR("Invalid AppKey"); return -EINVAL; } + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x AppKey %s", + net_idx, app_idx, bt_hex(app_key, 16)); + bt_mesh_model_msg_init(&msg, OP_APP_KEY_UPDATE); key_idx_pack(&msg, net_idx, app_idx); net_buf_simple_add_mem(&msg, app_key, 16); @@ -1101,6 +1249,8 @@ int bt_mesh_cfg_app_key_delete(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_DEL, 3); + BT_DBG("AppKeyDelete, NetIdx 0x%04x AppIdx 0x%04x", net_idx, app_idx); + bt_mesh_model_msg_init(&msg, OP_APP_KEY_DEL); key_idx_pack(&msg, net_idx, app_idx); @@ -1109,11 +1259,15 @@ int bt_mesh_cfg_app_key_delete(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_app_key_get(bt_mesh_client_common_param_t *param, uint16_t net_idx) { + BT_DBG("AppKeyGet, NetIdx 0x%04x", net_idx); + return send_msg_with_le16(param, OP_APP_KEY_GET, net_idx); } int bt_mesh_cfg_node_identity_get(bt_mesh_client_common_param_t *param, uint16_t net_idx) { + BT_DBG("NodeIdentityGet, NetIdx 0x%04x", net_idx); + return send_msg_with_le16(param, OP_NODE_IDENTITY_GET, net_idx); } @@ -1122,6 +1276,8 @@ int bt_mesh_cfg_node_identity_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_IDENTITY_SET, 3); + BT_DBG("NodeIdentitySet, NetIdx 0x%04x Identity 0x%02x", net_idx, identity); + if (identity > 0x02) { BT_ERR("Invalid node identity 0x%02x", identity); return -EINVAL; @@ -1140,6 +1296,10 @@ int bt_mesh_cfg_mod_app_unbind(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_APP_UNBIND, 8); + BT_DBG("ModAppUnbind"); + BT_DBG("ElemAddr 0x%04x AppIdx 0x%04x ModID 0x%04x CID 0x%04x", + elem_addr, app_idx, mod_id, cid); + bt_mesh_model_msg_init(&msg, OP_MOD_APP_UNBIND); net_buf_simple_add_le16(&msg, elem_addr); net_buf_simple_add_le16(&msg, app_idx); @@ -1169,21 +1329,29 @@ static int mod_app_get(bt_mesh_client_common_param_t *param, uint32_t op, int bt_mesh_cfg_mod_app_get(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t mod_id) { + BT_DBG("ModAppGet, ElemAddr 0x%04x ModID 0x%04x", elem_addr, mod_id); + return mod_app_get(param, OP_SIG_MOD_APP_GET, elem_addr, mod_id, BLE_MESH_CID_NVAL); } int bt_mesh_cfg_mod_app_get_vnd(bt_mesh_client_common_param_t *param, uint16_t elem_addr, uint16_t mod_id, uint16_t cid) { + BT_DBG("ModAppGetVnd"); + BT_DBG("ElemAddr 0x%04x ModID 0x%04x CID 0x%04x", elem_addr, mod_id, cid); + if (cid == BLE_MESH_CID_NVAL) { BT_ERR("Invalid company id"); return -EINVAL; } + return mod_app_get(param, OP_VND_MOD_APP_GET, elem_addr, mod_id, cid); } int bt_mesh_cfg_kr_phase_get(bt_mesh_client_common_param_t *param, uint16_t net_idx) { + BT_DBG("KrPhaseGet, NetIdx 0x%04x", net_idx); + return send_msg_with_le16(param, OP_KRP_GET, net_idx); } @@ -1192,6 +1360,8 @@ int bt_mesh_cfg_kr_phase_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_KRP_SET, 3); + BT_DBG("KrPhaseSet, NetIdx 0x%04x Transition 0x%02x", net_idx, transition); + if (transition > 0x03) { BT_ERR("Invalid kr phase transition 0x%02x", transition); return -EINVAL; @@ -1206,16 +1376,22 @@ int bt_mesh_cfg_kr_phase_set(bt_mesh_client_common_param_t *param, int bt_mesh_cfg_lpn_timeout_get(bt_mesh_client_common_param_t *param, uint16_t lpn_addr) { + BT_DBG("LPNTimeoutGet, LPN 0x%04x", lpn_addr); + return send_msg_with_le16(param, OP_LPN_TIMEOUT_GET, lpn_addr); } int bt_mesh_cfg_net_transmit_get(bt_mesh_client_common_param_t *param) { + BT_DBG("NetTransmitGet"); + return send_msg_with_none(param, OP_NET_TRANSMIT_GET); } int bt_mesh_cfg_net_transmit_set(bt_mesh_client_common_param_t *param, uint8_t transmit) { + BT_DBG("NetTransmitSet, Transmit 0x%02x", transmit); + return send_msg_with_u8(param, OP_NET_TRANSMIT_SET, transmit); } @@ -1224,6 +1400,8 @@ static int cfg_cli_init(struct bt_mesh_model *model) config_internal_data_t *internal = NULL; bt_mesh_config_client_t *client = NULL; + BT_DBG("CfgCliInit"); + if (!model) { BT_ERR("Invalid Configuration Client model"); return -EINVAL; @@ -1271,6 +1449,8 @@ static int cfg_cli_deinit(struct bt_mesh_model *model) { bt_mesh_config_client_t *client = NULL; + BT_DBG("CfgCliDeinit"); + if (!model) { BT_ERR("Invalid Configuration Client model"); return -EINVAL; diff --git a/components/bt/esp_ble_mesh/core/cfg_srv.c b/components/bt/esp_ble_mesh/core/cfg_srv.c index fe605939a5..84cdb59b3a 100644 --- a/components/bt/esp_ble_mesh/core/cfg_srv.c +++ b/components/bt/esp_ble_mesh/core/cfg_srv.c @@ -32,7 +32,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #define DEFAULT_TTL 7 @@ -66,6 +66,9 @@ static uint8_t bt_mesh_comp_page_check(uint8_t page, bool largest) static inline uint16_t get_comp_elem_size(struct bt_mesh_elem *elem) { + BT_DBG("GetCompElemSize, ModelCount %u VndModelCount %u", + elem->model_count, elem->vnd_model_count); + return (4 + elem->model_count * 2 + elem->vnd_model_count * 4); } @@ -77,6 +80,8 @@ static uint16_t get_comp_data_size(const struct bt_mesh_comp *comp) size += get_comp_elem_size(&(comp->elem[i])); } + BT_DBG("GetCompDataSize, Size %u", size); + return size; } @@ -119,6 +124,7 @@ static void get_comp_data(struct net_buf_simple *buf, */ if (full_element && net_buf_simple_tailroom(buf) < get_comp_elem_size(elem)) { + BT_WARN("NoRoomForElementModelList"); return; } @@ -137,6 +143,8 @@ static void get_comp_data(struct net_buf_simple *buf, net_buf_simple_add_le16(buf, model->vnd.id); } } + + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); } static int fetch_comp_data(struct net_buf_simple *buf, @@ -155,7 +163,7 @@ static int fetch_comp_data(struct net_buf_simple *buf, if (net_buf_simple_tailroom(buf) < 10 || size - offset > net_buf_simple_tailroom(buf)) { BT_ERR("Too small buffer for comp data %d, %d, expected %d", - page, buf->size, size - offset); + page, buf->size, size - offset); return -EINVAL; } @@ -183,6 +191,9 @@ static int bt_mesh_get_comp_data(struct net_buf_simple *buf, uint8_t page, uint16_t offset, bool full_element) { + BT_DBG("FetchCompData, Page %u Offset %u FullElement %u", + page, offset, full_element); + if (page == 0) { return fetch_comp_data(buf, comp_0, page, offset, full_element); } @@ -199,9 +210,10 @@ static void comp_data_get(struct bt_mesh_model *model, struct net_buf_simple *sdu = NULL; uint8_t page = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("CompDataGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); /* TODO: * @@ -268,14 +280,17 @@ static void comp_data_get(struct bt_mesh_model *model, } static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, - struct net_buf_simple *buf, bool *vnd) + struct net_buf_simple *buf, + bool *vnd) { uint16_t company = 0U, id = 0U; + BT_DBG("GetModel, Len %u", buf->len); + if (buf->len < 4) { id = net_buf_simple_pull_le16(buf); - BT_DBG("ID 0x%04x addr 0x%04x", id, elem->addr); + BT_DBG("ID 0x%04x ElemAddr 0x%04x", id, elem->addr); *vnd = false; @@ -285,42 +300,49 @@ static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, company = net_buf_simple_pull_le16(buf); id = net_buf_simple_pull_le16(buf); - BT_DBG("Company 0x%04x ID 0x%04x addr 0x%04x", company, id, - elem->addr); + BT_DBG("CID 0x%04x ID 0x%04x Addr 0x%04x", company, id, elem->addr); *vnd = true; return bt_mesh_model_find_vnd(elem, company, id); } -static bool mod_pub_app_key_bound(struct bt_mesh_model *model, - uint16_t app_idx) +static bool mod_pub_app_key_bound(struct bt_mesh_model *model, uint16_t app_idx) { int i; + BT_DBG("ModPubAppKeyBound, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(model->keys); i++) { if (model->keys[i] == app_idx) { return true; } } - BT_ERR("AppKey(0x%02x) not bound to this model", app_idx); + BT_ERR("AppKeyNotBound, AppIdx 0x%04x", app_idx); return false; } static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, - uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, uint8_t period, - uint8_t retransmit, bool store) + uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, + uint8_t period, uint8_t retransmit, bool store) { + BT_DBG("_ModPubSet"); + BT_DBG("Addr 0x%04x AppIdx 0x%04x TTL %u Period 0x%02x Retransmit 0x%02x Store %u", + pub_addr, app_idx, ttl, period, retransmit, store); + if (!model->pub) { + BT_DBG("StatusNvalPubParam"); return STATUS_NVAL_PUB_PARAM; } if (!IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && cred_flag) { + BT_DBG("StatusFeatNotSupp"); return STATUS_FEAT_NOT_SUPP; } if (!model->pub->update && period) { + BT_DBG("StatusNvalPubParam"); return STATUS_NVAL_PUB_PARAM; } @@ -353,6 +375,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, */ if (!bt_mesh_app_key_get(app_idx) || !mod_pub_app_key_bound(model, app_idx)) { + BT_DBG("StatusInvalidAppKey"); return STATUS_INVALID_APPKEY; } @@ -367,7 +390,8 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, int32_t period_ms; period_ms = bt_mesh_model_pub_period_get(model); - BT_DBG("period %u ms", period_ms); + + BT_DBG("PubPeriod %ld", period_ms); if (period_ms) { k_delayed_work_submit(&model->pub->timer, period_ms); @@ -387,9 +411,10 @@ static uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) { int i; - BT_DBG("model %p key_idx 0x%03x", model, key_idx); + BT_DBG("ModBind, KeyIdx 0x%04x", key_idx); if (!bt_mesh_app_key_get(key_idx)) { + BT_DBG("StatusInvalidAppKey"); return STATUS_INVALID_APPKEY; } @@ -412,6 +437,7 @@ static uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) } } + BT_DBG("StatusInsuffResources"); return STATUS_INSUFF_RESOURCES; } @@ -419,9 +445,10 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st { int i; - BT_DBG("model %p key_idx 0x%03x store %u", model, key_idx, store); + BT_DBG("ModUnbind, KeyIdx 0x%04x Store %u", key_idx, store); if (!bt_mesh_app_key_get(key_idx)) { + BT_DBG("StatusInvalidAppKey"); return STATUS_INVALID_APPKEY; } @@ -449,6 +476,8 @@ struct bt_mesh_app_key *bt_mesh_app_key_alloc(uint16_t app_idx) { int i; + BT_DBG("AppKeyAlloc, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; @@ -457,31 +486,36 @@ struct bt_mesh_app_key *bt_mesh_app_key_alloc(uint16_t app_idx) } } + BT_ERR("AppKeyFull"); return NULL; } -static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val[16], - bool update) +static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, + const uint8_t val[16], bool update) { struct bt_mesh_app_keys *keys = NULL; struct bt_mesh_app_key *key = NULL; struct bt_mesh_subnet *sub = NULL; - BT_DBG("net_idx 0x%04x app_idx %04x update %u val %s", + BT_DBG("AppKeySet"); + BT_DBG("NetIdx 0x%04x AppIdx %04x Update %u Val %s", net_idx, app_idx, update, bt_hex(val, 16)); sub = bt_mesh_subnet_get(net_idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); return STATUS_INVALID_NETKEY; } key = bt_mesh_app_key_get(app_idx); if (update) { if (!key) { + BT_DBG("StatusInvalidAppKey"); return STATUS_INVALID_APPKEY; } if (key->net_idx != net_idx) { + BT_DBG("StatusInvalidBinding"); return STATUS_INVALID_BINDING; } @@ -493,11 +527,13 @@ static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val * the AppKey value is different. */ if (sub->kr_phase != BLE_MESH_KR_PHASE_1) { + BT_DBG("StatusCannotUpdate"); return STATUS_CANNOT_UPDATE; } if (key->updated) { if (memcmp(keys->val, val, 16)) { + BT_DBG("StatusCannotUpdate"); return STATUS_CANNOT_UPDATE; } @@ -513,14 +549,17 @@ static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val } if (key->net_idx == net_idx) { + BT_DBG("StatusIdxAlreadyStored"); return STATUS_IDX_ALREADY_STORED; } + BT_DBG("StatusInvalidNetKey"); return STATUS_INVALID_NETKEY; } key = bt_mesh_app_key_alloc(app_idx); if (!key) { + BT_DBG("StatusInsuffResources"); return STATUS_INSUFF_RESOURCES; } @@ -532,17 +571,15 @@ static uint8_t app_key_set(uint16_t net_idx, uint16_t app_idx, const uint8_t val key->updated = false; } + BT_DBG("StatusStorageFail"); return STATUS_STORAGE_FAIL; } - BT_DBG("app_idx 0x%04x AID 0x%02x", app_idx, keys->id); - key->net_idx = net_idx; key->app_idx = app_idx; memcpy(keys->val, val, 16); if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing AppKey persistently"); bt_mesh_store_app_key(key); } @@ -559,14 +596,13 @@ static void app_key_add(struct bt_mesh_model *model, key_idx_unpack(buf, &key_net_idx, &key_app_idx); - BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); + BT_DBG("AppKeyAdd, NetIdx 0x%04x AppIdx 0x%04x", key_net_idx, key_app_idx); bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); status = app_key_set(key_net_idx, key_app_idx, buf->data, false); - BT_DBG("status 0x%02x", status); - net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_u8(&msg, status); key_idx_pack(&msg, key_net_idx, key_app_idx); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { @@ -594,14 +630,13 @@ static void app_key_update(struct bt_mesh_model *model, key_idx_unpack(buf, &key_net_idx, &key_app_idx); - BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); + BT_DBG("AppKeyUpdate, NetIdx 0x%04x AppIdx 0x%04x", key_net_idx, key_app_idx); bt_mesh_model_msg_init(&msg, OP_APP_KEY_STATUS); status = app_key_set(key_net_idx, key_app_idx, buf->data, true); - BT_DBG("status 0x%02x", status); - net_buf_simple_add_u8(&msg, status); + net_buf_simple_add_u8(&msg, status); key_idx_pack(&msg, key_net_idx, key_app_idx); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { @@ -628,6 +663,8 @@ static void _mod_unbind(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, { struct unbind_data *data = user_data; + BT_DBG("_ModUnbind, Vnd %u Primary %u", vnd, primary); + mod_unbind(mod, data->app_idx, data->store); } @@ -635,7 +672,7 @@ void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store) { struct unbind_data data = { .app_idx = key->app_idx, .store = store }; - BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store); + BT_DBG("AppKeyDel, AppIdx 0x%04x Store %u", key->app_idx, store); bt_mesh_model_foreach(_mod_unbind, &data); @@ -658,9 +695,10 @@ static void app_key_del(struct bt_mesh_model *model, key_idx_unpack(buf, &key_net_idx, &key_app_idx); - BT_DBG("AppIdx 0x%04x NetIdx 0x%04x", key_app_idx, key_net_idx); + BT_DBG("AppkeyDel, NetIdx 0x%04x AppIdx 0x%04x", key_net_idx, key_app_idx); if (!bt_mesh_subnet_get(key_net_idx)) { + BT_DBG("StatusInvalidNetKey"); status = STATUS_INVALID_NETKEY; goto send_status; } @@ -675,11 +713,13 @@ static void app_key_del(struct bt_mesh_model *model, } if (key->net_idx != key_net_idx) { + BT_DBG("StatusInvalidBinding"); status = STATUS_INVALID_BINDING; goto send_status; } bt_mesh_app_key_del(key, true); + status = STATUS_SUCCESS; send_status: @@ -703,7 +743,7 @@ send_status: } /* Index list length: 3 bytes for every pair and 2 bytes for an odd idx */ -#define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2) +#define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2) static void app_key_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, @@ -714,17 +754,20 @@ static void app_key_get(struct bt_mesh_model *model, uint16_t get_idx = 0U, i = 0U, prev = 0U; uint8_t status = 0U; + BT_DBG("AppkeyGet"); + get_idx = net_buf_simple_pull_le16(buf); if (get_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", get_idx); return; } - BT_DBG("idx 0x%04x", get_idx); + BT_DBG("GetIdx 0x%04x", get_idx); bt_mesh_model_msg_init(&msg, OP_APP_KEY_LIST); if (!bt_mesh_subnet_get(get_idx)) { + BT_DBG("StatusInvalidNetKey"); status = STATUS_INVALID_NETKEY; } else { status = STATUS_SUCCESS; @@ -738,6 +781,7 @@ static void app_key_get(struct bt_mesh_model *model, } prev = BLE_MESH_KEY_UNUSED; + for (i = 0U; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; @@ -770,9 +814,10 @@ static void beacon_get(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_BEACON_STATUS, 1); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("BeaconGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_BEACON_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_secure_beacon_get()); @@ -789,9 +834,10 @@ static void beacon_set(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_BEACON_STATUS, 1); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("BeaconSet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); if (!cfg) { BT_WARN("No Configuration Server context available"); @@ -828,9 +874,10 @@ static void default_ttl_get(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_DEFAULT_TTL_STATUS, 1); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("DefaultTTLGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_DEFAULT_TTL_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_default_ttl_get()); @@ -847,9 +894,10 @@ static void default_ttl_set(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_DEFAULT_TTL_STATUS, 1); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("DefaultTTLSet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); if (!cfg) { BT_WARN("No Configuration Server context available"); @@ -879,6 +927,8 @@ static void send_gatt_proxy_status(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_GATT_PROXY_STATUS, 1); + BT_DBG("SendGattProxyStatus"); + bt_mesh_model_msg_init(&msg, OP_GATT_PROXY_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_gatt_proxy_get()); @@ -891,9 +941,10 @@ static void gatt_proxy_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("GattProxyGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); send_gatt_proxy_status(model, ctx); } @@ -904,9 +955,10 @@ static void gatt_proxy_set(struct bt_mesh_model *model, { struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("GattProxySet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); if (buf->data[0] != 0x00 && buf->data[0] != 0x01) { BT_WARN("Invalid GATT Proxy value 0x%02x", buf->data[0]); @@ -923,7 +975,7 @@ static void gatt_proxy_set(struct bt_mesh_model *model, goto send_status; } - BT_DBG("GATT Proxy 0x%02x -> 0x%02x", cfg->gatt_proxy, buf->data[0]); + BT_DBG("GattProxy 0x%02x -> 0x%02x", cfg->gatt_proxy, buf->data[0]); if (cfg->gatt_proxy == buf->data[0]) { goto send_status; @@ -934,11 +986,11 @@ static void gatt_proxy_set(struct bt_mesh_model *model, #if CONFIG_BLE_MESH_PRB_SRV /* If the value of the GATT Proxy state of the node is 0x01 (see Table 4.21), * then the value of the Private GATT Proxy state shall be Disable (0x00). - */ + */ if (buf->data[0] == BLE_MESH_GATT_PROXY_ENABLED) { bt_mesh_disable_private_gatt_proxy(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ #if CONFIG_BLE_MESH_DF_SRV /* If the value of the GATT Proxy state of the node is 0x00, @@ -946,7 +998,7 @@ static void gatt_proxy_set(struct bt_mesh_model *model, * directed proxy use directed default shall be 0x02. */ bt_mesh_disable_directed_proxy_state(ctx->net_idx); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_store_cfg(); @@ -966,9 +1018,10 @@ static void net_transmit_get(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_TRANSMIT_STATUS, 1); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NetTransmitGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_NET_TRANSMIT_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_net_transmit_get()); @@ -985,11 +1038,13 @@ static void net_transmit_set(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_TRANSMIT_STATUS, 1); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NetTransmitSet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); - BT_DBG("Transmit 0x%02x (count %u interval %ums)", buf->data[0], + BT_DBG("Transmit 0x%02x Count %u Interval %u", + buf->data[0], BLE_MESH_TRANSMIT_COUNT(buf->data[0]), BLE_MESH_TRANSMIT_INT(buf->data[0])); @@ -1017,9 +1072,10 @@ static void relay_get(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_RELAY_STATUS, 2); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("RelayGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_RELAY_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_relay_get()); @@ -1037,9 +1093,10 @@ static void relay_set(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_RELAY_STATUS, 2); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("RelaySet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); if (!cfg) { BT_WARN("No Configuration Server context available"); @@ -1050,6 +1107,7 @@ static void relay_set(struct bt_mesh_model *model, change = false; } else { change = (cfg->relay != buf->data[0]); + cfg->relay = buf->data[0]; cfg->relay_retransmit = buf->data[1]; @@ -1058,9 +1116,8 @@ static void relay_set(struct bt_mesh_model *model, } } - BT_DBG("Relay 0x%02x (%s) xmit 0x%02x (count %u interval %u)", - cfg->relay, change ? "changed" : "not changed", - cfg->relay_retransmit, + BT_DBG("Relay 0x%02x Change %u Xmit 0x%02x Count %u Interval %u", + cfg->relay, change, cfg->relay_retransmit, BLE_MESH_TRANSMIT_COUNT(cfg->relay_retransmit), BLE_MESH_TRANSMIT_INT(cfg->relay_retransmit)); @@ -1089,6 +1146,10 @@ static void send_mod_pub_status(struct bt_mesh_model *cfg_mod, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_STATUS, 14); + BT_DBG("SendModPubStatus"); + BT_DBG("ElemAddr 0x%04x PubAddr 0x%04x Vnd %u Status 0x%02x", + elem_addr, pub_addr, vnd, status); + bt_mesh_model_msg_init(&msg, OP_MOD_PUB_STATUS); net_buf_simple_add_u8(&msg, status); @@ -1129,6 +1190,8 @@ static void mod_pub_get(struct bt_mesh_model *model, uint8_t *mod_id = NULL, status = 0U; bool vnd = false; + BT_DBG("ModPubGet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1137,10 +1200,11 @@ static void mod_pub_get(struct bt_mesh_model *model, mod_id = buf->data; - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1149,11 +1213,13 @@ static void mod_pub_get(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!mod->pub) { + BT_DBG("StatusNvalPubParam"); status = STATUS_NVAL_PUB_PARAM; goto send_status; } @@ -1162,8 +1228,7 @@ static void mod_pub_get(struct bt_mesh_model *model, status = STATUS_SUCCESS; send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, status, mod_id); } static void mod_pub_set(struct bt_mesh_model *model, @@ -1177,6 +1242,8 @@ static void mod_pub_set(struct bt_mesh_model *model, uint8_t *mod_id = NULL; bool vnd = false; + BT_DBG("ModPubSet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1198,16 +1265,18 @@ static void mod_pub_set(struct bt_mesh_model *model, retransmit = net_buf_simple_pull_u8(buf); mod_id = buf->data; - BT_DBG("elem_addr 0x%04x pub_addr 0x%04x cred_flag %u", + BT_DBG("ElemAddr 0x%04x PubAddr 0x%04x CredFlag %u", elem_addr, pub_addr, cred_flag); - BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x", + BT_DBG("PubAppIdx 0x%04x PubTTL %u PubPeriod 0x%02x", pub_app_idx, pub_ttl, pub_period); - BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit, + BT_DBG("Retransmit 0x%02x Count %u Interval %u", + retransmit, BLE_MESH_PUB_TRANSMIT_COUNT(retransmit), BLE_MESH_PUB_TRANSMIT_INT(retransmit)); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1216,6 +1285,7 @@ static void mod_pub_set(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } @@ -1224,8 +1294,7 @@ static void mod_pub_set(struct bt_mesh_model *model, pub_period, retransmit, true); send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, status, mod_id); if (status == STATUS_SUCCESS && mod->pub) { bt_mesh_cfg_server_state_change_t change = {0}; @@ -1245,6 +1314,8 @@ send_status: struct label *get_label(uint16_t index) { + BT_DBG("GetLabel, Index %u", index); + if (index >= ARRAY_SIZE(labels)) { return NULL; } @@ -1255,7 +1326,10 @@ struct label *get_label(uint16_t index) #if CONFIG_BLE_MESH_LABEL_COUNT > 0 static inline void va_store(struct label *store) { + BT_DBG("VaStore"); + bt_mesh_atomic_set_bit(store->flags, BLE_MESH_VA_CHANGED); + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_store_label(); } @@ -1267,6 +1341,8 @@ static struct label *va_find(const uint8_t *label_uuid, struct label *match = NULL; int i; + BT_DBG("VaFind"); + if (free_slot != NULL) { *free_slot = NULL; } @@ -1291,10 +1367,14 @@ uint8_t va_add(uint8_t *label_uuid, uint16_t *addr) { struct label *update = NULL, *free_slot = NULL; + BT_DBG("VaAdd"); + update = va_find(label_uuid, &free_slot); if (update) { update->ref++; + va_store(update); + if (addr) { *addr = update->addr; } @@ -1302,10 +1382,12 @@ uint8_t va_add(uint8_t *label_uuid, uint16_t *addr) } if (!free_slot) { + BT_DBG("StatusInsuffResources"); return STATUS_INSUFF_RESOURCES; } if (bt_mesh_virtual_addr(label_uuid, addr) < 0) { + BT_DBG("StatusUnspecified"); return STATUS_UNSPECIFIED; } @@ -1321,6 +1403,8 @@ uint8_t va_del(uint8_t *label_uuid, uint16_t *addr) { struct label *update = NULL; + BT_DBG("VaDel"); + update = va_find(label_uuid, NULL); if (update) { update->ref--; @@ -1337,6 +1421,7 @@ uint8_t va_del(uint8_t *label_uuid, uint16_t *addr) *addr = BLE_MESH_ADDR_UNASSIGNED; } + BT_DBG("StatusCannotRemove"); return STATUS_CANNOT_REMOVE; } @@ -1346,6 +1431,8 @@ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) size_t clear_count = 0U; int i; + BT_DBG("ModSubListClear"); + /* Unref stored labels related to this model */ for (i = 0, clear_count = 0; i < ARRAY_SIZE(mod->groups); i++) { if (!BLE_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) { @@ -1365,10 +1452,12 @@ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) if (label_uuid) { va_del(label_uuid, NULL); } else { - BT_ERR("Label UUID not found"); + BT_ERR("LabelUUIDNotFound"); } } + BT_DBG("ClearCount %u", clear_count); + return clear_count; } @@ -1384,6 +1473,8 @@ static void mod_pub_va_set(struct bt_mesh_model *model, uint8_t *mod_id = NULL; bool vnd = false; + BT_DBG("ModPubVaSet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1404,15 +1495,17 @@ static void mod_pub_va_set(struct bt_mesh_model *model, retransmit = net_buf_simple_pull_u8(buf); mod_id = buf->data; - BT_DBG("elem_addr 0x%04x cred_flag %u", elem_addr, cred_flag); - BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x", + BT_DBG("ElemAddr 0x%04x CredFlag %u", elem_addr, cred_flag); + BT_DBG("PubAppIdx 0x%04x PubTTL %u PubPeriod 0x%02x", pub_app_idx, pub_ttl, pub_period); - BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit, + BT_DBG("Retransmit 0x%02x Count %u Interval %u", + retransmit, BLE_MESH_PUB_TRANSMIT_COUNT(retransmit), BLE_MESH_PUB_TRANSMIT_INT(retransmit)); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); pub_addr = 0U; @@ -1422,6 +1515,7 @@ static void mod_pub_va_set(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); pub_addr = 0U; status = STATUS_INVALID_MODEL; goto send_status; @@ -1434,15 +1528,16 @@ static void mod_pub_va_set(struct bt_mesh_model *model, } send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, status, mod_id); } -#else +#else /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) { size_t clear_count = 0U; int i; + BT_DBG("ModSubListClear"); + /* Unref stored labels related to this model */ for (i = 0, clear_count = 0; i < ARRAY_SIZE(mod->groups); i++) { if (mod->groups[i] != BLE_MESH_ADDR_UNASSIGNED) { @@ -1451,6 +1546,8 @@ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) } } + BT_DBG("ClearCount %u", clear_count); + return clear_count; } @@ -1458,12 +1555,14 @@ static void mod_pub_va_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + uint16_t elem_addr = 0U, pub_addr = 0U; uint8_t *mod_id = NULL, status = 0U; struct bt_mesh_model *mod = NULL; struct bt_mesh_elem *elem = NULL; - uint16_t elem_addr = 0U, pub_addr = 0U; bool vnd = false; + BT_DBG("ModPubVaSet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1473,10 +1572,11 @@ static void mod_pub_va_set(struct bt_mesh_model *model, net_buf_simple_pull(buf, 16); mod_id = net_buf_simple_pull(buf, 4); - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1485,33 +1585,37 @@ static void mod_pub_va_set(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!mod->pub) { + BT_DBG("StatusNvalPubParam"); status = STATUS_NVAL_PUB_PARAM; goto send_status; } pub_addr = mod->pub->addr; + + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, status, mod_id); } #endif /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ static void send_mod_sub_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t status, - uint16_t elem_addr, uint16_t sub_addr, uint8_t *mod_id, - bool vnd) + uint16_t elem_addr, uint16_t sub_addr, + uint8_t *mod_id, bool vnd) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_SUB_STATUS, 9); - BT_DBG("status 0x%02x elem_addr 0x%04x sub_addr 0x%04x", status, - elem_addr, sub_addr); + BT_DBG("SendModSubStatus"); + BT_DBG("Status 0x%02x ElemAddr 0x%04x SubAddr 0x%04x Vnd %u", + status, elem_addr, sub_addr, vnd); bt_mesh_model_msg_init(&msg, OP_MOD_SUB_STATUS); @@ -1542,6 +1646,8 @@ static void mod_sub_add(struct bt_mesh_model *model, bool vnd = false; int i; + BT_DBG("ModSubAdd"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1550,12 +1656,13 @@ static void mod_sub_add(struct bt_mesh_model *model, sub_addr = net_buf_simple_pull_le16(buf); - BT_DBG("elem_addr 0x%04x, sub_addr 0x%04x", elem_addr, sub_addr); + BT_DBG("ElemAddr 0x%04x SubAddr 0x%04x", elem_addr, sub_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1564,18 +1671,19 @@ static void mod_sub_add(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!BLE_MESH_ADDR_IS_GROUP(sub_addr)) { + BT_DBG("StatusInvalidAddress"); status = STATUS_INVALID_ADDRESS; goto send_status; } if (bt_mesh_model_find_group(mod, sub_addr)) { /* Tried to add existing subscription */ - BT_DBG("found existing subscription"); status = STATUS_SUCCESS; goto send_status; } @@ -1592,6 +1700,7 @@ static void mod_sub_add(struct bt_mesh_model *model, } if (i == ARRAY_SIZE(mod->groups)) { + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; } else { status = STATUS_SUCCESS; @@ -1606,12 +1715,11 @@ static void mod_sub_add(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); #if CONFIG_BLE_MESH_DF_SRV bt_mesh_directed_forwarding_node_solicitation(mod, bt_mesh_subnet_get(ctx->net_idx)); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ if (status == STATUS_SUCCESS) { bt_mesh_cfg_server_state_change_t change = {0}; @@ -1636,6 +1744,8 @@ static void mod_sub_del(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubDel"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1644,12 +1754,13 @@ static void mod_sub_del(struct bt_mesh_model *model, sub_addr = net_buf_simple_pull_le16(buf); - BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr); + BT_DBG("ElemAddr 0x%04x SubAddr 0x%04x", elem_addr, sub_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1658,11 +1769,13 @@ static void mod_sub_del(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!BLE_MESH_ADDR_IS_GROUP(sub_addr)) { + BT_DBG("StatusInvalidAddress"); status = STATUS_INVALID_ADDRESS; goto send_status; } @@ -1686,8 +1799,7 @@ static void mod_sub_del(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); if (status == STATUS_SUCCESS) { bt_mesh_cfg_server_state_change_t change = {0}; @@ -1711,6 +1823,8 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubOverwrite"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1719,12 +1833,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, sub_addr = net_buf_simple_pull_le16(buf); - BT_DBG("elem_addr 0x%04x sub_addr 0x%04x", elem_addr, sub_addr); + BT_DBG("ElemAddr 0x%04x SubAddr 0x%04x", elem_addr, sub_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1733,11 +1848,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } if (!BLE_MESH_ADDR_IS_GROUP(sub_addr)) { + BT_DBG("StatusInvalidAddress"); status = STATUS_INVALID_ADDRESS; goto send_status; } @@ -1760,13 +1877,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, bt_mesh_lpn_group_add(sub_addr); } } else { + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } static void mod_sub_del_all(struct bt_mesh_model *model, @@ -1780,18 +1897,21 @@ static void mod_sub_del_all(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubDelAll"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); return; } - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -1800,6 +1920,7 @@ static void mod_sub_del_all(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } @@ -1832,6 +1953,8 @@ static void mod_sub_get(struct bt_mesh_model *model, uint16_t addr = 0U, id = 0U; int i; + BT_DBG("ModSubGet"); + addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { BT_ERR("Prohibited element address 0x%04x", addr); @@ -1840,12 +1963,13 @@ static void mod_sub_get(struct bt_mesh_model *model, id = net_buf_simple_pull_le16(buf); - BT_DBG("addr 0x%04x id 0x%04x", addr, id); + BT_DBG("ElemAddr 0x%04x ID 0x%04x", addr, id); bt_mesh_model_msg_init(&msg, OP_MOD_SUB_LIST); elem = bt_mesh_elem_find(addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); net_buf_simple_add_u8(&msg, STATUS_INVALID_ADDRESS); net_buf_simple_add_le16(&msg, addr); net_buf_simple_add_le16(&msg, id); @@ -1854,6 +1978,7 @@ static void mod_sub_get(struct bt_mesh_model *model, mod = bt_mesh_model_find(elem, id); if (!mod) { + BT_DBG("StatusInvalidModel"); net_buf_simple_add_u8(&msg, STATUS_INVALID_MODEL); net_buf_simple_add_le16(&msg, addr); net_buf_simple_add_le16(&msg, id); @@ -1888,6 +2013,8 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, uint16_t company = 0U, addr = 0U, id = 0U; int i; + BT_DBG("ModSubGetVnd"); + addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(addr)) { BT_ERR("Prohibited element address 0x%04x", addr); @@ -1897,12 +2024,13 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, company = net_buf_simple_pull_le16(buf); id = net_buf_simple_pull_le16(buf); - BT_DBG("addr 0x%04x company 0x%04x id 0x%04x", addr, company, id); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x", addr, company, id); bt_mesh_model_msg_init(&msg, OP_MOD_SUB_LIST_VND); elem = bt_mesh_elem_find(addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); net_buf_simple_add_u8(&msg, STATUS_INVALID_ADDRESS); net_buf_simple_add_le16(&msg, addr); net_buf_simple_add_le16(&msg, company); @@ -1912,6 +2040,7 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, mod = bt_mesh_model_find_vnd(elem, company, id); if (!mod) { + BT_DBG("StatusInvalidModel"); net_buf_simple_add_u8(&msg, STATUS_INVALID_MODEL); net_buf_simple_add_le16(&msg, addr); net_buf_simple_add_le16(&msg, company); @@ -1951,6 +2080,8 @@ static void mod_sub_va_add(struct bt_mesh_model *model, bool vnd = false; int i; + BT_DBG("ModSubVaAdd"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -1959,11 +2090,12 @@ static void mod_sub_va_add(struct bt_mesh_model *model, label_uuid = net_buf_simple_pull_mem(buf, 16); - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); sub_addr = BLE_MESH_ADDR_UNASSIGNED; @@ -1973,6 +2105,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); sub_addr = BLE_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_MODEL; goto send_status; @@ -2001,6 +2134,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model, } if (i == ARRAY_SIZE(mod->groups)) { + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; } else { if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { @@ -2015,8 +2149,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } static void mod_sub_va_del(struct bt_mesh_model *model, @@ -2032,6 +2165,8 @@ static void mod_sub_va_del(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaDel"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2040,12 +2175,13 @@ static void mod_sub_va_del(struct bt_mesh_model *model, label_uuid = net_buf_simple_pull_mem(buf, 16); - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); sub_addr = BLE_MESH_ADDR_UNASSIGNED; @@ -2055,6 +2191,7 @@ static void mod_sub_va_del(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); sub_addr = BLE_MESH_ADDR_UNASSIGNED; status = STATUS_INVALID_MODEL; goto send_status; @@ -2079,12 +2216,12 @@ static void mod_sub_va_del(struct bt_mesh_model *model, status = STATUS_SUCCESS; } else { + BT_DBG("StatusCannotRemove"); status = STATUS_CANNOT_REMOVE; } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } static void mod_sub_va_overwrite(struct bt_mesh_model *model, @@ -2099,6 +2236,8 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaOverwrite"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2107,12 +2246,13 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, label_uuid = net_buf_simple_pull_mem(buf, 16); - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); mod_id = buf->data; elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2121,6 +2261,7 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } @@ -2145,14 +2286,14 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, } } } else { + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } -#else +#else /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ static void mod_sub_va_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) @@ -2164,6 +2305,8 @@ static void mod_sub_va_add(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaAdd"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2176,6 +2319,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2184,10 +2328,12 @@ static void mod_sub_va_add(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; send_status: @@ -2205,6 +2351,8 @@ static void mod_sub_va_del(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaDel"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2217,16 +2365,19 @@ static void mod_sub_va_del(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; goto send_status; } if (!get_model(elem, buf, &vnd)) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; send_status: @@ -2244,6 +2395,8 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, uint8_t status = 0U; bool vnd = false; + BT_DBG("ModSubVaOverwrite"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2256,16 +2409,19 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; goto send_status; } if (!get_model(elem, buf, &vnd)) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } + BT_DBG("StatusInsuffResources"); status = STATUS_INSUFF_RESOURCES; send_status: @@ -2280,6 +2436,8 @@ static void send_net_key_status(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NET_KEY_STATUS, 3); + BT_DBG("SendNetKeyStatus"); + bt_mesh_model_msg_init(&msg, OP_NET_KEY_STATUS); net_buf_simple_add_u8(&msg, status); @@ -2298,13 +2456,15 @@ static void net_key_add(struct bt_mesh_model *model, uint16_t idx = 0U; int err = 0; + BT_DBG("NetKeyAdd"); + idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); return; } - BT_DBG("idx 0x%04x", idx); + BT_DBG("NetIdx 0x%04x", idx); sub = bt_mesh_subnet_get(idx); if (!sub) { @@ -2318,8 +2478,8 @@ static void net_key_add(struct bt_mesh_model *model, } if (!sub) { - send_net_key_status(model, ctx, idx, - STATUS_INSUFF_RESOURCES); + BT_DBG("StatusInsuffResources"); + send_net_key_status(model, ctx, idx, STATUS_INSUFF_RESOURCES); return; } } @@ -2329,6 +2489,7 @@ static void net_key_add(struct bt_mesh_model *model, uint8_t status = 0U; if (memcmp(buf->data, sub->keys[0].net, 16)) { + BT_DBG("StatusIdxAlreadyStored"); status = STATUS_IDX_ALREADY_STORED; } else { status = STATUS_SUCCESS; @@ -2340,6 +2501,7 @@ static void net_key_add(struct bt_mesh_model *model, err = bt_mesh_net_keys_create(&sub->keys[0], buf->data); if (err) { + BT_DBG("StatusUnspecified"); send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED); return; } @@ -2347,7 +2509,6 @@ static void net_key_add(struct bt_mesh_model *model, sub->net_idx = idx; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing NetKey persistently"); bt_mesh_store_subnet(sub); } @@ -2368,7 +2529,7 @@ static void net_key_add(struct bt_mesh_model *model, if (sub->directed_proxy != BLE_MESH_DIRECTED_PROXY_NOT_SUPPORTED) { bt_mesh_directed_proxy_server_directed_proxy_caps_send(sub, false); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV && CONFIG_BLE_MESH_SUPPORT_DIRECTED_PROXY */ bt_mesh_adv_update(); } else { @@ -2381,7 +2542,7 @@ static void net_key_add(struct bt_mesh_model *model, if (bt_mesh_directed_forwarding_sub_init(sub)) { BT_ERR("Failed to init subnet for directed forward"); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ bt_mesh_cfg_server_state_change_t change = {0}; change.cfg_netkey_add.net_idx = sub->net_idx; @@ -2398,16 +2559,19 @@ static void net_key_update(struct bt_mesh_model *model, uint16_t idx = 0U; int err = 0; + BT_DBG("NetKeyUpdate"); + idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); return; } - BT_DBG("idx 0x%04x", idx); + BT_DBG("NetIdx 0x%04x", idx); sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); send_net_key_status(model, ctx, idx, STATUS_INVALID_NETKEY); return; } @@ -2432,6 +2596,7 @@ static void net_key_update(struct bt_mesh_model *model, /* fall through */ case BLE_MESH_KR_PHASE_2: case BLE_MESH_KR_PHASE_3: + BT_DBG("StatusCannotUpdate"); send_net_key_status(model, ctx, idx, STATUS_CANNOT_UPDATE); return; } @@ -2443,6 +2608,7 @@ static void net_key_update(struct bt_mesh_model *model, } if (err) { + BT_DBG("StatusUnspecified"); send_net_key_status(model, ctx, idx, STATUS_UNSPECIFIED); return; } @@ -2450,7 +2616,6 @@ static void net_key_update(struct bt_mesh_model *model, sub->kr_phase = BLE_MESH_KR_PHASE_1; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing NetKey persistently"); bt_mesh_store_subnet(sub); } @@ -2467,6 +2632,8 @@ static void net_key_update(struct bt_mesh_model *model, static void hb_pub_disable(struct bt_mesh_cfg_srv *cfg) { + BT_DBG("HbPubDisable"); + cfg->hb_pub.dst = BLE_MESH_ADDR_UNASSIGNED; cfg->hb_pub.count = 0U; cfg->hb_pub.ttl = 0U; @@ -2483,13 +2650,15 @@ static void net_key_del(struct bt_mesh_model *model, uint16_t del_idx = 0U; uint8_t status = 0U; + BT_DBG("NetKeyDel"); + del_idx = net_buf_simple_pull_le16(buf); if (del_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", del_idx); return; } - BT_DBG("idx 0x%04x", del_idx); + BT_DBG("NetIdx 0x%04x", del_idx); sub = bt_mesh_subnet_get(del_idx); if (!sub) { @@ -2504,6 +2673,7 @@ static void net_key_del(struct bt_mesh_model *model, * The NetKey List must contain a minimum of one NetKey. */ if (ctx->net_idx == del_idx) { + BT_DBG("StatusCannotRemove"); status = STATUS_CANNOT_REMOVE; goto send_status; } @@ -2525,8 +2695,8 @@ static void net_key_del(struct bt_mesh_model *model, #if CONFIG_BLE_MESH_SETTINGS bt_mesh_clear_directed_forwarding_table_data(del_idx); -#endif -#endif +#endif /* CONFIG_BLE_MESH_SETTINGS */ +#endif /* CONFIG_BLE_MESH_DF_SRV && CONFIG_BLE_MESH_SUPPORT_DIRECTED_PROXY */ bt_mesh_subnet_del(sub, true); status = STATUS_SUCCESS; @@ -2540,11 +2710,11 @@ static void net_key_del(struct bt_mesh_model *model, * Index of the deleted NetKey are removed. */ bt_mesh_delete_netkey_in_bridge_table(del_idx); -#endif /* CONFIG_BLE_MESH_BRC_SRV */ +#endif /* CONFIG_BLE_MESH_BRC_SRV */ #if CONFIG_BLE_MESH_RPR_SRV bt_mesh_rpr_srv_netkey_del(del_idx); -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ send_status: send_net_key_status(model, ctx, del_idx, status); @@ -2565,6 +2735,8 @@ static void net_key_get(struct bt_mesh_model *model, IDX_LEN(CONFIG_BLE_MESH_SUBNET_COUNT)); uint16_t prev = 0U, i = 0U; + BT_DBG("NetKeyGet"); + bt_mesh_model_msg_init(&msg, OP_NET_KEY_LIST); prev = BLE_MESH_KEY_UNUSED; @@ -2602,9 +2774,10 @@ static void node_identity_get(struct bt_mesh_model *model, uint8_t node_id = 0U; uint16_t idx = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NodeIdentityGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -2616,6 +2789,7 @@ static void node_identity_get(struct bt_mesh_model *model, sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); net_buf_simple_add_u8(&msg, STATUS_INVALID_NETKEY); node_id = 0x00; } else { @@ -2640,9 +2814,10 @@ static void node_identity_set(struct bt_mesh_model *model, uint8_t node_id = 0U; uint16_t idx = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("NodeIdentitySet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -2660,6 +2835,7 @@ static void node_identity_set(struct bt_mesh_model *model, sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); net_buf_simple_add_u8(&msg, STATUS_INVALID_NETKEY); net_buf_simple_add_le16(&msg, idx); net_buf_simple_add_u8(&msg, node_id); @@ -2672,7 +2848,8 @@ static void node_identity_set(struct bt_mesh_model *model, * Identity state shall be Disable (0x00). */ bt_mesh_proxy_private_identity_disable(); -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ + bt_mesh_proxy_server_identity_start(sub); } else { bt_mesh_proxy_server_identity_stop(sub); @@ -2697,6 +2874,10 @@ static void create_mod_app_status(struct net_buf_simple *msg, { bt_mesh_model_msg_init(msg, OP_MOD_APP_STATUS); + BT_DBG("CreateModAppStatus"); + BT_DBG("ElemAddr 0x%04x AppIdx 0x%04x Status 0x%02x Vnd %u", + elem_addr, app_idx, status, vnd); + net_buf_simple_add_u8(msg, status); net_buf_simple_add_le16(msg, elem_addr); net_buf_simple_add_le16(msg, app_idx); @@ -2719,6 +2900,8 @@ static void mod_app_bind(struct bt_mesh_model *model, uint8_t *mod_id = NULL, status = 0U; bool vnd = false; + BT_DBG("ModAppBind"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2730,6 +2913,7 @@ static void mod_app_bind(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2738,24 +2922,24 @@ static void mod_app_bind(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } /* Configuration Server only allows device key based access */ if (model == mod) { - BT_ERR("Client tried to bind AppKey to Configuration Model"); + BT_ERR("StatusCannotBind"); status = STATUS_CANNOT_BIND; goto send_status; } status = mod_bind(mod, key_app_idx); - BT_INFO("bind app key %#x on mode %#x", key_app_idx, mod->id); + BT_INFO("AppIdx 0x%04x ID 0x%04x", key_app_idx, mod->id); + send_status: - BT_DBG("status 0x%02x", status); - create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, - mod_id); + create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, mod_id); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Config Model App Bind Status"); @@ -2783,6 +2967,8 @@ static void mod_app_unbind(struct bt_mesh_model *model, uint8_t *mod_id = NULL, status = 0U; bool vnd = false; + BT_DBG("ModAppUnbind"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2794,6 +2980,7 @@ static void mod_app_unbind(struct bt_mesh_model *model, elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2802,6 +2989,7 @@ static void mod_app_unbind(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_status; } @@ -2809,9 +2997,7 @@ static void mod_app_unbind(struct bt_mesh_model *model, status = mod_unbind(mod, key_app_idx, true); send_status: - BT_DBG("status 0x%02x", status); - create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, - mod_id); + create_mod_app_status(&msg, mod, vnd, elem_addr, key_app_idx, status, mod_id); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Config Model App Unbind Status"); @@ -2828,23 +3014,22 @@ send_status: } } -#define KEY_LIST_LEN (CONFIG_BLE_MESH_MODEL_KEY_COUNT * 2) +#define KEY_LIST_LEN (CONFIG_BLE_MESH_MODEL_KEY_COUNT * 2) static void mod_app_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - NET_BUF_SIMPLE_DEFINE(msg, - MAX(BLE_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, - 9 + KEY_LIST_LEN), - BLE_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST, - 9 + KEY_LIST_LEN))); + NET_BUF_SIMPLE_DEFINE(msg, MAX(BLE_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, 9 + KEY_LIST_LEN), + BLE_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST, 9 + KEY_LIST_LEN))); struct bt_mesh_model *mod = NULL; struct bt_mesh_elem *elem = NULL; uint8_t *mod_id = NULL, status = 0U; uint16_t elem_addr = 0U; bool vnd = false; + BT_DBG("ModAppGet"); + elem_addr = net_buf_simple_pull_le16(buf); if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_ERR("Prohibited element address 0x%04x", elem_addr); @@ -2853,10 +3038,11 @@ static void mod_app_get(struct bt_mesh_model *model, mod_id = buf->data; - BT_DBG("elem_addr 0x%04x", elem_addr); + BT_DBG("ElemAddr 0x%04x", elem_addr); elem = bt_mesh_elem_find(elem_addr); if (!elem) { + BT_DBG("StatusInvalidAddress"); mod = NULL; vnd = (buf->len == 4U); status = STATUS_INVALID_ADDRESS; @@ -2865,6 +3051,7 @@ static void mod_app_get(struct bt_mesh_model *model, mod = get_model(elem, buf, &vnd); if (!mod) { + BT_DBG("StatusInvalidModel"); status = STATUS_INVALID_MODEL; goto send_list; } @@ -2908,15 +3095,15 @@ static void node_reset(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_NODE_RESET_STATUS, 0); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); - + BT_DBG("NodeReset"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_NODE_RESET_STATUS); - /* Send the response first since we won't have any keys left to - * send it later. + /* Send the response first since we won't have any keys + * left to send it later. */ if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { BT_ERR("Unable to send Config Node Reset Status"); @@ -2933,6 +3120,8 @@ static void send_friend_status(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_FRIEND_STATUS, 1); struct bt_mesh_cfg_srv *cfg = model->user_data; + BT_DBG("SendFrndStatus"); + bt_mesh_model_msg_init(&msg, OP_FRIEND_STATUS); net_buf_simple_add_u8(&msg, cfg->frnd); @@ -2945,9 +3134,10 @@ static void friend_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("FrndGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); send_friend_status(model, ctx); } @@ -2958,9 +3148,10 @@ static void friend_set(struct bt_mesh_model *model, { struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("FrndSet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); if (buf->data[0] != 0x00 && buf->data[0] != 0x01) { BT_WARN("Invalid Friend value 0x%02x", buf->data[0]); @@ -2972,7 +3163,7 @@ static void friend_set(struct bt_mesh_model *model, goto send_status; } - BT_DBG("Friend 0x%02x -> 0x%02x", cfg->frnd, buf->data[0]); + BT_DBG("Frnd 0x%02x -> 0x%02x", cfg->frnd, buf->data[0]); if (cfg->frnd == buf->data[0]) { goto send_status; @@ -2993,7 +3184,7 @@ static void friend_set(struct bt_mesh_model *model, * then the value of the directed friend state shall be 0x00. */ bt_mesh_disable_directed_friend_state(ctx->net_idx); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV && CONFIG_BLE_MESH_FRIEND */ } } @@ -3016,7 +3207,8 @@ static void lpn_timeout_get(struct bt_mesh_model *model, lpn_addr = net_buf_simple_pull_le16(buf); - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x lpn_addr 0x%02x", + BT_DBG("LPNTimeoutGet"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x LPN 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr, lpn_addr); if (!BLE_MESH_ADDR_IS_UNICAST(lpn_addr)) { @@ -3054,6 +3246,8 @@ static void send_krp_status(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_KRP_STATUS, 4); + BT_DBG("SendKrpStatus"); + bt_mesh_model_msg_init(&msg, OP_KRP_STATUS); net_buf_simple_add_u8(&msg, status); @@ -3071,20 +3265,22 @@ static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct bt_mesh_subnet *sub = NULL; uint16_t idx = 0U; + BT_DBG("KrpGet"); + idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); return; } - BT_DBG("idx 0x%04x", idx); + BT_DBG("NetIdx 0x%04x", idx); sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY); } else { - send_krp_status(model, ctx, idx, sub->kr_phase, - STATUS_SUCCESS); + send_krp_status(model, ctx, idx, sub->kr_phase, STATUS_SUCCESS); } } @@ -3095,6 +3291,8 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, uint8_t phase = 0U; uint16_t idx = 0U; + BT_DBG("KrpSet"); + idx = net_buf_simple_pull_le16(buf); phase = net_buf_simple_pull_u8(buf); @@ -3103,15 +3301,16 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, return; } - BT_DBG("idx 0x%04x transition 0x%02x", idx, phase); + BT_DBG("NetIdx 0x%04x Phase 0x%02x", idx, phase); sub = bt_mesh_subnet_get(idx); if (!sub) { + BT_DBG("StatusInvalidNetKey"); send_krp_status(model, ctx, idx, 0x00, STATUS_INVALID_NETKEY); return; } - BT_DBG("%u -> %u", sub->kr_phase, phase); + BT_DBG("KrPhase %u -> %u", sub->kr_phase, phase); if (phase < BLE_MESH_KR_PHASE_2 || phase > BLE_MESH_KR_PHASE_3 || (sub->kr_phase == BLE_MESH_KR_NORMAL && @@ -3126,7 +3325,6 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, sub->kr_flag = 1; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing kr phase persistently"); bt_mesh_store_subnet(sub); } @@ -3157,6 +3355,8 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, static uint8_t hb_log(uint16_t val) { + BT_DBG("HbLog, Val 0x%04x", val); + switch (val) { case 0x0000: return 0x00; @@ -3169,6 +3369,8 @@ static uint8_t hb_log(uint16_t val) static uint8_t hb_pub_count_log(uint16_t val) { + BT_DBG("HbPubCountLog, Val 0x%04x", val); + switch (val) { case 0x0000: return 0x00; @@ -3183,6 +3385,8 @@ static uint8_t hb_pub_count_log(uint16_t val) static uint16_t hb_pwr2(uint8_t val, uint8_t sub) { + BT_DBG("HbPwr2, Val 0x%02x Sub 0x%02x", val, sub); + switch (val) { case 0x00: return 0x0000; @@ -3210,7 +3414,7 @@ static void hb_pub_send_status(struct bt_mesh_model *model, BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_PUB_STATUS, 10); struct bt_mesh_cfg_srv *cfg = model->user_data; - BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status); + BT_DBG("HbPubSendStatus, Src 0x%04x Status 0x%02x", ctx->addr, status); bt_mesh_model_msg_init(&msg, OP_HEARTBEAT_PUB_STATUS); @@ -3239,7 +3443,7 @@ static void heartbeat_pub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("src 0x%04x", ctx->addr); + BT_DBG("HeartbeatPubGet, Src 0x%04x", ctx->addr); hb_pub_send_status(model, ctx, STATUS_SUCCESS, NULL); } @@ -3253,27 +3457,30 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, uint16_t dst = 0U, feat = 0U, idx = 0U; uint8_t status = 0U; - BT_DBG("src 0x%04x", ctx->addr); + BT_DBG("HeartbeatPubSet, Src 0x%04x", ctx->addr); dst = sys_le16_to_cpu(param->dst); /* All other address types but virtual are valid */ if (BLE_MESH_ADDR_IS_VIRTUAL(dst)) { + BT_DBG("StatusInvalidAddress"); status = STATUS_INVALID_ADDRESS; goto failed; } if (param->count_log > 0x11 && param->count_log != 0xff) { + BT_DBG("StatusCannotSet"); status = STATUS_CANNOT_SET; goto failed; } if (param->period_log > 0x11) { + BT_DBG("StatusCannotSet"); status = STATUS_CANNOT_SET; goto failed; } if (param->ttl > BLE_MESH_TTL_MAX && param->ttl != BLE_MESH_TTL_DEFAULT) { - BT_ERR("Invalid TTL value 0x%02x", param->ttl); + BT_ERR("InvalidTTL %u", param->ttl); return; } @@ -3281,11 +3488,12 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, idx = sys_le16_to_cpu(param->net_idx); if (idx > 0xfff) { - BT_ERR("Invalid NetKeyIndex 0x%04x", idx); + BT_ERR("InvalidNetIdx 0x%04x", idx); return; } if (!bt_mesh_subnet_get(idx)) { + BT_DBG("StatusInvalidNetKey"); status = STATUS_INVALID_NETKEY; goto failed; } @@ -3302,7 +3510,7 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, cfg->hb_pub.count = hb_pwr2(param->count_log, 1); cfg->hb_pub.ttl = param->ttl; - BT_DBG("period %u ms", hb_pwr2(param->period_log, 1) * 1000U); + BT_DBG("Period %u", hb_pwr2(param->period_log, 1) * 1000U); /* Note: Send heartbeat message here will cause wrong heartbeat status message */ #if 0 @@ -3343,14 +3551,15 @@ failed: } static void hb_sub_send_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, uint8_t status) + struct bt_mesh_msg_ctx *ctx, + uint8_t status) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_SUB_STATUS, 9); struct bt_mesh_cfg_srv *cfg = model->user_data; uint16_t period = 0U; int64_t uptime = 0; - BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status); + BT_DBG("HbSubSendStatus, Src 0x%04x Status 0x%02x", ctx->addr, status); uptime = k_uptime_get(); if (uptime > cfg->hb_sub.expiry) { @@ -3378,7 +3587,7 @@ static void heartbeat_sub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { - BT_DBG("src 0x%04x", ctx->addr); + BT_DBG("HeartbeatSubGet, Src 0x%04x", ctx->addr); hb_sub_send_status(model, ctx, STATUS_SUCCESS); } @@ -3392,13 +3601,13 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, uint8_t sub_period = 0U; int32_t period_ms = 0; - BT_DBG("src 0x%04x", ctx->addr); + BT_DBG("HeartbeatSubSet, Src 0x%04x", ctx->addr); sub_src = net_buf_simple_pull_le16(buf); sub_dst = net_buf_simple_pull_le16(buf); sub_period = net_buf_simple_pull_u8(buf); - BT_DBG("sub_src 0x%04x sub_dst 0x%04x period 0x%02x", + BT_DBG("SubSrc 0x%04x SubDst 0x%04x SubPeriod 0x%02x", sub_src, sub_dst, sub_period); if (sub_src != BLE_MESH_ADDR_UNASSIGNED && @@ -3447,7 +3656,7 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, /* Let the transport layer know it needs to handle this address */ bt_mesh_set_hb_sub_dst(cfg->hb_sub.dst); - BT_DBG("period_ms %u", period_ms); + BT_DBG("Period %ld", period_ms); if (period_ms) { cfg->hb_sub.expiry = k_uptime_get() + period_ms; @@ -3529,7 +3738,8 @@ static void hb_publish(struct k_work *work) struct bt_mesh_subnet *sub = NULL; uint16_t period_ms = 0U; - BT_DBG("hb_pub.count: %u", cfg->hb_pub.count); + BT_DBG("HbPublish, NetIdx 0x%04x Count %u", + cfg->hb_pub.net_idx, cfg->hb_pub.count); sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx); if (!sub) { @@ -3557,15 +3767,20 @@ static void hb_publish(struct k_work *work) static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg) { + BT_DBG("ConfIsValid"); + if (cfg->relay > 0x02) { + BT_ERR("InvalidRelay 0x%02x", cfg->relay); return false; } if (cfg->beacon > 0x01) { + BT_ERR("InvalidBeacon 0x%02x", cfg->beacon); return false; } if (cfg->default_ttl > BLE_MESH_TTL_MAX) { + BT_ERR("InvalidDefaultTTL 0x%02x", cfg->default_ttl); return false; } @@ -3591,6 +3806,8 @@ static int cfg_srv_init(struct bt_mesh_model *model) { struct bt_mesh_cfg_srv *cfg = model->user_data; + BT_DBG("CfgSrvInit"); + if (!bt_mesh_model_in_primary(model)) { BT_ERR("Configuration Server only allowed in primary element"); return -EINVAL; @@ -3602,7 +3819,6 @@ static int cfg_srv_init(struct bt_mesh_model *model) } if (!conf_is_valid(cfg)) { - BT_ERR("Invalid values in configuration"); return -EINVAL; } @@ -3637,6 +3853,8 @@ static int cfg_srv_deinit(struct bt_mesh_model *model) { struct bt_mesh_cfg_srv *cfg = model->user_data; + BT_DBG("CfgSrvDeinit"); + if (!bt_mesh_model_in_primary(model)) { BT_ERR("Configuration Server only allowed in primary element"); return -EINVAL; @@ -3682,6 +3900,9 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, clear_count = mod_sub_list_clear(mod); + BT_DBG("ModReset, ClearCount %lu Vnd %u Primary %u", + clear_count, vnd, primary); + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && clear_count && store) { bt_mesh_store_mod_sub(mod); } @@ -3689,6 +3910,8 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, void bt_mesh_mod_sub_reset(bool store) { + BT_DBG("ModSubReset, Store %u", store); + bt_mesh_model_foreach(mod_reset, &store); } @@ -3697,6 +3920,8 @@ void bt_mesh_cfg_reset(bool store) struct bt_mesh_cfg_srv *cfg = conf; int i; + BT_DBG("CfgReset, Store %u", store); + if (!cfg) { return; } @@ -3725,7 +3950,11 @@ void bt_mesh_cfg_reset(bool store) uint8_t bt_mesh_net_transmit_get(void) { + BT_DBG("NetTransmitGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->net_transmit); + return conf->net_transmit; } @@ -3734,6 +3963,8 @@ uint8_t bt_mesh_net_transmit_get(void) void bt_mesh_relay_local_set(bool enable) { + BT_DBG("RelayLocalSet, Enable %u", enable); + if (conf && conf->relay != BLE_MESH_RELAY_NOT_SUPPORTED) { if (enable) { conf->relay = BLE_MESH_RELAY_ENABLED; @@ -3745,7 +3976,11 @@ void bt_mesh_relay_local_set(bool enable) uint8_t bt_mesh_relay_get(void) { + BT_DBG("RelayGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->relay); + return conf->relay; } @@ -3754,8 +3989,11 @@ uint8_t bt_mesh_relay_get(void) uint8_t bt_mesh_friend_get(void) { + BT_DBG("FrndGet"); + if (conf) { - BT_DBG("conf %p conf->frnd 0x%02x", conf, conf->frnd); + BT_DBG("Val 0x%02x", conf->frnd); + return conf->frnd; } @@ -3764,7 +4002,11 @@ uint8_t bt_mesh_friend_get(void) uint8_t bt_mesh_relay_retransmit_get(void) { + BT_DBG("RelayRetransmitGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->relay_retransmit); + return conf->relay_retransmit; } @@ -3773,7 +4015,11 @@ uint8_t bt_mesh_relay_retransmit_get(void) uint8_t bt_mesh_secure_beacon_get(void) { + BT_DBG("SecureBeaconGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->beacon); + return conf->beacon; } @@ -3782,7 +4028,11 @@ uint8_t bt_mesh_secure_beacon_get(void) uint8_t bt_mesh_gatt_proxy_get(void) { + BT_DBG("GattProxyGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->gatt_proxy); + return conf->gatt_proxy; } @@ -3791,7 +4041,11 @@ uint8_t bt_mesh_gatt_proxy_get(void) uint8_t bt_mesh_default_ttl_get(void) { + BT_DBG("DefaultTTLGet"); + if (conf) { + BT_DBG("Val 0x%02x", conf->default_ttl); + return conf->default_ttl; } @@ -3802,7 +4056,7 @@ uint8_t *bt_mesh_label_uuid_get(uint16_t addr) { int i; - BT_DBG("addr 0x%04x", addr); + BT_DBG("LabelUUIDGet, Addr 0x%04x", addr); for (i = 0; i < ARRAY_SIZE(labels); i++) { if (labels[i].addr == addr) { @@ -3819,6 +4073,8 @@ uint8_t *bt_mesh_label_uuid_get(uint16_t addr) struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void) { + BT_DBG("HbPubGet"); + if (!conf) { return NULL; } @@ -3828,6 +4084,8 @@ struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void) void bt_mesh_hb_pub_disable(void) { + BT_DBG("HbPubDisable"); + if (conf) { hb_pub_disable(conf); } @@ -3835,6 +4093,8 @@ void bt_mesh_hb_pub_disable(void) struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void) { + BT_DBG("CfgGet, Conf %p", conf); + return conf; } @@ -3842,7 +4102,7 @@ void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store) { int i; - BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store); + BT_DBG("SubnetDel, NetIdx 0x%04x Store %u", sub->net_idx, store); if (conf && conf->hb_pub.net_idx == sub->net_idx) { hb_pub_disable(conf); diff --git a/components/bt/esp_ble_mesh/core/crypto.c b/components/bt/esp_ble_mesh/core/crypto.c index 2577c65efb..3adba0be1f 100644 --- a/components/bt/esp_ble_mesh/core/crypto.c +++ b/components/bt/esp_ble_mesh/core/crypto.c @@ -24,9 +24,9 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ -#define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) +#define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4) #define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4) int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg, @@ -369,10 +369,11 @@ static int bt_mesh_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], size_t i = 0U, j = 0U; int err = 0; - BT_DBG("key %s", bt_hex(key, 16)); - BT_DBG("nonce %s", bt_hex(nonce, 13)); - BT_DBG("msg (len %u) %s", msg_len, bt_hex(msg, msg_len)); - BT_DBG("aad_len %u mic_size %u", aad_len, mic_size); + BT_DBG("CCMEncrypt"); + BT_DBG("Key %s", bt_hex(key, 16)); + BT_DBG("Nonce %s", bt_hex(nonce, 13)); + BT_DBG("Len %u: %s", msg_len, bt_hex(msg, msg_len)); + BT_DBG("AADLen %u MicSize %u", aad_len, mic_size); /* Unsupported AAD size */ if (aad_len >= 0xff00) { @@ -580,7 +581,7 @@ int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, uint8_t tmp[16] = {0}; int err = 0, i; - BT_DBG("IVIndex %u, PrivacyKey %s", iv_index, bt_hex(privacy_key, 16)); + BT_DBG("IVIndex %lu PrivacyKey %s", iv_index, bt_hex(privacy_key, 16)); sys_put_be32(iv_index, &priv_rand[5]); memcpy(&priv_rand[9], &pdu[7], 7); @@ -589,6 +590,7 @@ int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index, err = bt_mesh_encrypt_be(privacy_key, priv_rand, tmp); if (err) { + BT_ERR("NetObfuscateFailed (%d)", err); return err; } @@ -606,9 +608,9 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, uint8_t nonce[13] = {0}; int err = 0; - BT_DBG("IVIndex %u EncKey %s mic_len %u", iv_index, bt_hex(key, 16), - mic_len); - BT_DBG("PDU (len %u) %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("IVIndex %u EncKey %s MicLen %u proxy %u/%u", + iv_index, bt_hex(key, 16), mic_len, proxy, proxy_solic); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); #if CONFIG_BLE_MESH_PROXY if (proxy) { @@ -633,6 +635,8 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf, NULL, 0, &buf->data[7], mic_len); if (!err) { net_buf_simple_add(buf, mic_len); + } else { + BT_ERR("NetEncryptFailed (%d)", err); } return err; @@ -643,10 +647,11 @@ int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, { uint8_t mic_len = NET_MIC_LEN(buf->data); uint8_t nonce[13] = {0}; + int err; - BT_DBG("PDU (%u bytes) %s", buf->len, bt_hex(buf->data, buf->len)); - BT_DBG("iv_index %u, key %s mic_len %u", iv_index, bt_hex(key, 16), - mic_len); + BT_DBG("IVIndex %u EncKey %s MicLen %u proxy %u/%u", + iv_index, bt_hex(key, 16), mic_len, proxy, proxy_solic); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); #if CONFIG_BLE_MESH_PROXY if (proxy) { @@ -669,8 +674,13 @@ int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf, buf->len -= mic_len; - return bt_mesh_ccm_decrypt(key, nonce, &buf->data[7], buf->len - 7, - NULL, 0, &buf->data[7], mic_len); + err = bt_mesh_ccm_decrypt(key, nonce, &buf->data[7], buf->len - 7, + NULL, 0, &buf->data[7], mic_len); + if (err) { + BT_ERR("NetDecrypt failed (%d)", err); + } + + return err; } static void create_app_nonce(uint8_t nonce[13], bool dev_key, uint8_t aszmic, @@ -698,14 +708,15 @@ int bt_mesh_app_encrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, uint8_t nonce[13] = {0}; int err = 0; + BT_DBG("AppEncrypt"); BT_DBG("AppKey %s", bt_hex(key, 16)); - BT_DBG("dev_key %u src 0x%04x dst 0x%04x", dev_key, src, dst); - BT_DBG("seq_num 0x%08x iv_index 0x%08x", seq_num, iv_index); - BT_DBG("Clear: %s", bt_hex(buf->data, buf->len)); + BT_DBG("DevKey %u Src 0x%04x Dst 0x%04x", dev_key, src, dst); + BT_DBG("SeqNum 0x%08lx IVIndex 0x%08lx", seq_num, iv_index); + BT_DBG("Data %u %s", buf->len, bt_hex(buf->data, buf->len)); create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index); - BT_DBG("Nonce %s", bt_hex(nonce, 13)); + BT_DBG("Nonce %s", bt_hex(nonce, 13)); err = bt_mesh_ccm_encrypt(key, nonce, buf->data, buf->len, ad, ad ? 16 : 0, buf->data, APP_MIC_LEN(aszmic)); @@ -725,12 +736,12 @@ int bt_mesh_app_decrypt(const uint8_t key[16], bool dev_key, uint8_t aszmic, uint8_t nonce[13] = {0}; int err = 0; - BT_DBG("EncData (len %u) %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("EncData %u %s", buf->len, bt_hex(buf->data, buf->len)); create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index); BT_DBG("AppKey %s", bt_hex(key, 16)); - BT_DBG("Nonce %s", bt_hex(nonce, 13)); + BT_DBG("Nonce %s", bt_hex(nonce, 13)); err = bt_mesh_ccm_decrypt(key, nonce, buf->data, buf->len, ad, ad ? 16 : 0, out->data, APP_MIC_LEN(aszmic)); diff --git a/components/bt/esp_ble_mesh/core/ext_adv.c b/components/bt/esp_ble_mesh/core/ext_adv.c index 4958e5686d..37000ce73e 100644 --- a/components/bt/esp_ble_mesh/core/ext_adv.c +++ b/components/bt/esp_ble_mesh/core/ext_adv.c @@ -44,8 +44,8 @@ static int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) uint8_t is_ext_adv = false; #endif - BT_DBG("type %u len %u: %s", BLE_MESH_ADV(buf)->type, - buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("ExtAdvSend, Type %u", BLE_MESH_ADV(buf)->type); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); switch (BLE_MESH_ADV(buf)->type) { #if CONFIG_BLE_MESH_EXT_ADV @@ -65,13 +65,13 @@ static int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) case BLE_MESH_ADV_DATA: #if CONFIG_BLE_MESH_FRIEND case BLE_MESH_ADV_FRIEND: -#endif +#endif /* CONFIG_BLE_MESH_FRIEND */ #if CONFIG_BLE_MESH_RELAY_ADV_BUF case BLE_MESH_ADV_RELAY_DATA: -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX case BLE_MESH_ADV_PROXY_SOLIC: -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ case BLE_MESH_ADV_BEACON: case BLE_MESH_ADV_URI: { #if CONFIG_BLE_MESH_EXT_ADV @@ -127,19 +127,23 @@ static int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX if (BLE_MESH_ADV(buf)->type == BLE_MESH_ADV_PROXY_SOLIC) { bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); + struct bt_mesh_adv_data solic_ad[2] = { BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x59, 0x18), BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, buf->data, buf->len), }; - err = bt_le_ext_adv_start(CONFIG_BLE_MESH_ADV_INST_ID, ¶m, solic_ad, ARRAY_SIZE(solic_ad), NULL, 0); + + err = bt_le_ext_adv_start(CONFIG_BLE_MESH_ADV_INST_ID, ¶m, + solic_ad, ARRAY_SIZE(solic_ad), NULL, 0); } else -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_TX */ { bt_mesh_adv_buf_ref_debug(__func__, buf, 4U, BLE_MESH_BUF_REF_SMALL); + err = bt_le_ext_adv_start(inst->id, ¶m, &ad, 1, NULL, 0); } - } break; + #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV case BLE_MESH_ADV_BLE: struct bt_mesh_ble_adv_data data = {0}; @@ -152,8 +156,8 @@ static int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) } BT_DBG("interval %dms, duration %dms, period %dms, count %d", - ADV_SCAN_INT(tx->param.interval), tx->param.duration, - tx->param.period, tx->param.count); + ADV_SCAN_INT(tx->param.interval), tx->param.duration, + tx->param.period, tx->param.count); data.adv_data_len = tx->buf->data[0]; if (data.adv_data_len) { @@ -169,9 +173,10 @@ static int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) err = bt_mesh_ble_ext_adv_start(inst->id, &tx->param, &data); break; -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + default: - BT_ERR("Error Type"); + BT_ERR("InvalidAdvType %u", BLE_MESH_ADV(buf)->type); break; } @@ -182,12 +187,15 @@ static int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) } *adv_duration = duration; + BT_DBG("Advertising started. %u ms", duration); return 0; } static int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_msg_t *msg) { + BT_DBG("FindValidMsgFromQueue"); + while(uxQueueMessagesWaiting(msg_queue->handle)) { xQueueReceive(msg_queue->handle, msg, K_WAIT(K_FOREVER)); @@ -197,11 +205,16 @@ static int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_msg_t * */ assert(msg->arg); + BT_DBG("Buf %p Relay %u Busy %u", + BLE_MESH_MSG_NET_BUF(msg), msg->relay, + !!bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(BLE_MESH_MSG_NET_BUF(msg)))); + /* If the message is cancelled for advertising, then continue to retrieve the next * message from that queue. */ if (!bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(BLE_MESH_MSG_NET_BUF(msg)), 1, 0)) { bt_mesh_adv_buf_ref_debug(__func__, BLE_MESH_MSG_NET_BUF(msg), 1U, BLE_MESH_BUF_REF_EQUAL); + /* Cancel the adv task's reference to this data packet. * Tips: * The reference of buffer by adv_task occurs when the buffer is pushed into @@ -225,11 +238,13 @@ static int find_valid_msg_from_queue(bt_mesh_queue_t *msg_queue, bt_mesh_msg_t * * BLE_MESH_RELAY_TIME_INTERVAL, this relay packet will not be sent. */ BT_DBG("Ignore relay packet"); + net_buf_unref(BLE_MESH_MSG_NET_BUF(msg)); msg->arg = NULL; continue; } -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ + break; } @@ -250,14 +265,18 @@ static int activate_idle_adv_instance(uint32_t *update_evts, uint16_t *min_durat uint32_t spt_mask = 0; uint32_t evts = 0; + BT_DBG("ActivateIdleAdvInst"); + #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER if (!adv_insts[BLE_MESH_ADV_PROXY_INST].busy) { BT_DBG("Mesh Proxy Advertising start"); + duration = bt_mesh_proxy_server_adv_start(); if (duration < cur_min_duration) { cur_min_duration = duration; } + adv_insts[BLE_MESH_ADV_PROXY_INST].busy = true; evts |= ADV_TASK_ADV_INST_EVT(adv_insts[BLE_MESH_ADV_PROXY_INST].id); } @@ -268,10 +287,11 @@ static int activate_idle_adv_instance(uint32_t *update_evts, uint16_t *min_durat if (instance->busy #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_SERVER - || unlikely(instance->id == CONFIG_BLE_MESH_PROXY_ADV_INST_ID) + CONFIG_BLE_MESH_GATT_PROXY_SERVER + || unlikely(instance->id == CONFIG_BLE_MESH_PROXY_ADV_INST_ID) #endif - ) { + ) { + BT_DBG("AdvInstSkipped, InstID %u Busy %u", instance->id, instance->busy); continue; } @@ -285,13 +305,13 @@ static int activate_idle_adv_instance(uint32_t *update_evts, uint16_t *min_durat /* If no new message in the queue, the *buf (aka: msg.arg) will be empty */ if (find_valid_msg_from_queue(msg_queue, &msg)) { - BT_DBG("no valid message for instance %d", instance->id); + BT_DBG("NoMsgForAdvInst, InstID %u", instance->id); continue; } instance->sending_buf = (struct net_buf *)msg.arg; + if (adv_send(instance, &duration)) { - BT_ERR("adv start failed"); /* When this adv instance fails to broadcast, it could be due to some * persistent issues, such as incorrect adv parameter settings, or it * could be due to some temporary issues, such as memory allocation @@ -301,11 +321,18 @@ static int activate_idle_adv_instance(uint32_t *update_evts, uint16_t *min_durat * instance and attempt to broadcast subsequent data again next time, * rather than disabling the adv instance. */ + BT_ERR("AdvSendFailed, InstID %u AdvType %u SptMask %08lx Buf %p", + instance->id, adv_type, instance->spt_mask, instance->sending_buf); + net_buf_unref(instance->sending_buf); instance->sending_buf = NULL; break; } + BT_DBG("Activate, InstID %u AdvType %u SptMask %08lx Buf %p Duration %u/%u", + instance->id, adv_type, instance->spt_mask, + instance->sending_buf, duration, cur_min_duration); + if (duration < cur_min_duration) { cur_min_duration = duration; } @@ -321,6 +348,9 @@ static int activate_idle_adv_instance(uint32_t *update_evts, uint16_t *min_durat } } + BT_DBG("ActivateEnd, Duration %u UpdateEvts %08lx Evts%08lx", + cur_min_duration, *update_evts, evts); + *min_duration = cur_min_duration; *update_evts |= evts; @@ -329,6 +359,8 @@ static int activate_idle_adv_instance(uint32_t *update_evts, uint16_t *min_durat static uint32_t received_adv_evts_handle(uint32_t recv_evts) { + BT_DBG("RecvAdvEvtsHandle, RecvEvts 0x%08lx", recv_evts); + if (!recv_evts) { return 0; } @@ -338,20 +370,25 @@ static uint32_t received_adv_evts_handle(uint32_t recv_evts) if (recv_evts & evt) { recv_evts &= ~evt; + #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ -CONFIG_BLE_MESH_GATT_PROXY_SERVER + CONFIG_BLE_MESH_GATT_PROXY_SERVER if (unlikely(i == BLE_MESH_ADV_PROXY_INST)) { BT_DBG("Mesh Proxy Advertising auto stop"); + bt_mesh_proxy_server_adv_flag_set(false); } else #endif { - /* adv_send_end maybe*/ - adv_send_end(0, BLE_MESH_ADV(adv_insts[i].sending_buf)->cb, BLE_MESH_ADV(adv_insts[i].sending_buf)->cb_data); + adv_send_end(0, BLE_MESH_ADV(adv_insts[i].sending_buf)->cb, + BLE_MESH_ADV(adv_insts[i].sending_buf)->cb_data); + bt_mesh_adv_buf_ref_debug(__func__, adv_insts[i].sending_buf, 4U, BLE_MESH_BUF_REF_SMALL); + net_buf_unref(adv_insts[i].sending_buf); adv_insts[i].sending_buf = NULL; } + adv_insts[i].busy = false; } } @@ -365,7 +402,7 @@ static void adv_thread(void *p) uint32_t recv_evts = 0; uint32_t wait_evts = 0; - BT_DBG("%s, starts", __func__); + BT_DBG("ExtAdvThread"); while (1) { adv_duration = K_FOREVER; @@ -375,6 +412,8 @@ static void adv_thread(void *p) bt_mesh_adv_task_wait(wait_evts, adv_duration, &recv_evts); + BT_DBG("WaitEvts %08lx RecvEvts %08lx", wait_evts, recv_evts); + wait_evts &= ~recv_evts; #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ @@ -400,17 +439,21 @@ static void adv_thread(void *p) recv_evts = received_adv_evts_handle(recv_evts); if (recv_evts) { - BT_ERR("Remain evts %08x to handle", recv_evts); + BT_ERR("RecvEvts %08lx", recv_evts); } } } void bt_mesh_adv_update(void) { + BT_DBG("ExtAdvUpdate"); + #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER BT_DBG("Mesh Proxy Advertising stopped manually"); + bt_mesh_proxy_server_adv_stop(); + if (adv_insts[BLE_MESH_ADV_PROXY_INST].busy) { bt_mesh_adv_task_wakeup(ADV_TASK_PROXY_ADV_UPD_EVT); } @@ -419,17 +462,19 @@ void bt_mesh_adv_update(void) void bt_mesh_adv_init(void) { + BT_DBG("ExtAdvInit"); + bt_mesh_adv_common_init(); adv_insts = bt_mesh_get_adv_insts_set(); #if CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_relay_adv_init(); -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV bt_mesh_ble_adv_init(); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ bt_mesh_adv_task_init(adv_thread); } @@ -437,6 +482,8 @@ void bt_mesh_adv_init(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_adv_deinit(void) { + BT_DBG("ExtAdvDeinit"); + bt_mesh_adv_task_deinit(); bt_mesh_adv_common_deinit(); @@ -445,10 +492,10 @@ void bt_mesh_adv_deinit(void) #if CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_relay_adv_deinit(); -#endif +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV bt_mesh_ble_adv_deinit(); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ } #endif /* CONFIG_BLE_MESH_DEINIT */ diff --git a/components/bt/esp_ble_mesh/core/ext_adv.h b/components/bt/esp_ble_mesh/core/ext_adv.h index 3d4820a8d6..eaa9c4f819 100644 --- a/components/bt/esp_ble_mesh/core/ext_adv.h +++ b/components/bt/esp_ble_mesh/core/ext_adv.h @@ -23,6 +23,7 @@ extern "C" { void bt_mesh_adv_update(void); void bt_mesh_adv_init(void); + void bt_mesh_adv_deinit(void); #ifdef __cplusplus diff --git a/components/bt/esp_ble_mesh/core/fast_prov.c b/components/bt/esp_ble_mesh/core/fast_prov.c index 049a12bb43..5d34db8a09 100644 --- a/components/bt/esp_ble_mesh/core/fast_prov.c +++ b/components/bt/esp_ble_mesh/core/fast_prov.c @@ -27,12 +27,15 @@ const uint8_t *bt_mesh_fast_prov_dev_key_get(uint16_t dst) { const uint8_t *key = NULL; + BT_DBG("FastProvDevKeyGet, Dst 0x%04x", dst); + if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { BT_ERR("Invalid unicast address 0x%04x", dst); return NULL; } if (bt_mesh_is_provisioner_en() == false) { + BT_DBG("NodeDevKey"); return bt_mesh.dev_key; } @@ -42,9 +45,11 @@ const uint8_t *bt_mesh_fast_prov_dev_key_get(uint16_t dst) */ key = bt_mesh_provisioner_dev_key_get(dst); if (key) { + BT_DBG("PvnrDevKey"); return key; } + BT_DBG("NodeDevKeyFinal"); return bt_mesh.dev_key; } @@ -53,9 +58,12 @@ struct bt_mesh_subnet *bt_mesh_fast_prov_subnet_get(uint16_t net_idx) struct bt_mesh_subnet *sub = NULL; int i; + BT_DBG("FastProvSubnetGet, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { sub = &bt_mesh.sub[i]; if (sub->net_idx == net_idx) { + BT_DBG("NodeSub"); return sub; } } @@ -63,10 +71,12 @@ struct bt_mesh_subnet *bt_mesh_fast_prov_subnet_get(uint16_t net_idx) for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { sub = bt_mesh.p_sub[i]; if (sub && sub->net_idx == net_idx) { + BT_DBG("PvnrSub"); return sub; } } + BT_DBG("NoSub"); return NULL; } @@ -75,10 +85,13 @@ struct bt_mesh_app_key *bt_mesh_fast_prov_app_key_find(uint16_t app_idx) struct bt_mesh_app_key *key = NULL; int i; + BT_DBG("FastProvAppKeyFind, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { key = &bt_mesh.app_keys[i]; if (key->net_idx != BLE_MESH_KEY_UNUSED && key->app_idx == app_idx) { + BT_DBG("NodeAppKey"); return key; } } @@ -87,15 +100,19 @@ struct bt_mesh_app_key *bt_mesh_fast_prov_app_key_find(uint16_t app_idx) key = bt_mesh.p_app_keys[i]; if (key && key->net_idx != BLE_MESH_KEY_UNUSED && key->app_idx == app_idx) { + BT_DBG("PvnrAppKey"); return key; } } + BT_DBG("NoAppKey"); return NULL; } uint8_t bt_mesh_set_fast_prov_net_idx(uint16_t net_idx) { + BT_DBG("SetFastProvNetIdx, NetIdx 0x%04x", net_idx); + /* Set net_idx for fast provisioning */ bt_mesh_provisioner_set_fast_prov_net_idx(net_idx); @@ -116,6 +133,8 @@ uint8_t bt_mesh_fast_prov_net_key_add(const uint8_t net_key[16]) net_idx = bt_mesh_provisioner_get_fast_prov_net_idx(); bt_mesh.p_net_idx_next = net_idx; + BT_DBG("FastProvNetKeyAdd, NetIdx 0x%04x", net_idx); + err = bt_mesh_provisioner_local_net_key_add(net_key, &net_idx); if (err) { BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); @@ -130,12 +149,16 @@ const uint8_t *bt_mesh_fast_prov_net_key_get(uint16_t net_idx) { struct bt_mesh_subnet *sub = NULL; + BT_DBG("FastProvNetKeyGet, NetIdx 0x%04x", net_idx); + sub = bt_mesh_fast_prov_subnet_get(net_idx); if (!sub) { BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); return NULL; } + BT_DBG("KrFlag %u", sub->kr_flag); + return (sub->kr_flag ? sub->keys[1].net : sub->keys[0].net); } @@ -143,17 +166,23 @@ const uint8_t *bt_mesh_get_fast_prov_app_key(uint16_t net_idx, uint16_t app_idx) { struct bt_mesh_app_key *key = NULL; + BT_DBG("GetFastProvAppKey, NetIdx 0x%04x AppIdx 0x%04x", net_idx, app_idx); + key = bt_mesh_fast_prov_app_key_find(app_idx); if (!key) { BT_ERR("Invalid AppKeyIndex 0x%04x", app_idx); return NULL; } + BT_DBG("KeyUpdated %u", key->updated); + return (key->updated ? key->keys[1].val : key->keys[0].val); } uint8_t bt_mesh_set_fast_prov_action(uint8_t action) { + BT_DBG("SetFastProvAction, Action %u", action); + if (!action || action > ACTION_EXIT) { return 0x01; } @@ -168,9 +197,11 @@ uint8_t bt_mesh_set_fast_prov_action(uint8_t action) if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { bt_mesh_secure_beacon_disable(); } + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { bt_mesh_proxy_client_prov_enable(); } + bt_mesh_provisioner_set_primary_elem_addr(bt_mesh_primary_addr()); bt_mesh_provisioner_set_prov_bearer(BLE_MESH_PROV_ADV, false); bt_mesh_provisioner_fast_prov_enable(true); @@ -179,11 +210,15 @@ uint8_t bt_mesh_set_fast_prov_action(uint8_t action) if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { bt_mesh_proxy_client_prov_disable(); } + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { bt_mesh_secure_beacon_enable(); } + bt_mesh_atomic_and(bt_mesh.flags, ~(BIT(BLE_MESH_PROVISIONER) | BIT(BLE_MESH_VALID_PROV))); + bt_mesh_provisioner_fast_prov_enable(false); + if (action == ACTION_EXIT) { bt_mesh_provisioner_remove_node(NULL); } @@ -191,4 +226,5 @@ uint8_t bt_mesh_set_fast_prov_action(uint8_t action) return 0x0; } + #endif /* CONFIG_BLE_MESH_FAST_PROV */ diff --git a/components/bt/esp_ble_mesh/core/foundation.h b/components/bt/esp_ble_mesh/core/foundation.h index 4f3aa79ad1..66f8c5ea2b 100644 --- a/components/bt/esp_ble_mesh/core/foundation.h +++ b/components/bt/esp_ble_mesh/core/foundation.h @@ -287,6 +287,7 @@ uint8_t bt_mesh_default_ttl_get(void); void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store); struct bt_mesh_app_key *bt_mesh_app_key_alloc(uint16_t app_idx); + void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store); static inline void key_idx_pack(struct net_buf_simple *buf, diff --git a/components/bt/esp_ble_mesh/core/friend.c b/components/bt/esp_ble_mesh/core/friend.c index eae9f9471d..07de4b7d3c 100644 --- a/components/bt/esp_ble_mesh/core/friend.c +++ b/components/bt/esp_ble_mesh/core/friend.c @@ -69,6 +69,9 @@ static struct bt_mesh_subnet *friend_subnet_get(uint16_t net_idx) static bool is_lpn_unicast(struct bt_mesh_friend *frnd, uint16_t addr) { + BT_INFO("IsLPNUnicast, LPN 0x%04x NumElem %u Addr 0x%04x", + frnd->lpn, frnd->num_elem, addr); + if (frnd->lpn == BLE_MESH_ADDR_UNASSIGNED) { return false; } @@ -81,11 +84,16 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, { int i; - BT_DBG("net_idx 0x%04x lpn_addr 0x%04x", net_idx, lpn_addr); + BT_DBG("FrndFind"); + BT_DBG("NetIdx 0x%04x LPN 0x%04x Valid %u Established %u", + net_idx, lpn_addr, valid, established); for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + BT_DBG("%u: LPN 0x%04x NetIdx 0x%04x Valid %u Established %u", + i, frnd->lpn, frnd->net_idx, frnd->valid, frnd->established); + if (valid && !frnd->valid) { continue; } @@ -108,11 +116,15 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, static void purge_buffers(sys_slist_t *list) { + BT_DBG("PurgeBuffers"); + while (!sys_slist_is_empty(list)) { struct net_buf *buf = NULL; buf = (void *)sys_slist_get_not_empty(list); + BT_DBG("Buf %p Ref %u", buf, buf->ref); + buf->frags = NULL; buf->flags &= ~NET_BUF_FRAGS; @@ -127,18 +139,21 @@ static void purge_buffers(sys_slist_t *list) */ static int32_t recv_delay(struct bt_mesh_friend *frnd) { + BT_DBG("RecvDelay, LPN 0x%04x RecvWin %u RecvDelay %u", + frnd->lpn, CONFIG_BLE_MESH_FRIEND_RECV_WIN, frnd->recv_delay); + #if CONFIG_BLE_MESH_FRIEND_RECV_WIN > 50 return (int32_t)frnd->recv_delay + (CONFIG_BLE_MESH_FRIEND_RECV_WIN / 5); -#else +#else /* CONFIG_BLE_MESH_FRIEND_RECV_WIN > 50 */ return frnd->recv_delay; -#endif +#endif /* CONFIG_BLE_MESH_FRIEND_RECV_WIN > 50 */ } static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason) { int i; - BT_DBG("LPN 0x%04x", frnd->lpn); + BT_DBG("FrndClear, LPN 0x%04x Reason 0x%02x", frnd->lpn, reason); k_delayed_work_cancel(&frnd->timer); @@ -160,9 +175,13 @@ static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason) friend_cred_del(frnd->net_idx, frnd->lpn); if (frnd->last) { + BT_DBG("FrndLast, Buf %p Ref %u PendingBuf %u", + frnd->last, frnd->last->ref, frnd->pending_buf); + /* Cancel the sending if necessary */ if (frnd->pending_buf) { bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 2U, BLE_MESH_BUF_REF_EQUAL); + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(frnd->last), 0); } else { bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 1U, BLE_MESH_BUF_REF_EQUAL); @@ -177,6 +196,8 @@ static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason) for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) { struct bt_mesh_friend_seg *seg = &frnd->seg[i]; + BT_DBG("%u: SegCount %u", i, seg->seg_count); + purge_buffers(&seg->queue); seg->seg_count = 0U; } @@ -194,11 +215,13 @@ void bt_mesh_friend_clear_net_idx(uint16_t net_idx) { int i; - BT_DBG("net_idx 0x%04x", net_idx); + BT_DBG("FrndClearNetIdx, NetIdx 0x%04x", net_idx); for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + BT_DBG("%u: LPN 0x%04x NetIdx 0x%04x", i, frnd->lpn, frnd->net_idx); + if (frnd->net_idx == BLE_MESH_KEY_UNUSED) { continue; } @@ -213,11 +236,13 @@ void bt_mesh_friend_sec_update(uint16_t net_idx) { int i; - BT_DBG("net_idx 0x%04x", net_idx); + BT_DBG("FrndSecUpdate, NetIdx 0x%04x", net_idx); for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; + BT_DBG("%u: NetIdx 0x%04x", i, frnd->net_idx); + if (frnd->net_idx == BLE_MESH_KEY_UNUSED) { continue; } @@ -257,19 +282,21 @@ int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) }; struct bt_mesh_ctl_friend_clear_confirm cfm = {0}; + BT_DBG("FrndClear, NetIdx 0x%04x", rx->sub->net_idx); + if (buf->len < sizeof(*msg)) { - BT_WARN("Too short Friend Clear (len %d)", buf->len); + BT_WARN("Too short FriendClear (len %d)", buf->len); return -EINVAL; } lpn_addr = sys_be16_to_cpu(msg->lpn_addr); lpn_counter = sys_be16_to_cpu(msg->lpn_counter); - BT_DBG("LPN addr 0x%04x counter 0x%04x", lpn_addr, lpn_counter); + BT_DBG("LPN 0x%04x Counter %u", lpn_addr, lpn_counter); frnd = bt_mesh_friend_find(rx->sub->net_idx, lpn_addr, false, false); if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", lpn_addr); + BT_WARN("NoMatchLPN, Addr 0x%04x", lpn_addr); return 0; } @@ -305,6 +332,8 @@ static bool friend_sub_exist(struct bt_mesh_friend *frnd, uint16_t addr) { int i; + BT_DBG("IsFrndSubExist, Addr 0x%04x"); + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == addr) { return true; @@ -318,6 +347,8 @@ static void friend_sub_add(struct bt_mesh_friend *frnd, uint16_t addr) { int i; + BT_DBG("FrndSubAdd, Addr 0x%04x"); + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == BLE_MESH_ADDR_UNASSIGNED) { frnd->sub_list[i] = addr; @@ -332,6 +363,8 @@ static void friend_sub_rem(struct bt_mesh_friend *frnd, uint16_t addr) { int i; + BT_DBG("FrndSubRem, Addr 0x%04x"); + for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == addr) { frnd->sub_list[i] = BLE_MESH_ADDR_UNASSIGNED; @@ -346,6 +379,8 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd, { struct net_buf *buf = NULL; + BT_DBG("CreatFrndPDU"); + buf = bt_mesh_adv_create(BLE_MESH_ADV_FRIEND, K_NO_WAIT); if (!buf) { return NULL; @@ -385,6 +420,10 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, uint16_t app_idx = FRIEND_ADV(buf)->app_idx; int err = 0; + BT_DBG("UnsegAppSduUnpack"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x RecvDst 0x%04x", + frnd->net_idx, app_idx, meta->net.ctx.recv_dst); + meta->subnet = friend_subnet_get(frnd->net_idx); if (!meta->subnet) { BT_ERR("Invalid subnet for unseg app sdu"); @@ -393,6 +432,7 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd, meta->is_dev_key = (app_idx == BLE_MESH_KEY_DEV); bt_mesh_net_header_parse(&buf->b, &meta->net); + err = bt_mesh_upper_key_get(meta->subnet, app_idx, &meta->key, &meta->aid, meta->net.ctx.addr); if (err) { @@ -423,6 +463,8 @@ static int unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd, net_buf_simple_pull(&sdu, 10); sdu.len -= 4; + BT_DBG("UnsegAppSduDecrypt, SduLen %u", sdu.len); + return bt_mesh_app_decrypt(meta->key, meta->is_dev_key, 0, &sdu, &sdu, meta->ad, meta->net.ctx.addr, meta->net.ctx.recv_dst, meta->net.seq, @@ -439,6 +481,8 @@ static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd, net_buf_simple_pull(&sdu, 10); sdu.len -= 4; + BT_DBG("UnsegAppSduEncrypt, SduLen %u", sdu.len); + return bt_mesh_app_encrypt(meta->key, meta->is_dev_key, 0, &sdu, meta->ad, meta->net.ctx.addr, meta->net.ctx.recv_dst, bt_mesh.seq, @@ -451,6 +495,10 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, struct unseg_app_sdu_meta meta = {0}; int err = 0; + BT_DBG("UnsegAppSduPrepare"); + BT_DBG("LPN 0x%04x AppIdx 0x%04x Buf %p", + frnd->lpn, FRIEND_ADV(buf)->app_idx, buf); + if (FRIEND_ADV(buf)->app_idx == BLE_MESH_KEY_UNUSED) { return 0; } @@ -464,6 +512,7 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, * unchanged. */ if (meta.net.seq == bt_mesh.seq) { + BT_DBG("Seq 0x%06x", bt_mesh.seq); return 0; } @@ -491,8 +540,11 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, uint8_t nid = 0U; int err = 0; + BT_DBG("EncryptFrndPDU, LPN 0x%04x NetIdx 0x%04x Cred %u", + frnd->lpn, frnd->net_idx, master_cred); + if (!sub) { - BT_ERR("Invalid subnet to encrypt friend pdu"); + BT_ERR("NoSubToEncryptFrndPDU"); return -EINVAL; } @@ -502,7 +554,7 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, nid = sub->keys[sub->kr_flag].nid; } else { if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) { - BT_ERR("friend_cred_get failed"); + BT_ERR("FrndCredNotFound"); return -ENOENT; } } @@ -515,6 +567,7 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, if (FRIEND_ADV(buf)->app_idx != BLE_MESH_KEY_UNUSED) { err = unseg_app_sdu_prepare(frnd, buf); if (err) { + BT_DBG("UnsegAppSduPrepareFailed, Err %d", err); return err; } } @@ -529,15 +582,15 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, iv_index = (bt_mesh.iv_index - ((bt_mesh.iv_index & 1) != ivi)); } + BT_DBG("Src 0x%04x NID 0x%02x IVIndex 0x%08lx", src, nid, iv_index); + buf->data[0] = (nid | (iv_index & 1) << 7); if (bt_mesh_net_encrypt(enc, &buf->b, iv_index, false, false)) { - BT_ERR("Encrypting failed"); return -EINVAL; } if (bt_mesh_net_obfuscate(buf->data, iv_index, priv)) { - BT_ERR("Obfuscating failed"); return -EINVAL; } @@ -550,7 +603,7 @@ static struct net_buf *encode_friend_ctl(struct bt_mesh_friend *frnd, { struct friend_pdu_info info = {0}; - BT_DBG("LPN 0x%04x", frnd->lpn); + BT_DBG("EncodeFrndCTL"); net_buf_simple_push_u8(sdu, TRANS_CTL_HDR(ctl_op, 0)); @@ -564,21 +617,25 @@ static struct net_buf *encode_friend_ctl(struct bt_mesh_friend *frnd, info.iv_index = BLE_MESH_NET_IVI_TX; + BT_DBG("CTLOp 0x%02x IVIndex 0x%08lx", ctl_op, info.iv_index); + return create_friend_pdu(frnd, &info, sdu); } static struct net_buf *encode_update(struct bt_mesh_friend *frnd, uint8_t md) { + struct bt_mesh_subnet *sub = friend_subnet_get(frnd->net_idx); struct bt_mesh_ctl_friend_update *upd = NULL; NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*upd)); - struct bt_mesh_subnet *sub = friend_subnet_get(frnd->net_idx); + + BT_DBG("EncodeUpdate, NetIdx 0x%04x", frnd->net_idx); if (!sub) { BT_ERR("Friend subnet 0x%04x not found", frnd->net_idx); return NULL; } - BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md); + BT_DBG("LPN 0x%04x MD %u", frnd->lpn, md); net_buf_simple_reserve(&sdu, 1); @@ -596,7 +653,7 @@ static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, uint8_t xact) NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*cfm)); struct net_buf *buf = NULL; - BT_DBG("lpn 0x%04x xact 0x%02x", frnd->lpn, xact); + BT_DBG("EnqueueSubCFM, LPN 0x%04x Xact 0x%02x", frnd->lpn, xact); net_buf_simple_reserve(&sdu, 1); @@ -614,7 +671,7 @@ static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, uint8_t xact) } if (frnd->last) { - BT_DBG("Discarding last PDU"); + BT_DBG("DiscardFrndLast, Buf %p Ref %u", frnd->last, frnd->last->ref); net_buf_unref(frnd->last); } @@ -624,9 +681,12 @@ static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, uint8_t xact) static void friend_recv_delay(struct bt_mesh_friend *frnd) { + int32_t delay = recv_delay(frnd); + + BT_INFO("FrndRecvDelay, Delay %ld", delay); + frnd->pending_req = 1U; - k_delayed_work_submit(&frnd->timer, recv_delay(frnd)); - BT_INFO("Waiting RecvDelay of %d ms", recv_delay(frnd)); + k_delayed_work_submit(&frnd->timer, delay); } int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, @@ -635,6 +695,8 @@ int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, struct bt_mesh_friend *frnd = NULL; uint8_t xact = 0U; + BT_DBG("FrndSubAdd"); + if (buf->len < BLE_MESH_FRIEND_SUB_MIN_LEN) { BT_WARN("Too short Friend Subscription Add (len %d)", buf->len); return -EINVAL; @@ -642,7 +704,7 @@ int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true); if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr); + BT_WARN("NoMatchLPN, Addr 0x%04x", rx->ctx.addr); return 0; } @@ -666,6 +728,7 @@ int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, } if (friend_sub_exist(frnd, addr)) { + BT_DBG("FrndSubExist, Addr 0x%04x", addr); continue; } @@ -676,9 +739,9 @@ int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx, #if CONFIG_BLE_MESH_DF_SRV return bt_mesh_directed_friend_solicitation(frnd, rx->sub); -#else +#else /* CONFIG_BLE_MESH_DF_SRV */ return 0; -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, @@ -687,6 +750,8 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, struct bt_mesh_friend *frnd = NULL; uint8_t xact = 0U; + BT_DBG("FrndSubRem"); + if (buf->len < BLE_MESH_FRIEND_SUB_MIN_LEN) { BT_WARN("Too short Friend Subscription Remove (len %d)", buf->len); return -EINVAL; @@ -694,7 +759,7 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, true); if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr); + BT_WARN("NoMatchLPN, Addr 0x%04x", rx->ctx.addr); return 0; } @@ -713,7 +778,7 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, if (!BLE_MESH_ADDR_IS_GROUP(addr) && !BLE_MESH_ADDR_IS_VIRTUAL(addr) && !BLE_MESH_ADDR_IS_FIXED_GROUP(addr)) { - BT_WARN("Invalid friend sub addr 0x%04x to remove", addr); + BT_WARN("InvalidFrndSub, Addr 0x%04x", addr); continue; } @@ -727,6 +792,8 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, static void enqueue_buf(struct bt_mesh_friend *frnd, struct net_buf *buf) { + BT_DBG("EnqueueBuf, Buf %p QueueSize %u", __func__, buf, frnd->queue_size); + net_buf_slist_put(&frnd->queue, buf); frnd->queue_size++; } @@ -735,6 +802,8 @@ static void enqueue_update(struct bt_mesh_friend *frnd, uint8_t md) { struct net_buf *buf = NULL; + BT_DBG("EnqueueUpdate, LPN 0x%04x MD %u", __func__, frnd->lpn, md); + buf = encode_update(frnd, md); if (!buf) { BT_ERR("Unable to encode Friend Update"); @@ -749,6 +818,8 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) struct bt_mesh_ctl_friend_poll *msg = (void *)buf->data; struct bt_mesh_friend *frnd = NULL; + BT_DBG("FrndPoll"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Poll (len %d)", buf->len); return -EINVAL; @@ -756,7 +827,7 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) frnd = bt_mesh_friend_find(rx->sub->net_idx, rx->ctx.addr, true, false); if (!frnd) { - BT_WARN("No matching LPN addr 0x%04x", rx->ctx.addr); + BT_WARN("NoMatchLPN, Addr 0x%04x", rx->ctx.addr); return 0; } @@ -770,12 +841,13 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) return 0; } - BT_DBG("msg->fsn %u frnd->fsn %u", (msg->fsn & 1), frnd->fsn); + BT_DBG("MsgFSN %u FrndFSN %u", (msg->fsn & 1), frnd->fsn); friend_recv_delay(frnd); if (!frnd->established) { - BT_INFO("Friendship established with 0x%04x", frnd->lpn); + BT_INFO("Friendship established with LPN 0x%04x", frnd->lpn); + frnd->established = 1U; if (friend_cb) { friend_cb(true, frnd->lpn, 0); @@ -783,7 +855,8 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } if (msg->fsn == frnd->fsn && frnd->last) { - BT_DBG("Re-sending last PDU"); + BT_DBG("ResendFrndLast"); + frnd->send_last = 1U; } else { if (frnd->last) { @@ -794,8 +867,8 @@ int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) frnd->fsn = msg->fsn; if (sys_slist_is_empty(&frnd->queue)) { + BT_DBG("EnqueueFrndUpdate"); enqueue_update(frnd, 0); - BT_DBG("Enqueued Friend Update to empty queue"); } } @@ -806,6 +879,8 @@ static struct bt_mesh_friend *find_clear(uint16_t prev_friend) { int i; + BT_DBG("FindClear, PrevFrnd 0x%04x", prev_friend); + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; @@ -821,6 +896,8 @@ static void friend_clear_sent(int err, void *user_data) { struct bt_mesh_friend *frnd = user_data; + BT_DBG("FrndClearSent, RepeatSec %u Err %d", frnd->clear.repeat_sec, err); + k_delayed_work_submit(&frnd->clear.timer, K_SECONDS(frnd->clear.repeat_sec)); frnd->clear.repeat_sec *= 2U; @@ -852,6 +929,8 @@ static void send_friend_clear(struct bt_mesh_friend *frnd) .lpn_counter = sys_cpu_to_be16(frnd->lpn_counter), }; + BT_DBG("SendFrndClear, Addr 0x%04x", frnd->clear.frnd); + if (!tx.sub) { BT_ERR("Invalid subnet for Friend Clear"); return; @@ -863,13 +942,15 @@ static void send_friend_clear(struct bt_mesh_friend *frnd) static void clear_timeout(struct k_work *work) { - struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, - clear.timer.work); + struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, clear.timer.work); uint32_t duration = 0U; - BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); - duration = k_uptime_get_32() - frnd->clear.start; + + BT_DBG("ClearTimeout"); + BT_DBG("LPN 0x%04x Frnd 0x%04x Duration %lu PollTo %ld", + frnd->lpn, frnd->clear.frnd, duration, frnd->poll_to); + if (duration > 2 * frnd->poll_to) { BT_DBG("Clear Procedure timer expired"); frnd->clear.frnd = BLE_MESH_ADDR_UNASSIGNED; @@ -881,11 +962,13 @@ static void clear_timeout(struct k_work *work) static void clear_procedure_start(struct bt_mesh_friend *frnd) { - BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); - frnd->clear.start = k_uptime_get_32(); frnd->clear.repeat_sec = 1U; + BT_DBG("ClearProcedureStart"); + BT_DBG("LPN 0x%04x Frnd 0x%04x ClearStart %lu", + frnd->lpn, frnd->clear.frnd, frnd->clear.start); + send_friend_clear(frnd); } @@ -896,6 +979,8 @@ int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, struct bt_mesh_friend *frnd = NULL; uint16_t lpn_addr = 0U, lpn_counter = 0U; + BT_DBG("FrndClearCFM"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Clear Confirm (len %d)", buf->len); return -EINVAL; @@ -933,6 +1018,9 @@ static void enqueue_offer(struct bt_mesh_friend *frnd, int8_t rssi) NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*off)); struct net_buf *buf = NULL; + BT_DBG("EnqueueOffset"); + BT_DBG("LPN 0x%04x Counter %u Rssi %d", frnd->lpn, frnd->counter, rssi); + net_buf_simple_reserve(&sdu, 1); off = net_buf_simple_add(&sdu, sizeof(*off)); @@ -977,7 +1065,7 @@ static int32_t offer_delay(struct bt_mesh_friend *frnd, int8_t rssi, uint8_t cri static const uint8_t fact[] = { 10, 15, 20, 25 }; int32_t delay = 0; - BT_INFO("ReceiveWindowFactor %u ReceiveWindow %u RSSIFactor %u RSSI %d", + BT_INFO("RecvWinFactor %u RecvWin %u RssiFactor %u Rssi %d", fact[RECV_WIN_FACT(crit)], RECV_WIN, fact[RSSI_FACT(crit)], rssi); @@ -986,7 +1074,7 @@ static int32_t offer_delay(struct bt_mesh_friend *frnd, int8_t rssi, uint8_t cri delay -= (int32_t)fact[RSSI_FACT(crit)] * rssi; delay /= 10; - BT_DBG("Local Delay calculated as %d ms", delay); + BT_DBG("OfferDelay %d", delay); if (delay < 100) { return K_MSEC(100); @@ -1002,13 +1090,15 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) uint32_t poll_to = 0U; int i; + BT_DBG("FrndReq"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Request (len %d)", buf->len); return -EINVAL; } if (msg->recv_delay <= 0x09) { - BT_WARN("Prohibited ReceiveDelay (0x%02x)", msg->recv_delay); + BT_WARN("Prohibited RecvDelay (0x%02x)", msg->recv_delay); return -EINVAL; } @@ -1035,7 +1125,7 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } if (CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE < MIN_QUEUE_SIZE(msg->criteria)) { - BT_WARN("We have a too small Friend Queue size (%u < %u)", + BT_WARN("Too small Friend Queue size (%u < %u)", CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE, MIN_QUEUE_SIZE(msg->criteria)); return 0; @@ -1070,11 +1160,10 @@ init_friend: frnd->lpn_counter = sys_be16_to_cpu(msg->lpn_counter); frnd->clear.frnd = sys_be16_to_cpu(msg->prev_addr); - BT_INFO("LPN 0x%04x rssi %d recv_delay %u poll_to %ums", - frnd->lpn, rx->ctx.recv_rssi, frnd->recv_delay, frnd->poll_to); + BT_INFO("LPN 0x%04x Rssi %d RecvDelay %u PollTo %u", + frnd->lpn, rx->ctx.recv_rssi, frnd->recv_delay, frnd->poll_to); - /** - * Spec says: + /* Spec says: * After a friendship has been established, if the PreviousAddress field * of the Friend Request message contains a valid unicast address that is * not the Friend node’s own unicast address, then the Friend node shall @@ -1086,11 +1175,9 @@ init_friend: } k_delayed_work_submit(&frnd->timer, - offer_delay(frnd, rx->ctx.recv_rssi, - msg->criteria)); + offer_delay(frnd, rx->ctx.recv_rssi, msg->criteria)); - friend_cred_create(rx->sub, frnd->lpn, frnd->lpn_counter, - frnd->counter); + friend_cred_create(rx->sub, frnd->lpn, frnd->lpn_counter, frnd->counter); enqueue_offer(frnd, rx->ctx.recv_rssi); @@ -1104,6 +1191,8 @@ static bool is_seg(struct bt_mesh_friend_seg *seg, uint16_t src, uint16_t seq_ze uint16_t buf_seq_zero = 0U; uint16_t buf_src = 0U; + BT_DBG("IsSeg, Buf %p", buf); + if (!buf) { return false; } @@ -1125,6 +1214,9 @@ static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd, struct bt_mesh_friend_seg *unassigned = NULL; int i; + BT_DBG("GetSeg, Src 0x%04x SeqZero 0x%04x SegCount %u", + src, seq_zero, seg_count); + for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) { struct bt_mesh_friend_seg *seg = &frnd->seg[i]; @@ -1150,15 +1242,18 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf) { struct bt_mesh_friend_seg *seg = NULL; + uint16_t seq_zero = 0; - BT_DBG("type %u", type); + BT_DBG("EnqueueFrndPDU, Type %u", type); if (type == BLE_MESH_FRIEND_PDU_SINGLE) { enqueue_buf(frnd, buf); return; } - uint16_t seq_zero = (((buf->data[10] << 8 | buf->data[11]) >> 2) & TRANS_SEQ_ZERO_MASK); + seq_zero = (((buf->data[10] << 8 | buf->data[11]) >> 2) & TRANS_SEQ_ZERO_MASK); + + BT_DBG("Src 0x%04x SegCount %u SegZero 0x%04x", src, seg_count, seq_zero); seg = get_seg(frnd, src, seq_zero, seg_count); if (!seg) { @@ -1184,7 +1279,7 @@ static void buf_send_start(uint16_t duration, int err, void *user_data) { struct bt_mesh_friend *frnd = user_data; - BT_DBG("err %d", err); + BT_DBG("BufSendStart, Err %d", err); frnd->pending_buf = 0U; @@ -1199,7 +1294,7 @@ static void buf_send_end(int err, void *user_data) { struct bt_mesh_friend *frnd = user_data; - BT_DBG("err %d", err); + BT_DBG("BufSendEnd, Err %d", err); if (frnd->pending_req) { BT_WARN("Another request before previous completed sending"); @@ -1207,47 +1302,48 @@ static void buf_send_end(int err, void *user_data) } if (frnd->established) { + BT_DBG("WaitForNextPoll %u", frnd->poll_to); + k_delayed_work_submit(&frnd->timer, frnd->poll_to); - BT_DBG("Waiting %u ms for next poll", frnd->poll_to); } else { /* Friend offer timeout is 1 second */ + BT_DBG("WaitForFirstPoll"); + k_delayed_work_submit(&frnd->timer, K_SECONDS(1)); - BT_DBG("Waiting for first poll"); } } static void friend_timeout(struct k_work *work) { - struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, - timer.work); + struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, timer.work); static const struct bt_mesh_send_cb buf_sent_cb = { .start = buf_send_start, .end = buf_send_end, }; + BT_DBG("FrndTimeout"); + if (frnd->pending_buf != 0U) { BT_ERR("Previous buffer not yet sent!"); return; } - BT_DBG("lpn 0x%04x send_last %u last %p", frnd->lpn, - frnd->send_last, frnd->last); + BT_DBG("LPN 0x%04x SendLast %u FrndLast %p", frnd->lpn, frnd->send_last, frnd->last); if (frnd->send_last && frnd->last) { - BT_DBG("Sending frnd->last %p", frnd->last); frnd->send_last = 0U; goto send_last; } if (frnd->established && !frnd->pending_req) { - BT_WARN("Friendship lost with 0x%04x", frnd->lpn); + BT_WARN("FriendshipLost, LPN 0x%04x", frnd->lpn); friend_clear(frnd, BLE_MESH_FRIENDSHIP_TERMINATE_POLL_TIMEOUT); return; } frnd->last = (void *)sys_slist_get(&frnd->queue); if (!frnd->last) { - BT_WARN("Friendship not established with 0x%04x", frnd->lpn); + BT_WARN("FriendshipNotEstablished, LPN 0x%04x", frnd->lpn); friend_clear(frnd, BLE_MESH_FRIENDSHIP_TERMINATE_ESTABLISH_FAIL); return; } @@ -1260,8 +1356,9 @@ static void friend_timeout(struct k_work *work) frnd->last->flags &= ~NET_BUF_FRAGS; frnd->last->frags = NULL; - BT_DBG("Sending buf %p from Friend Queue of LPN 0x%04x", - frnd->last, frnd->lpn); + BT_DBG("SendBufFromFrndQueue, Last %p QueueSize %u LPN 0x%04x", + frnd->last, frnd->queue_size, frnd->lpn); + frnd->queue_size--; send_last: @@ -1279,6 +1376,8 @@ int bt_mesh_friend_init(void) { int i; + BT_DBG("FrndInit"); + if (friend_init == true) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1312,6 +1411,8 @@ int bt_mesh_friend_deinit(void) { int i; + BT_DBG("FrndDeinit"); + if (friend_init == false) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1341,6 +1442,8 @@ static bool is_segack(struct net_buf *buf, const uint64_t *seqauth, uint16_t src struct net_buf_simple_state state = {0}; bool found = false; + BT_DBG("IsSegAck, Len %u", buf->len); + if (buf->len != 16) { return false; } @@ -1350,23 +1453,27 @@ static bool is_segack(struct net_buf *buf, const uint64_t *seqauth, uint16_t src net_buf_skip(buf, 1); /* skip IVI, NID */ if (!(net_buf_pull_u8(buf) >> 7)) { + BT_DBG("Not SegAck"); goto end; } net_buf_pull(buf, 3); /* skip SEQNUM */ if (src != net_buf_pull_be16(buf)) { + BT_DBG("SrcNotSegAck"); goto end; } net_buf_skip(buf, 2); /* skip dst */ - if (TRANS_CTL_OP((uint8_t *) net_buf_pull_mem(buf, 1)) != TRANS_CTL_OP_ACK) { + if (TRANS_CTL_OP((uint8_t *)net_buf_pull_mem(buf, 1)) != TRANS_CTL_OP_ACK) { + BT_DBG("OpNotSegAck"); goto end; } - found = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) == - (*seqauth & TRANS_SEQ_ZERO_MASK); + found = (((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) == + (*seqauth & TRANS_SEQ_ZERO_MASK)); + end: net_buf_simple_restore(&buf->b, &state); return found; @@ -1377,17 +1484,18 @@ static void friend_purge_old_ack(struct bt_mesh_friend *frnd, { sys_snode_t *cur = NULL, *prev = NULL; - BT_DBG("SeqAuth %llx src 0x%04x", *seq_auth, src); + BT_DBG("FrndPurgeOldAck, SeqAuth %llx Src 0x%04x", *seq_auth, src); for (cur = sys_slist_peek_head(&frnd->queue); - cur != NULL; prev = cur, cur = sys_slist_peek_next(cur)) { + cur != NULL; prev = cur, cur = sys_slist_peek_next(cur)) { struct net_buf *buf = (void *)cur; if (is_segack(buf, seq_auth, src)) { - BT_DBG("Removing old ack from Friend Queue"); + BT_DBG("RemoveOldAckFromFrndQueue, QueueSize %u", frnd->queue_size); sys_slist_remove(&frnd->queue, prev, cur); frnd->queue_size--; + /* Make sure old slist entry state doesn't remain */ buf->frags = NULL; @@ -1406,6 +1514,9 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, struct friend_pdu_info info = {0}; struct net_buf *buf = NULL; + BT_DBG("FrndLPNEnqueueRx, LPN 0x%04x QueueSize %u Type 0x%02x", + frnd->lpn, frnd->queue_size, type); + /* Because of network loopback, tx packets will also be passed into * this rx function. These packets have already been added to the * queue, and should be ignored. @@ -1414,8 +1525,6 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, return; } - BT_DBG("LPN 0x%04x queue_size %u", frnd->lpn, frnd->queue_size); - if (type == BLE_MESH_FRIEND_PDU_SINGLE && seq_auth) { friend_purge_old_ack(frnd, seq_auth, rx->ctx.addr); } @@ -1443,7 +1552,7 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, enqueue_friend_pdu(frnd, type, info.src, seg_count, buf); - BT_DBG("Queued message for LPN 0x%04x, queue_size %u", + BT_DBG("QueuedMsg, LPN 0x%04x QueueSize %u", frnd->lpn, frnd->queue_size); } @@ -1456,7 +1565,7 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd, struct friend_pdu_info info = {0}; struct net_buf *buf = NULL; - BT_DBG("LPN 0x%04x", frnd->lpn); + BT_DBG("FrndLPNEnqueueTx, LPN 0x%04x Type 0x%02x", frnd->lpn, type); if (type == BLE_MESH_FRIEND_PDU_SINGLE && seq_auth) { friend_purge_old_ack(frnd, seq_auth, tx->src); @@ -1488,7 +1597,7 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd, enqueue_friend_pdu(frnd, type, info.src, seg_count, buf); - BT_DBG("Queued message for LPN 0x%04x", frnd->lpn); + BT_DBG("QueuedMsg, LPN 0x%04x", frnd->lpn); } static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx, @@ -1496,6 +1605,10 @@ static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx, { int i; + BT_DBG("IsFrndLPNMatch"); + BT_DBG("LPN 0x%04x NetIdx 0x%04x/0x%04x Addr 0x%04x Established %u", + frnd->lpn, net_idx, frnd->net_idx, addr, frnd->established); + if (!frnd->established) { return false; } @@ -1521,12 +1634,13 @@ bool bt_mesh_friend_match(uint16_t net_idx, uint16_t addr) { int i; + BT_DBG("FrndMatch, NetIdx 0x%04x Addr 0x%04x", net_idx, addr); + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; if (friend_lpn_matches(frnd, net_idx, addr)) { - BT_DBG("LPN 0x%04x matched address 0x%04x", - frnd->lpn, addr); + BT_DBG("LPNMatch, LPN 0x%04x Addr 0x%04x", frnd->lpn, addr); return true; } } @@ -1540,6 +1654,8 @@ bool bt_mesh_friend_unicast_match(uint16_t net_idx, uint16_t addr, uint8_t *sele { int i; + BT_DBG("FrndUnicastMatch, NetIdx 0x%04x addr 0x%04x", net_idx, addr); + if (!BLE_MESH_ADDR_IS_UNICAST(addr) || selem == NULL) { BT_ERR("%s, Invalid parameter", __func__); return false; @@ -1565,6 +1681,10 @@ static bool friend_queue_has_space(struct bt_mesh_friend *frnd, uint16_t addr, uint32_t total = 0U; int i; + BT_DBG("IsFrndQueueHasSpace"); + BT_DBG("LPN 0x%04x SegCount %u QueueSize %u Addr 0x%04x", + frnd->lpn, seg_count, CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE, addr); + if (seg_count > CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE) { return false; } @@ -1573,8 +1693,8 @@ static bool friend_queue_has_space(struct bt_mesh_friend *frnd, uint16_t addr, struct bt_mesh_friend_seg *seg = &frnd->seg[i]; if (seq_auth && is_seg(seg, addr, *seq_auth & TRANS_SEQ_ZERO_MASK)) { - /* If there's a segment queue for this message then the - * space verification has already happened. + /* If there's a segment queue for this message then the space + * verification has already happened. */ return true; } @@ -1582,6 +1702,8 @@ static bool friend_queue_has_space(struct bt_mesh_friend *frnd, uint16_t addr, total += seg->seg_count; } + BT_DBG("TotalCount %u", total); + /* If currently pending segments combined with this segmented message * are more than the Friend Queue Size, then there's no space. This * is because we don't have a mechanism of aborting already pending @@ -1596,6 +1718,10 @@ bool bt_mesh_friend_queue_has_space(uint16_t net_idx, uint16_t src, uint16_t dst bool someone_has_space = false, friend_match = false; int i; + BT_DBG("FrndQueueHasSpace"); + BT_DBG("NetIdx 0x%04x Src 0x%04x Dst 0x%04x SegCount %u", + net_idx, src, dst, seg_count); + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; @@ -1614,6 +1740,7 @@ bool bt_mesh_friend_queue_has_space(uint16_t net_idx, uint16_t src, uint16_t dst * transport layer can continue its work. */ if (!friend_match) { + BT_DBG("NoMatchLPN"); return true; } @@ -1631,6 +1758,9 @@ static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, uint16_t add bool pending_segments = false; uint8_t avail_space = 0U; + BT_DBG("FrndQueuePrepareSpace"); + BT_DBG("LPN 0x%04x Addr 0x%04x SegCount %u", frnd->lpn, addr, seg_count); + if (!friend_queue_has_space(frnd, addr, seq_auth, seg_count)) { return false; } @@ -1646,6 +1776,9 @@ static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, uint16_t add return false; } + BT_DBG("PendingSeg %u AvailSpace %u QueueSize %u", + pending_segments, avail_space, frnd->queue_size); + frnd->queue_size--; avail_space++; @@ -1668,15 +1801,19 @@ void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, { int i; + BT_DBG("FrndEnqueueRx"); + BT_DBG("FrndMatch %u RecvTTL %u NetIf %u FrndGet %u", + rx->friend_match, rx->ctx.recv_ttl, rx->net_if, + bt_mesh_friend_get()); + if (!rx->friend_match || (rx->ctx.recv_ttl <= 1U && rx->net_if != BLE_MESH_NET_IF_LOCAL) || bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { return; } - BT_DBG("recv_ttl %u net_idx 0x%04x src 0x%04x dst 0x%04x", - rx->ctx.recv_ttl, rx->sub->net_idx, rx->ctx.addr, - rx->ctx.recv_dst); + BT_DBG("NetIdx 0x%04x Src 0x%04x Dst 0x%04x", + rx->sub->net_idx, rx->ctx.addr, rx->ctx.recv_dst); for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; @@ -1691,8 +1828,7 @@ void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, continue; } - friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, seg_count, - sbuf); + friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, seg_count, sbuf); } } @@ -1704,14 +1840,15 @@ bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx, bool matched = false; int i; + BT_DBG("FrndEnqueueTx"); + BT_DBG("NetIdx 0x%04x Dst 0x%04x Src 0x%04x FrndState %u", + tx->sub->net_idx, tx->ctx->addr, tx->src, bt_mesh_friend_get()); + if (!bt_mesh_friend_match(tx->sub->net_idx, tx->ctx->addr) || bt_mesh_friend_get() != BLE_MESH_FRIEND_ENABLED) { return matched; } - BT_DBG("net_idx 0x%04x dst 0x%04x src 0x%04x", tx->sub->net_idx, - tx->ctx->addr, tx->src); - for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; @@ -1738,6 +1875,9 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, uint16_t src, { int i; + BT_DBG("FrndClearComplete"); + BT_DBG("NetIdx 0x%04x Src 0x%04x Dst 0x%04x", sub->net_idx, src, dst); + for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; int j; @@ -1766,6 +1906,8 @@ void bt_mesh_friend_remove_lpn(uint16_t lpn_addr) { struct bt_mesh_friend *frnd = NULL; + BT_DBG("FrndRemoveLPN, Addr 0x%04x", lpn_addr); + frnd = bt_mesh_friend_find(BLE_MESH_KEY_ANY, lpn_addr, false, false); if (frnd) { friend_clear(frnd, BLE_MESH_FRIENDSHIP_TERMINATE_DISABLE); diff --git a/components/bt/esp_ble_mesh/core/health_cli.c b/components/bt/esp_ble_mesh/core/health_cli.c index 1e03d93513..829ae33693 100644 --- a/components/bt/esp_ble_mesh/core/health_cli.c +++ b/components/bt/esp_ble_mesh/core/health_cli.c @@ -68,6 +68,8 @@ static void health_client_recv_status(struct bt_mesh_model *model, struct net_buf_simple buf = {0}; uint8_t evt_type = 0xFF; + BT_DBG("HealthClientRecvStatus"); + if (!model || !ctx || !status || !len) { BT_ERR("%s, Invalid parameter", __func__); return; @@ -83,6 +85,8 @@ static void health_client_recv_status(struct bt_mesh_model *model, if (!node) { BT_DBG("Unexpected Health Status 0x%04x", ctx->recv_op); } else { + BT_DBG("OpCode 0x%08lx RecvOp 0x%08lx", node->opcode, ctx->recv_op); + switch (node->opcode) { case OP_HEALTH_FAULT_GET: case OP_HEALTH_PERIOD_GET: @@ -131,9 +135,10 @@ static void health_fault_status(struct bt_mesh_model *model, { struct bt_mesh_health_fault_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HealthFaultStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.test_id = net_buf_simple_pull_u8(buf); status.cid = net_buf_simple_pull_le16(buf); @@ -154,9 +159,10 @@ static void health_current_status(struct bt_mesh_model *model, { struct bt_mesh_health_current_status status = {0}; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HealthCurrentStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status.test_id = net_buf_simple_pull_u8(buf); status.cid = net_buf_simple_pull_le16(buf); @@ -177,9 +183,10 @@ static void health_period_status(struct bt_mesh_model *model, { uint8_t status = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HealthPeriodStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); @@ -192,9 +199,10 @@ static void health_attention_status(struct bt_mesh_model *model, { uint8_t status = 0U; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", - ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, - bt_hex(buf->data, buf->len)); + BT_DBG("HealthAttentionStatus"); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", + ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); @@ -213,6 +221,8 @@ int bt_mesh_health_attention_get(bt_mesh_client_common_param_t *param) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_ATTENTION_GET, 0); + BT_DBG("HealthAttentionGet"); + bt_mesh_model_msg_init(&msg, OP_ATTENTION_GET); return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); @@ -223,6 +233,8 @@ int bt_mesh_health_attention_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_ATTENTION_SET, 1); + BT_DBG("HealthAttentionSet, Attention 0x%02x NeedAck %u", attention, need_ack); + bt_mesh_model_msg_init(&msg, need_ack ? OP_ATTENTION_SET : OP_ATTENTION_SET_UNREL); net_buf_simple_add_u8(&msg, attention); @@ -233,6 +245,8 @@ int bt_mesh_health_period_get(bt_mesh_client_common_param_t *param) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_PERIOD_GET, 0); + BT_DBG("HealthPeriodGet"); + bt_mesh_model_msg_init(&msg, OP_HEALTH_PERIOD_GET); return bt_mesh_client_send_msg(param, &msg, true, timeout_handler); @@ -243,6 +257,8 @@ int bt_mesh_health_period_set(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_PERIOD_SET, 1); + BT_DBG("HealthPeriodSet, Divisor 0x%02x NeedAck %u", divisor, need_ack); + bt_mesh_model_msg_init(&msg, need_ack ? OP_HEALTH_PERIOD_SET : OP_HEALTH_PERIOD_SET_UNREL); net_buf_simple_add_u8(&msg, divisor); @@ -254,6 +270,8 @@ int bt_mesh_health_fault_test(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_FAULT_TEST, 3); + BT_DBG("HealthFaultTest, CID 0x%04x TestID 0x%04x NeedAck %u", cid, test_id, need_ack); + bt_mesh_model_msg_init(&msg, need_ack ? OP_HEALTH_FAULT_TEST : OP_HEALTH_FAULT_TEST_UNREL); net_buf_simple_add_u8(&msg, test_id); net_buf_simple_add_le16(&msg, cid); @@ -266,6 +284,8 @@ int bt_mesh_health_fault_clear(bt_mesh_client_common_param_t *param, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_FAULT_CLEAR, 2); + BT_DBG("HealthFaultClear, CID 0x%04x NeedAck %u", cid, need_ack); + bt_mesh_model_msg_init(&msg, need_ack ? OP_HEALTH_FAULT_CLEAR : OP_HEALTH_FAULT_CLEAR_UNREL); net_buf_simple_add_le16(&msg, cid); @@ -276,6 +296,8 @@ int bt_mesh_health_fault_get(bt_mesh_client_common_param_t *param, uint16_t cid) { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_FAULT_GET, 2); + BT_DBG("HealthFaultGet, CID 0x%04x", cid); + bt_mesh_model_msg_init(&msg, OP_HEALTH_FAULT_GET); net_buf_simple_add_le16(&msg, cid); @@ -287,6 +309,8 @@ static int health_cli_init(struct bt_mesh_model *model) health_internal_data_t *internal = NULL; bt_mesh_health_client_t *client = NULL; + BT_DBG("HealthCliInit"); + if (!model) { BT_ERR("Invalid Health Client model"); return -EINVAL; @@ -328,6 +352,8 @@ static int health_cli_deinit(struct bt_mesh_model *model) { bt_mesh_health_client_t *client = NULL; + BT_DBG("HealthCliDeinit"); + if (!model) { BT_ERR("Invalid Health Client model"); return -EINVAL; diff --git a/components/bt/esp_ble_mesh/core/health_srv.c b/components/bt/esp_ble_mesh/core/health_srv.c index a27e4547b2..f7db34babb 100644 --- a/components/bt/esp_ble_mesh/core/health_srv.c +++ b/components/bt/esp_ble_mesh/core/health_srv.c @@ -26,8 +26,7 @@ /* Health Server context of the primary element */ struct bt_mesh_health_srv *health_srv; -/** - * When an Element receives a Health Fault Get, or a Health Fault Test, or +/* When an Element receives a Health Fault Get, or a Health Fault Test, or * a Health Fault Test Unacknowledged, or a Health Fault Clear, or a Health * Fault Clear Unacknowledged message that is not successfully processed * (i.e. the Company ID field that does not identify any Health Fault state @@ -48,6 +47,8 @@ static uint8_t health_get_curr_fault_count(struct bt_mesh_model *model) } } + BT_DBG("HealthGetCurrFaultCount, Count %u", count); + return count; } @@ -61,6 +62,8 @@ static void health_get_fault_value(struct bt_mesh_model *model, array_size = current ? ARRAY_SIZE(srv->test.curr_faults) : ARRAY_SIZE(srv->test.reg_faults); + BT_DBG("HealthGetFaultValue, Current %u Size %lu", current, array_size); + for (i = 0U; i < array_size; i++) { if (net_buf_simple_tailroom(msg) == 0) { return; @@ -70,6 +73,8 @@ static void health_get_fault_value(struct bt_mesh_model *model, if (fault != HEALTH_NO_FAULT) { net_buf_simple_add_u8(msg, fault); } + + BT_DBG("%u: Fault 0x%02x", i, fault); } } @@ -78,12 +83,16 @@ static bool health_is_test_id_exist(struct bt_mesh_model *model, uint8_t test_id struct bt_mesh_health_srv *srv = model->user_data; int i; + BT_DBG("HealthIsTestIDExist, TestID 0x%02x", test_id); + for (i = 0; i < srv->test.id_count; i++) { if (srv->test.test_ids[i] == test_id) { + BT_DBG("TestIDExist"); return true; } } + BT_DBG("TestIDNotExist"); return false; } @@ -94,19 +103,23 @@ static int health_send_fault_status(struct bt_mesh_model *model, struct net_buf_simple *msg = NULL; int err = 0; + BT_DBG("HealthSendFaultStatus"); + msg = bt_mesh_alloc_buf(4 + ARRAY_SIZE(srv->test.reg_faults) + 4); if (!msg) { BT_ERR("%s, Out of memory", __func__); return -ENOMEM; } + BT_DBG("TestID 0x%02x CID 0x%04x", + srv->test.prev_test_id, srv->test.company_id); + bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_STATUS); net_buf_simple_add_u8(msg, srv->test.prev_test_id); net_buf_simple_add_le16(msg, srv->test.company_id); if (ctx->recv_op != OP_HEALTH_FAULT_CLEAR) { - /** - * For Health Fault Clear, the FaultArray field in Health Fault Status - * shall be empty. + /* For Health Fault Clear, the FaultArray field + * in Health Fault Status shall be empty. */ health_get_fault_value(model, msg, false); } @@ -127,6 +140,8 @@ static void health_fault_get(struct bt_mesh_model *model, struct bt_mesh_health_srv *srv = model->user_data; uint16_t company_id = 0U; + BT_DBG("HealthFaultGet"); + if (!srv) { BT_ERR("No Health Server context provided"); return; @@ -138,7 +153,7 @@ static void health_fault_get(struct bt_mesh_model *model, return; } - BT_DBG("company_id 0x%04x", company_id); + BT_DBG("CID 0x%04x", company_id); health_send_fault_status(model, ctx); } @@ -150,6 +165,8 @@ static void health_fault_clear(struct bt_mesh_model *model, struct bt_mesh_health_srv *srv = model->user_data; uint16_t company_id = 0U; + BT_DBG("HealthFaultClear"); + if (!srv) { BT_ERR("No Health Server context provided"); return; @@ -161,7 +178,7 @@ static void health_fault_clear(struct bt_mesh_model *model, return; } - BT_DBG("company_id 0x%04x", company_id); + BT_DBG("CID 0x%04x", company_id); memset(srv->test.reg_faults, HEALTH_NO_FAULT, ARRAY_SIZE(srv->test.reg_faults)); @@ -182,6 +199,8 @@ static void health_fault_test(struct bt_mesh_model *model, uint16_t company_id = 0U; uint8_t test_id = 0U; + BT_DBG("HealthFaultTest"); + if (!srv) { BT_ERR("No Health Server context provided"); return; @@ -199,7 +218,7 @@ static void health_fault_test(struct bt_mesh_model *model, return; } - BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); + BT_DBG("TestID 0x%02x CID 0x%04x", test_id, company_id); srv->test.prev_test_id = test_id; @@ -219,13 +238,16 @@ static void send_attention_status(struct bt_mesh_model *model, struct bt_mesh_health_srv *srv = model->user_data; uint8_t time = 0U; + BT_DBG("SendAttentionStatus"); + if (!srv) { BT_ERR("No Health Server context provided"); return; } time = k_delayed_work_remaining_get(&srv->attn_timer) / 1000; - BT_DBG("%u second%s", time, (time == 1U) ? "" : "s"); + + BT_DBG("Time %u", time); bt_mesh_model_msg_init(&msg, OP_ATTENTION_STATUS); net_buf_simple_add_u8(&msg, time); @@ -239,6 +261,8 @@ static void attention_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("AttentionGet"); + send_attention_status(model, ctx); } @@ -250,7 +274,7 @@ static void health_set_attention(struct bt_mesh_model *model, time = net_buf_simple_pull_u8(buf); - BT_DBG("%u second%s", time, (time == 1U) ? "" : "s"); + BT_DBG("HealthSetAttention, Time %u", time); bt_mesh_attention(model, time); } @@ -259,6 +283,8 @@ static void attention_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("AttentionSet"); + health_set_attention(model, ctx, buf); if (ctx->recv_op == OP_ATTENTION_SET) { @@ -271,6 +297,8 @@ static void send_health_period_status(struct bt_mesh_model *model, { BLE_MESH_MODEL_BUF_DEFINE(msg, OP_HEALTH_PERIOD_STATUS, 1); + BT_DBG("SendHealthPeriodStatus"); + bt_mesh_model_msg_init(&msg, OP_HEALTH_PERIOD_STATUS); net_buf_simple_add_u8(&msg, model->pub->period_div); @@ -283,6 +311,8 @@ static void health_period_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("HealthPeriodGet"); + send_health_period_status(model, ctx); } @@ -292,13 +322,15 @@ static void health_set_period(struct bt_mesh_model *model, { uint8_t period = 0U; + BT_DBG("HealthSetPeriod"); + period = net_buf_simple_pull_u8(buf); if (period > 15) { BT_WARN("Prohibited period value %u", period); return; } - BT_DBG("period %u", period); + BT_DBG("Period %u", period); model->pub->period_div = period; } @@ -307,6 +339,8 @@ static void health_period_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + BT_DBG("HealthPeriodSet"); + health_set_period(model, ctx, buf); if (ctx->recv_op == OP_HEALTH_PERIOD_SET) { @@ -334,6 +368,8 @@ static size_t health_get_current(struct bt_mesh_model *model, { struct bt_mesh_health_srv *srv = model->user_data; + BT_DBG("HealthGetCurrent"); + if (!srv) { BT_ERR("No Health Server context provided"); return 0; @@ -344,6 +380,9 @@ static size_t health_get_current(struct bt_mesh_model *model, return 0; } + BT_DBG("TestID 0x%02x CID 0x%04x", + srv->test.prev_test_id, srv->test.company_id); + bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS); net_buf_simple_add_u8(msg, srv->test.prev_test_id); net_buf_simple_add_le16(msg, srv->test.company_id); @@ -357,6 +396,8 @@ static int health_pub_update(struct bt_mesh_model *model) struct bt_mesh_model_pub *pub = model->pub; size_t count = 0U; + BT_DBG("HealthPubUpdate"); + if (!pub || !pub->msg) { BT_ERR("Invalid health publication context"); return -EINVAL; @@ -369,6 +410,8 @@ static int health_pub_update(struct bt_mesh_model *model) pub->fast_period = 0U; } + BT_DBG("Count %lu", count); + return 0; } @@ -376,6 +419,8 @@ int bt_mesh_fault_update(struct bt_mesh_elem *elem) { struct bt_mesh_model *model = NULL; + BT_DBG("FaultUpdate"); + model = bt_mesh_model_find(elem, BLE_MESH_MODEL_ID_HEALTH_SRV); if (!model) { BT_ERR("Health Server not exists"); @@ -409,6 +454,8 @@ static void attention_off(struct k_work *work) return; } + BT_DBG("AttentionOff"); + if (srv->cb.attn_off) { srv->cb.attn_off(srv->model); } @@ -423,6 +470,8 @@ static int health_srv_init(struct bt_mesh_model *model) * supported by any secondary elements. */ + BT_DBG("HealthSrvInit"); + if (!srv) { BT_ERR("No Health Server context provided"); return -EINVAL; @@ -433,6 +482,8 @@ static int health_srv_init(struct bt_mesh_model *model) return -EINVAL; } + BT_DBG("TestIDCount %u", srv->test.id_count); + if (!model->pub) { BT_ERR("Health Server has no publication support"); return -EINVAL; @@ -460,6 +511,8 @@ static int health_srv_deinit(struct bt_mesh_model *model) { struct bt_mesh_health_srv *srv = model->user_data; + BT_DBG("HealthSrvDeinit"); + if (!srv) { BT_ERR("No Health Server context provided"); return -EINVAL; @@ -499,6 +552,8 @@ void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time) { struct bt_mesh_health_srv *srv = NULL; + BT_DBG("Attention, Time %u", time); + if (!model) { srv = health_srv; if (!srv) { diff --git a/components/bt/esp_ble_mesh/core/heartbeat.c b/components/bt/esp_ble_mesh/core/heartbeat.c index 4ff63a13ab..4324da3223 100644 --- a/components/bt/esp_ble_mesh/core/heartbeat.c +++ b/components/bt/esp_ble_mesh/core/heartbeat.c @@ -21,11 +21,15 @@ static uint16_t hb_sub_dst = BLE_MESH_ADDR_UNASSIGNED; void bt_mesh_set_hb_sub_dst(uint16_t addr) { + BT_DBG("SetHbSubDst 0x%04x", addr); + hb_sub_dst = addr; } uint16_t bt_mesh_get_hb_sub_dst(void) { + BT_DBG("GetHbSubDst 0x%04x", hb_sub_dst); + return hb_sub_dst; } @@ -33,6 +37,9 @@ void bt_mesh_heartbeat_recv(uint16_t src, uint16_t dst, uint8_t hops, uint16_t f { struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); + BT_DBG("HeartbeatRecv"); + BT_DBG("Src 0x%04x Dst 0x%04x Hops %u Feat 0x%04x", src, dst, hops, feat); + if (cfg == NULL) { BT_WARN("No configuration server context available"); return; @@ -55,9 +62,8 @@ void bt_mesh_heartbeat_recv(uint16_t src, uint16_t dst, uint8_t hops, uint16_t f cfg->hb_sub.count++; } - BT_DBG("src 0x%04x dst 0x%04x hops %u min %u max %u count %u", src, - dst, hops, cfg->hb_sub.min_hops, cfg->hb_sub.max_hops, - cfg->hb_sub.count); + BT_DBG("MinHops %u MaxHops %u Count %u", + cfg->hb_sub.min_hops, cfg->hb_sub.max_hops, cfg->hb_sub.count); if (cfg->hb_sub.func) { cfg->hb_sub.func(hops, feat); @@ -67,7 +73,6 @@ void bt_mesh_heartbeat_recv(uint16_t src, uint16_t dst, uint8_t hops, uint16_t f void bt_mesh_heartbeat_send(void) { struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); - uint16_t feat = 0U; struct __attribute__((packed)) { uint8_t init_ttl; uint16_t feat; @@ -85,6 +90,9 @@ void bt_mesh_heartbeat_send(void) .src = bt_mesh_model_elem(cfg->model)->addr, .xmit = bt_mesh_net_transmit_get(), }; + uint16_t feat = 0U; + + BT_DBG("HeartbeatSend, Dst 0x%04x", cfg->hb_pub.dst); /* Do nothing if heartbeat publication is not enabled */ if (cfg->hb_pub.dst == BLE_MESH_ADDR_UNASSIGNED) { @@ -111,7 +119,7 @@ void bt_mesh_heartbeat_send(void) hb.feat = sys_cpu_to_be16(feat); - BT_INFO("InitTTL %u feat 0x%04x", cfg->hb_pub.ttl, feat); + BT_INFO("InitTTL %u Feat 0x%04x", cfg->hb_pub.ttl, feat); bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb), NULL, NULL); @@ -149,6 +157,8 @@ int bt_mesh_pvnr_register_hb_recv_cb(bt_mesh_pvnr_hb_recv_cb_t cb) int bt_mesh_pvnr_set_hb_recv_filter_type(uint8_t type) { + BT_DBG("PvnrSetHbRecvFilterType"); + if (type > HEARTBEAT_FILTER_REJECTLIST) { BT_ERR("Invalid heartbeat filter type 0x%02x", type); return -EINVAL; @@ -158,6 +168,8 @@ int bt_mesh_pvnr_set_hb_recv_filter_type(uint8_t type) * clear the existing filter entries. */ if (hb_rx.type != type) { + BT_DBG("OldType %u NewType %u", hb_rx.type, type); + memset(&hb_rx, 0, offsetof(struct heartbeat_recv, cb)); hb_rx.type = type; } @@ -169,6 +181,8 @@ static int hb_filter_alloc(uint16_t src, uint16_t dst) { int i; + BT_DBG("HbFilterAlloc, Src 0x%04x Dst 0x%04x", src, dst); + for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { struct heartbeat_filter *filter = &hb_rx.filter[i]; @@ -180,7 +194,7 @@ static int hb_filter_alloc(uint16_t src, uint16_t dst) } } - BT_ERR("Heartbeat filter is full!"); + BT_ERR("HbFilterFull"); return -ENOMEM; } @@ -188,6 +202,8 @@ static int hb_filter_add(uint16_t src, uint16_t dst) { int i; + BT_DBG("HbFilterAdd, Src 0x%04x Dst 0x%04x", src, dst); + if (!(BLE_MESH_ADDR_IS_UNICAST(src) && (BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)))) { BT_ERR("Invalid filter address, src 0x%04x, dst 0x%04x", src, dst); @@ -199,7 +215,7 @@ static int hb_filter_add(uint16_t src, uint16_t dst) struct heartbeat_filter *filter = &hb_rx.filter[i]; if (filter->src == src && filter->dst == dst) { - BT_WARN("Filter already exists, src 0x%04x dst 0x%04x", filter->src, filter->dst); + BT_DBG("FilterIndex %u", i); return 0; } } @@ -211,6 +227,8 @@ static int hb_filter_remove(uint16_t src, uint16_t dst) { int i; + BT_DBG("HbFilterRemove, Src 0x%04x Dst 0x%04x", src, dst); + if (!(BLE_MESH_ADDR_IS_UNICAST(src) && (BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)))) { BT_ERR("Invalid filter address, src 0x%04x, dst 0x%04x", src, dst); @@ -221,6 +239,7 @@ static int hb_filter_remove(uint16_t src, uint16_t dst) struct heartbeat_filter *filter = &hb_rx.filter[i]; if (filter->src == src && filter->dst == dst) { + BT_DBG("FilterIndex %u", i); memset(filter, 0, sizeof(struct heartbeat_filter)); } } @@ -236,7 +255,7 @@ int bt_mesh_pvnr_set_hb_recv_filter_info(uint8_t op, uint16_t src, uint16_t dst) case HEARTBEAT_FILTER_REMOVE: return hb_filter_remove(src, dst); default: - BT_ERR("Invalid heartbeat filter opcode 0x%02x", op); + BT_ERR("Invalid HbFilterOpCode 0x%02x", op); return -EINVAL; } } @@ -248,6 +267,7 @@ static bool filter_with_rejectlist(uint16_t hb_src, uint16_t hb_dst) for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { struct heartbeat_filter *filter = &hb_rx.filter[i]; if (hb_src == filter->src && hb_dst == filter->dst) { + BT_DBG("InRejectList, Src 0x%04x Dst 0x%04x", hb_src, hb_dst); return true; } } @@ -262,6 +282,7 @@ static bool filter_with_acceptlist(uint16_t hb_src, uint16_t hb_dst) for (i = 0; i < ARRAY_SIZE(hb_rx.filter); i++) { struct heartbeat_filter *filter = &hb_rx.filter[i]; if (hb_src == filter->src && hb_dst == filter->dst) { + BT_DBG("InAcceptList, Src 0x%04x Dst 0x%04x", hb_src, hb_dst); return false; } } @@ -273,6 +294,8 @@ void bt_mesh_pvnr_heartbeat_recv(uint16_t hb_src, uint16_t hb_dst, uint8_t init_ttl, uint8_t rx_ttl, uint8_t hops, uint16_t feat, int8_t rssi) { + BT_DBG("PvnrHeartbeatRecv"); + if (hb_rx.cb == NULL) { BT_DBG("Receiving heartbeat is not enabled"); return; @@ -280,16 +303,17 @@ void bt_mesh_pvnr_heartbeat_recv(uint16_t hb_src, uint16_t hb_dst, if (hb_rx.type == HEARTBEAT_FILTER_REJECTLIST) { if (filter_with_rejectlist(hb_src, hb_dst)) { - BT_INFO("Filtered by rejectlist, src 0x%04x, dst 0x%04x", hb_src, hb_dst); return; } } else { if (filter_with_acceptlist(hb_src, hb_dst)) { - BT_INFO("Filtered by acceptlist, src 0x%04x, dst 0x%04x", hb_src, hb_dst); return; } } + BT_DBG("Src 0x%04x Dst 0x%04x InitTTL %u RxTTL %u Hops %u Feat 0x%04x Rssi %d", + hb_src, hb_dst, init_ttl, rx_ttl, hops, feat, rssi); + if (hb_rx.cb) { hb_rx.cb(hb_src, hb_dst, init_ttl, rx_ttl, hops, feat, rssi); } diff --git a/components/bt/esp_ble_mesh/core/local.c b/components/bt/esp_ble_mesh/core/local.c index 4451e0d7b2..fb933cc804 100644 --- a/components/bt/esp_ble_mesh/core/local.c +++ b/components/bt/esp_ble_mesh/core/local.c @@ -22,14 +22,17 @@ static struct bt_mesh_model *find_model(uint16_t elem_addr, uint16_t cid, uint16 { struct bt_mesh_elem *elem = NULL; + BT_DBG("FindModelLocal"); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x", elem_addr, cid, mod_id); + if (!BLE_MESH_ADDR_IS_UNICAST(elem_addr)) { - BT_ERR("Invalid unicast address 0x%04x", elem_addr); + BT_ERR("InvalidUnicastAddr 0x%04x", elem_addr); return NULL; } elem = bt_mesh_elem_find(elem_addr); if (elem == NULL) { - BT_ERR("No element found, addr 0x%04x", elem_addr); + BT_ERR("NoElemFound 0x%04x", elem_addr); return NULL; } @@ -46,19 +49,23 @@ int bt_mesh_model_subscribe_group_addr(uint16_t elem_addr, uint16_t cid, struct bt_mesh_model *model = NULL; int i; + BT_DBG("ModelSubGroupAddrLocal"); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x GroupAddr 0x%04x", + elem_addr, cid, mod_id, group_addr); + model = find_model(elem_addr, cid, mod_id); if (model == NULL) { - BT_ERR("Subscribe, model not found, cid 0x%04x, mod_id 0x%04x", cid, mod_id); + BT_ERR("ModelNotFound, CID 0x%04x ID 0x%04x", cid, mod_id); return -ENODEV; } if (!BLE_MESH_ADDR_IS_GROUP(group_addr)) { - BT_ERR("Subscribe, not a group address 0x%04x", group_addr); + BT_ERR("NotGroupAddr 0x%04x", group_addr); return -EINVAL; } if (bt_mesh_model_find_group(model, group_addr)) { - BT_INFO("Group address 0x%04x already exists", group_addr); + BT_INFO("GroupAddrExist 0x%04x", group_addr); return 0; } @@ -74,12 +81,11 @@ int bt_mesh_model_subscribe_group_addr(uint16_t elem_addr, uint16_t cid, bt_mesh_lpn_group_add(group_addr); } - BT_INFO("Subscribe group address 0x%04x", group_addr); return 0; } } - BT_ERR("Subscribe, model sub is full!"); + BT_ERR("ModelSubFull"); return -ENOMEM; } @@ -89,20 +95,24 @@ int bt_mesh_model_unsubscribe_group_addr(uint16_t elem_addr, uint16_t cid, struct bt_mesh_model *model = NULL; uint16_t *match = NULL; + BT_DBG("ModelUnsubGroupAddrLocal"); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x GroupAddr 0x%04x", + elem_addr, cid, mod_id, group_addr); + model = find_model(elem_addr, cid, mod_id); if (model == NULL) { - BT_ERR("Unsubscribe, model not found, cid 0x%04x, mod_id 0x%04x", cid, mod_id); + BT_ERR("ModelNotFound, CID 0x%04x ID 0x%04x", cid, mod_id); return -ENODEV; } if (!BLE_MESH_ADDR_IS_GROUP(group_addr)) { - BT_ERR("Unsubscribe, not a group address 0x%04x", group_addr); + BT_ERR("NotGroupAddr 0x%04x", group_addr); return -EINVAL; } match = bt_mesh_model_find_group(model, group_addr); if (match == NULL) { - BT_WARN("Group address 0x%04x not exists", group_addr); + BT_WARN("GroupAddrExist 0x%04x", group_addr); return -EEXIST; } @@ -116,7 +126,6 @@ int bt_mesh_model_unsubscribe_group_addr(uint16_t elem_addr, uint16_t cid, bt_mesh_lpn_group_del(&group_addr, 1); } - BT_INFO("Unsubscribe group address 0x%04x", group_addr); return 0; } @@ -126,20 +135,24 @@ int bt_mesh_enable_directed_forwarding(uint16_t net_idx, bool directed_forwardin { struct bt_mesh_subnet *sub = NULL; + BT_DBG("EnableDFLocal, NetIdx 0x%04x DF %u DFRelay %u", + net_idx, directed_forwarding, directed_forwarding_relay); + if (net_idx > 0xFFF) { - BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); + BT_ERR("InvalidNetIdx 0x%04x", net_idx); return -EINVAL; } sub = bt_mesh_subnet_get(net_idx); if (!sub) { - BT_ERR("NetKey 0x%04x not exists", net_idx); + BT_ERR("NetIdxNotExist 0x%04x", net_idx); return -EINVAL; } if (directed_forwarding == BLE_MESH_DIRECTED_FORWARDING_DISABLED && directed_forwarding_relay == BLE_MESH_DIRECTED_RELAY_ENABLED) { - BT_ERR("Invalid Config directed forwarding: %d, directed forwarding relay: %d", directed_forwarding, directed_forwarding_relay); + BT_ERR("InvalidDFConfig %u/%u", + directed_forwarding, directed_forwarding_relay); return -EINVAL; } @@ -155,14 +168,16 @@ const uint8_t *bt_mesh_node_get_local_net_key(uint16_t net_idx) { struct bt_mesh_subnet *sub = NULL; + BT_DBG("NodeGetNetKeyLocal, NetIdx 0x%04x", net_idx); + if (net_idx > 0xFFF) { - BT_ERR("Invalid NetKeyIndex 0x%04x", net_idx); + BT_ERR("InvalidNetIdx 0x%04x", net_idx); return NULL; } sub = bt_mesh_subnet_get(net_idx); if (!sub) { - BT_ERR("NetKey 0x%04x not exists", net_idx); + BT_ERR("NetIdxNotExist 0x%04x", net_idx); return NULL; } @@ -173,14 +188,16 @@ const uint8_t *bt_mesh_node_get_local_app_key(uint16_t app_idx) { struct bt_mesh_app_key *key = NULL; + BT_DBG("NodeGetAppKeyLocal, AppIdx 0x%04x", app_idx); + if (app_idx > 0xFFF) { - BT_ERR("Invalid AppKeyIndex 0x%04x", app_idx); + BT_ERR("InvalidAppIdx 0x%04x", app_idx); return NULL; } key = bt_mesh_app_key_get(app_idx); if (!key) { - BT_ERR("AppKey 0x%04x not exists", app_idx); + BT_ERR("AppIdxNotExist 0x%04x", app_idx); return NULL; } @@ -193,19 +210,21 @@ int bt_mesh_node_local_net_key_add(uint16_t net_idx, const uint8_t net_key[16]) int err = 0; int i; + BT_DBG("NodeAddNetKeyLocal, NetIdx 0x%04x", net_idx); + if (net_idx > 0xFFF || net_key == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } if (!bt_mesh_is_provisioned()) { - BT_ERR("Not provisioned, failed to add NetKey"); + BT_ERR("NotProvisioned"); return -EIO; } sub = bt_mesh_subnet_get(net_idx); if (sub) { - BT_WARN("NetKey 0x%04x already exists", net_idx); + BT_WARN("NetIdxExist 0x%04x", net_idx); return -EEXIST; } @@ -215,7 +234,7 @@ int bt_mesh_node_local_net_key_add(uint16_t net_idx, const uint8_t net_key[16]) memcmp(bt_mesh.sub[i].keys[0].net, net_key, 16) == 0) || (bt_mesh.sub[i].kr_flag == true && memcmp(bt_mesh.sub[i].keys[1].net, net_key, 16) == 0)) { - BT_WARN("Key value %s already exists", bt_hex(net_key, 16)); + BT_WARN("NetKeyValExist %s", bt_hex(net_key, 16)); return -EEXIST; } } @@ -229,13 +248,13 @@ int bt_mesh_node_local_net_key_add(uint16_t net_idx, const uint8_t net_key[16]) } if (sub == NULL) { - BT_ERR("NetKey is full!"); + BT_ERR("NetKeyFull"); return -ENOMEM; } err = bt_mesh_net_keys_create(&sub->keys[0], net_key); if (err) { - BT_ERR("Failed to create keys for NetKey 0x%04x", net_idx); + BT_ERR("NetKeyCreateFail 0x%04x", net_idx); return -EIO; } @@ -249,7 +268,6 @@ int bt_mesh_node_local_net_key_add(uint16_t net_idx, const uint8_t net_key[16]) } if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing NetKey persistently"); bt_mesh_store_subnet(sub); } @@ -264,24 +282,26 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, { struct bt_mesh_app_key *key = NULL; + BT_DBG("NodeAddAppKeyLocal, NetIdx 0x%04x AppIdx 0x%04x", net_idx, app_idx); + if (net_idx > 0xFFF || app_idx > 0xFFF || app_key == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } if (!bt_mesh_is_provisioned()) { - BT_ERR("Not provisioned, failed to add AppKey"); + BT_ERR("NotProvisioned"); return -EIO; } if (bt_mesh_subnet_get(net_idx) == NULL) { - BT_ERR("Subnet 0x%04x not exists", net_idx); + BT_ERR("NetIdxNotExist 0x%04x", net_idx); return -EIO; } key = bt_mesh_app_key_get(app_idx); if (key) { - BT_WARN("AppKey 0x%04x already exists", app_idx); + BT_WARN("AppIdxExist 0x%04x", app_idx); return -EEXIST; } @@ -291,7 +311,7 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, memcmp(bt_mesh.app_keys[i].keys[0].val, app_key, 16) == 0) || (bt_mesh.app_keys[i].updated == true && memcmp(bt_mesh.app_keys[i].keys[1].val, app_key, 16) == 0)) { - BT_WARN("Key value %s already exists", bt_hex(app_key, 16)); + BT_WARN("AppKeyValExist %s", bt_hex(app_key, 16)); return -EEXIST; } } @@ -302,7 +322,7 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, struct bt_mesh_app_keys *keys = &key->keys[0]; if (bt_mesh_app_id(app_key, &keys->id)) { - BT_ERR("Failed to generate AID"); + BT_ERR("GenAIDFail"); return -EIO; } @@ -312,15 +332,12 @@ int bt_mesh_node_local_app_key_add(uint16_t net_idx, uint16_t app_idx, memcpy(keys->val, app_key, 16); if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing AppKey persistently"); bt_mesh_store_app_key(key); } - BT_INFO("Add AppKey 0x%04x, NetKeyIndex 0x%04x", app_idx, net_idx); return 0; } - BT_ERR("AppKey is full!"); return -ENOMEM; } @@ -330,25 +347,29 @@ int bt_mesh_node_bind_app_key_to_model(uint16_t elem_addr, uint16_t mod_id, struct bt_mesh_model *model = NULL; int i; + BT_DBG("NodeBindAppKeyLocal"); + BT_DBG("ElemAddr 0x%04x CID 0x%04x ID 0x%04x AppIdx 0x%04x", + elem_addr, cid, mod_id, app_idx); + if (!bt_mesh_is_provisioned()) { - BT_ERR("Not provisioned, failed to bind AppKey"); + BT_ERR("NotProvisioned"); return -EIO; } model = find_model(elem_addr, cid, mod_id); if (model == NULL) { - BT_ERR("Bind, model(id 0x%04x, cid 0x%04x) not found", mod_id, cid); + BT_ERR("ModelNotFound, ID 0x%04x CID 0x%04x", mod_id, cid); return -ENODEV; } if (bt_mesh_app_key_get(app_idx) == NULL) { - BT_ERR("Bind, AppKey 0x%03x not exists", app_idx); + BT_ERR("AppIdxNotExist 0x%04x", app_idx); return -ENODEV; } for (i = 0; i < ARRAY_SIZE(model->keys); i++) { if (model->keys[i] == app_idx) { - BT_WARN("Already bound to AppKey 0x%04x", app_idx); + BT_WARN("AppIdxBound 0x%04x", app_idx); return -EALREADY; } } @@ -356,16 +377,16 @@ int bt_mesh_node_bind_app_key_to_model(uint16_t elem_addr, uint16_t mod_id, for (i = 0; i < ARRAY_SIZE(model->keys); i++) { if (model->keys[i] == BLE_MESH_KEY_UNUSED) { model->keys[i] = app_idx; + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_store_mod_bind(model); } - BT_INFO("Model(id 0x%04x, cid 0x%04x) bound to AppKey 0x%04x", mod_id, cid, app_idx); return 0; } } - BT_ERR("Model bound is full!"); + BT_ERR("ModelBindFull"); return -ENOMEM; } #endif /* CONFIG_BLE_MESH_NODE */ diff --git a/components/bt/esp_ble_mesh/core/lpn.c b/components/bt/esp_ble_mesh/core/lpn.c index 80f5b4321a..a38b0944e4 100644 --- a/components/bt/esp_ble_mesh/core/lpn.c +++ b/components/bt/esp_ble_mesh/core/lpn.c @@ -81,30 +81,30 @@ static const char *state2str(int state) { switch (state) { case BLE_MESH_LPN_DISABLED: - return "disabled"; + return "Disabled"; case BLE_MESH_LPN_CLEAR: - return "clear"; + return "Clear"; case BLE_MESH_LPN_TIMER: - return "timer"; + return "Timer"; case BLE_MESH_LPN_ENABLED: - return "enabled"; + return "Enabled"; case BLE_MESH_LPN_REQ_WAIT: - return "req wait"; + return "ReqWait"; case BLE_MESH_LPN_WAIT_OFFER: - return "wait offer"; + return "WaitOffer"; case BLE_MESH_LPN_ESTABLISHED: - return "established"; + return "Established"; case BLE_MESH_LPN_RECV_DELAY: - return "recv delay"; + return "RecvDelay"; case BLE_MESH_LPN_WAIT_UPDATE: - return "wait update"; + return "WaitUpdate"; case BLE_MESH_LPN_OFFER_RECV: - return "offer recv"; + return "OfferRecv"; default: - return "(unknown)"; + return "(Unknown)"; } } -#endif +#endif /* !CONFIG_BLE_MESH_NO_LOG */ static inline void lpn_set_state(int state) { @@ -120,9 +120,9 @@ static inline void group_zero(bt_mesh_atomic_t *target) for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { bt_mesh_atomic_set(&target[i], 0); } -#else +#else /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ bt_mesh_atomic_set(target, 0); -#endif +#endif /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ } static inline void group_set(bt_mesh_atomic_t *target, bt_mesh_atomic_t *source) @@ -133,9 +133,9 @@ static inline void group_set(bt_mesh_atomic_t *target, bt_mesh_atomic_t *source) for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { (void)bt_mesh_atomic_or(&target[i], bt_mesh_atomic_get(&source[i])); } -#else +#else /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ (void)bt_mesh_atomic_or(target, bt_mesh_atomic_get(source)); -#endif +#endif /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ } static inline void group_clear(bt_mesh_atomic_t *target, bt_mesh_atomic_t *source) @@ -146,9 +146,9 @@ static inline void group_clear(bt_mesh_atomic_t *target, bt_mesh_atomic_t *sourc for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { (void)bt_mesh_atomic_and(&target[i], ~bt_mesh_atomic_get(&source[i])); } -#else +#else /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ (void)bt_mesh_atomic_and(target, ~bt_mesh_atomic_get(source)); -#endif +#endif /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ } static void clear_friendship(bool force, bool disable); @@ -159,6 +159,8 @@ static void friend_clear_sent(int err, void *user_data) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("FrndClearSent, Err %d", err); + /* We're switching away from Low Power behavior, so permanently * enable scanning. */ @@ -169,6 +171,8 @@ static void friend_clear_sent(int err, void *user_data) lpn->req_attempts++; + BT_DBG("ReqAttempts %u", lpn->req_attempts); + if (err) { BT_ERR("Sending Friend Clear failed (err %d)", err); lpn_set_state(BLE_MESH_LPN_ENABLED); @@ -206,6 +210,8 @@ static int send_friend_clear(void) .lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.counter), }; + BT_DBG("SendFrndClear"); + return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req, sizeof(req), &clear_sent_cb, NULL); } @@ -215,10 +221,12 @@ static void clear_friendship(bool force, bool disable) struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - BT_DBG("force %u disable %u", force, disable); + BT_DBG("ClearFriendship, Force %u Disable %u", force, disable); if (!force && lpn->established && !lpn->clear_success && lpn->req_attempts < CLEAR_ATTEMPTS) { + BT_DBG("SendFrndClear, ReqAttempts %u", lpn->req_attempts); + send_friend_clear(); lpn->disable = disable; return; @@ -253,7 +261,7 @@ static void clear_friendship(bool force, bool disable) bt_mesh_restore_directed_forwarding_state(bt_mesh.sub[0].net_idx, lpn->old_directed_forwarding); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ lpn->frnd = BLE_MESH_ADDR_UNASSIGNED; lpn->fsn = 0U; @@ -306,6 +314,8 @@ static void friend_req_sent(uint16_t duration, int err, void *user_data) return; } + BT_DBG("FrndReqSent, duration %u", duration); + lpn->adv_duration = duration; if (IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { @@ -349,6 +359,8 @@ static int send_friend_req(struct bt_mesh_lpn *lpn) .lpn_counter = sys_cpu_to_be16(lpn->counter), }; + BT_DBG("SendFrndReq, NetIdx 0x%04x", ctx.net_idx); + return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_REQ, &req, sizeof(req), &friend_req_sent_cb, NULL); } @@ -357,7 +369,7 @@ static void req_sent(uint16_t duration, int err, void *user_data) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - BT_DBG("req 0x%02x duration %u err %d state %s", + BT_DBG("ReqSent, Req 0x%02x Duration %u Err %d State %s", lpn->sent_req, duration, err, state2str(lpn->state)); if (err) { @@ -372,6 +384,9 @@ static void req_sent(uint16_t duration, int err, void *user_data) if (lpn->established || IS_ENABLED(CONFIG_BLE_MESH_LPN_ESTABLISHMENT)) { lpn_set_state(BLE_MESH_LPN_RECV_DELAY); + + BT_DBG("RecvDelay %u ScanLatency %u", LPN_RECV_DELAY, SCAN_LATENCY); + /* We start scanning a bit early to eliminate risk of missing * response data due to HCI and other latencies. */ @@ -379,6 +394,9 @@ static void req_sent(uint16_t duration, int err, void *user_data) LPN_RECV_DELAY - SCAN_LATENCY); } else { lpn_set_state(BLE_MESH_LPN_OFFER_RECV); + + BT_DBG("RecvDelay %u RecvWin %u", LPN_RECV_DELAY, lpn->recv_win); + /** * Friend Update is replied by Friend Node with TTL set to 0 and Network * Transmit set to 30ms which will cause the packet easy to be missed. @@ -416,7 +434,7 @@ static int send_friend_poll(void) uint8_t fsn = lpn->fsn; int err = 0; - BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req); + BT_DBG("SendFrndPoll, Req 0x%02x ", lpn->sent_req); if (lpn->sent_req) { if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { @@ -438,6 +456,8 @@ static int send_friend_poll(void) void bt_mesh_lpn_disable(bool force) { + BT_DBG("LPNDisable, Force %u State 0x%02x", force, bt_mesh.lpn.state); + if (bt_mesh.lpn.state == BLE_MESH_LPN_DISABLED) { return; } @@ -449,6 +469,8 @@ int bt_mesh_lpn_set(bool enable, bool force) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNSet, Enable %u Force %u State 0x%02x", enable, force, lpn->state); + if (enable) { if (lpn->state != BLE_MESH_LPN_DISABLED) { return 0; @@ -479,7 +501,7 @@ int bt_mesh_lpn_set(bool enable, bool force) send_friend_req(lpn); } else { if (IS_ENABLED(CONFIG_BLE_MESH_LPN_AUTO) && - lpn->state == BLE_MESH_LPN_TIMER) { + lpn->state == BLE_MESH_LPN_TIMER) { k_delayed_work_cancel(&lpn->timer); lpn_set_state(BLE_MESH_LPN_DISABLED); } else { @@ -492,7 +514,7 @@ int bt_mesh_lpn_set(bool enable, bool force) static void friend_response_received(struct bt_mesh_lpn *lpn) { - BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req); + BT_DBG("FrndRspRecv, Req 0x%02x Fsn %u", lpn->sent_req, lpn->fsn); if (lpn->sent_req == TRANS_CTL_OP_FRIEND_POLL) { lpn->fsn++; @@ -509,6 +531,8 @@ void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNMsgRecv, Req 0x%02x State 0x%02x", lpn->sent_req, lpn->state); + if (lpn->state == BLE_MESH_LPN_TIMER) { BT_DBG("Restarting establishment timer"); k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); @@ -522,8 +546,6 @@ void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) friend_response_received(lpn); - BT_DBG("Requesting more messages from Friend"); - send_friend_poll(); } @@ -537,6 +559,8 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, uint16_t frnd_counter = 0U; int err = 0; + BT_DBG("LPNFrndOffer"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Offer"); return -EINVAL; @@ -554,9 +578,9 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, frnd_counter = sys_be16_to_cpu(msg->frnd_counter); - BT_INFO("recv_win %u queue_size %u sub_list_size %u rssi %d counter %u", - msg->recv_win, msg->queue_size, msg->sub_list_size, msg->rssi, - frnd_counter); + BT_INFO("Frnd 0x%04x RecvWin %u QueueSize %u SubListSize %u FrndCounter %u Rssi %d", + rx->ctx.addr, msg->recv_win, msg->queue_size, + msg->sub_list_size, frnd_counter, msg->rssi); lpn->frnd = rx->ctx.addr; @@ -575,6 +599,8 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, err = send_friend_poll(); if (err) { + BT_ERR("SendFrndPollFailed, Err %d", err); + friend_cred_clear(cred); lpn->frnd = BLE_MESH_ADDR_UNASSIGNED; lpn->recv_win = 0U; @@ -598,6 +624,8 @@ int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, struct bt_mesh_lpn *lpn = &bt_mesh.lpn; uint16_t addr = 0U, counter = 0U; + BT_DBG("LPNFrndClearCFM"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Clear Confirm"); return -EINVAL; @@ -611,7 +639,7 @@ int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, addr = sys_be16_to_cpu(msg->lpn_addr); counter = sys_be16_to_cpu(msg->lpn_counter); - BT_DBG("LPNAddress 0x%04x LPNCounter 0x%04x", addr, counter); + BT_DBG("LPN 0x%04x Counter 0x%04x", addr, counter); if (addr != bt_mesh_primary_addr() || counter != lpn->counter) { BT_WARN("Invalid parameters in Friend Clear Confirm"); @@ -630,8 +658,11 @@ static void lpn_group_add(uint16_t group) uint16_t *free_slot = NULL; int i; + BT_DBG("LPNGroupAdd, Addr 0x%04x", group); + for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { if (lpn->groups[i] == group) { + BT_DBG("ClearLPNToRemove"); bt_mesh_atomic_clear_bit(lpn->to_remove, i); return; } @@ -655,10 +686,13 @@ static void lpn_group_del(uint16_t group) struct bt_mesh_lpn *lpn = &bt_mesh.lpn; int i; + BT_DBG("LPNGroupDel, Addr 0x%04x", group); + for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) { if (lpn->groups[i] == group) { if (bt_mesh_atomic_test_bit(lpn->added, i) || bt_mesh_atomic_test_bit(lpn->pending, i)) { + BT_DBG("Set LPNToRemove"); bt_mesh_atomic_set_bit(lpn->to_remove, i); lpn->groups_changed = 1U; } else { @@ -676,9 +710,9 @@ static inline int group_popcount(bt_mesh_atomic_t *target) for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) { count += popcount(bt_mesh_atomic_get(&target[i])); } -#else +#else /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ return popcount(bt_mesh_atomic_get(target)); -#endif +#endif /* CONFIG_BLE_MESH_LPN_GROUPS > 32 */ } static bool sub_update(uint8_t op) @@ -703,7 +737,7 @@ static bool sub_update(uint8_t op) struct bt_mesh_ctl_friend_sub req = {0}; size_t i = 0U, g = 0U; - BT_DBG("op 0x%02x sent_req 0x%02x", op, lpn->sent_req); + BT_DBG("SubUpdate, OP 0x%02x Req 0x%02x ", op, lpn->sent_req); if (lpn->sent_req) { return false; @@ -725,7 +759,8 @@ static bool sub_update(uint8_t op) } if (added_count + g >= lpn->queue_size) { - BT_WARN("Friend Queue Size exceeded"); + BT_WARN("FrndQueueExceeded, Added %u G %u Size %u", + added_count, g, lpn->queue_size); break; } @@ -744,6 +779,8 @@ static bool sub_update(uint8_t op) req.xact = lpn->xact_next++; + BT_DBG("Xact %u G %u", req.xact, g); + if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2, &req_sent_cb, NULL) < 0) { group_zero(lpn->pending); @@ -752,14 +789,19 @@ static bool sub_update(uint8_t op) lpn->xact_pending = req.xact; lpn->sent_req = op; + return true; } static void update_timeout(struct bt_mesh_lpn *lpn) { + BT_DBG("UpdateTimeout"); + if (lpn->established) { BT_WARN("No response from Friend during ReceiveWindow"); + bt_mesh_scan_disable(); + lpn_set_state(BLE_MESH_LPN_ESTABLISHED); k_delayed_work_submit(&lpn->timer, POLL_RETRY_TIMEOUT); } else { @@ -767,6 +809,8 @@ static void update_timeout(struct bt_mesh_lpn *lpn) bt_mesh_scan_disable(); } + BT_DBG("ReqAttempts %u", lpn->req_attempts); + if (lpn->req_attempts < FIRST_POLL_ATTEMPTS) { BT_WARN("Retrying first Friend Poll"); lpn->sent_req = 0U; @@ -784,7 +828,7 @@ static void lpn_timeout(struct k_work *work) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - BT_DBG("state: %s", state2str(lpn->state)); + BT_DBG("LPNTimeout, State: %s", state2str(lpn->state)); switch (lpn->state) { case BLE_MESH_LPN_DISABLED: @@ -830,6 +874,8 @@ static void lpn_timeout(struct k_work *work) clear_friendship(true, false); break; case BLE_MESH_LPN_ESTABLISHED: + BT_DBG("ReqAttempts %u vs. %u", lpn->req_attempts, REQ_ATTEMPTS(lpn)); + if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) { uint8_t req = lpn->sent_req; @@ -867,11 +913,13 @@ static void lpn_timeout(struct k_work *work) void bt_mesh_lpn_group_add(uint16_t group) { - BT_DBG("group 0x%04x", group); + BT_DBG("LPNGroupAdd, Addr 0x%04x", group); lpn_group_add(group); if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) { + BT_INFO("Established %u Req 0x%02x", + bt_mesh_lpn_established(), bt_mesh.lpn.sent_req); return; } @@ -882,6 +930,8 @@ void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count) { int i; + BT_DBG("LPNGroupDel, GroupCount %u", group_count); + for (i = 0; i < group_count; i++) { if (groups[i] != BLE_MESH_ADDR_UNASSIGNED) { BT_DBG("group 0x%04x", groups[i]); @@ -890,6 +940,8 @@ void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count) } if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) { + BT_INFO("Established %u Req 0x%02x", + bt_mesh_lpn_established(), bt_mesh.lpn.sent_req); return; } @@ -900,6 +952,7 @@ static int32_t poll_timeout(struct bt_mesh_lpn *lpn) { /* If we're waiting for segment acks keep polling at high freq */ if (bt_mesh_tx_in_progress()) { + BT_DBG("PollTimeout, Max %u", POLL_TIMEOUT_MAX(lpn)); return MIN(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); } @@ -909,7 +962,7 @@ static int32_t poll_timeout(struct bt_mesh_lpn *lpn) POLL_TIMEOUT_MAX(lpn)); } - BT_DBG("Poll Timeout is %ums", lpn->poll_timeout); + BT_DBG("PollTimeout %u", lpn->poll_timeout); return lpn->poll_timeout; } @@ -920,12 +973,15 @@ int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, struct bt_mesh_ctl_friend_sub_confirm *msg = (void *)buf->data; struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNFrndSubCFM"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Subscription Confirm"); return -EINVAL; } - BT_DBG("xact 0x%02x", msg->xact); + BT_DBG("Xact %u Req 0x%02x GroupsChanged %u PendingPoll %u", + msg->xact, lpn->sent_req, lpn->groups_changed, lpn->pending_poll); if (!lpn->sent_req) { BT_WARN("No pending subscription list message"); @@ -987,11 +1043,16 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, struct bt_mesh_subnet *sub = rx->sub; uint32_t iv_index = 0U; + BT_DBG("LPNFrndUpdate"); + if (buf->len < sizeof(*msg)) { BT_WARN("Too short Friend Update"); return -EINVAL; } + BT_DBG("Req 0x%02x KrPhase %u Established %u", + lpn->sent_req, sub->kr_phase, lpn->established); + if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) { BT_WARN("Unexpected friend update"); return 0; @@ -1034,8 +1095,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, } /* Set initial poll timeout */ - lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn), - POLL_TIMEOUT_INIT); + lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn), POLL_TIMEOUT_INIT); /* If the Low Power node supports directed forwarding functionality when * the friendship is established in a subnet, the Low Power node shall @@ -1046,18 +1106,16 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, */ #if CONFIG_BLE_MESH_DF_SRV lpn->old_directed_forwarding = bt_mesh_get_and_disable_directed_forwarding_state(sub); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } friend_response_received(lpn); iv_index = sys_be32_to_cpu(msg->iv_index); - BT_INFO("flags 0x%02x iv_index 0x%08x md %u", msg->flags, iv_index, - msg->md); + BT_INFO("Flags 0x%02x IVIndex 0x%08lx MD %u", msg->flags, iv_index, msg->md); - if (bt_mesh_kr_update(sub, BLE_MESH_KEY_REFRESH(msg->flags), - rx->new_key)) { + if (bt_mesh_kr_update(sub, BLE_MESH_KEY_REFRESH(msg->flags), rx->new_key)) { bt_mesh_net_secure_beacon_update(sub); } @@ -1086,12 +1144,12 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, int bt_mesh_lpn_poll(void) { + BT_DBG("LPNPoll, Established %u", bt_mesh.lpn.established); + if (!bt_mesh.lpn.established) { return -EAGAIN; } - BT_DBG("Requesting more messages"); - return send_friend_poll(); } @@ -1104,6 +1162,8 @@ int bt_mesh_lpn_init(void) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNInit"); + k_delayed_work_init(&lpn->timer, lpn_timeout); if (lpn->state == BLE_MESH_LPN_ENABLED) { @@ -1130,6 +1190,8 @@ int bt_mesh_lpn_deinit(void) { struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + BT_DBG("LPNDeinit"); + bt_mesh_lpn_disable(true); k_delayed_work_free(&lpn->timer); diff --git a/components/bt/esp_ble_mesh/core/main.c b/components/bt/esp_ble_mesh/core/main.c index 957234e312..3b6dcb1402 100644 --- a/components/bt/esp_ble_mesh/core/main.c +++ b/components/bt/esp_ble_mesh/core/main.c @@ -32,12 +32,14 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ static bool mesh_init = false; bool bt_mesh_is_initialized(void) { + BT_DBG("IsInitialized %u", mesh_init); + return mesh_init; } @@ -48,9 +50,10 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, bool pb_gatt_enabled = false; int err = 0; - BT_INFO("Primary Element: 0x%04x", addr); - BT_INFO("net_idx 0x%04x flags 0x%02x iv_index 0x%04x", - net_idx, flags, iv_index); + BT_INFO("NodeProvisioned"); + BT_INFO("PrimaryAddr 0x%04x", addr); + BT_INFO("NetIdx 0x%04x Flags 0x%02x IVIndex 0x%08lx", + net_idx, flags, iv_index); BT_INFO("DevKey %s", bt_hex(dev_key, 16)); BT_INFO("NetKey %s", bt_hex(net_key, 16)); @@ -69,9 +72,12 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, pb_gatt_enabled = false; } + BT_DBG("PbGattEnabled %u", pb_gatt_enabled); + err = bt_mesh_net_create(net_idx, flags, net_key, iv_index); if (err) { BT_ERR("Create network for node failed"); + bt_mesh_atomic_clear_bit(bt_mesh.flags, BLE_MESH_VALID); if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && pb_gatt_enabled) { @@ -89,11 +95,11 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && IS_ENABLED(CONFIG_BLE_MESH_LPN_SUB_ALL_NODES_ADDR)) { + BT_DBG("LPNAllNodesAdded"); bt_mesh_lpn_group_add(BLE_MESH_ADDR_ALL_NODES); } if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing network information persistently"); bt_mesh_store_net(); bt_mesh_store_subnet(&bt_mesh.sub[0]); bt_mesh_store_iv(false); @@ -106,6 +112,8 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, void bt_mesh_node_reset(void) { + BT_DBG("NodeLocalReset"); + if (!bt_mesh_is_provisioned()) { BT_WARN("%s, Not provisioned", __func__); return; @@ -154,7 +162,7 @@ void bt_mesh_node_reset(void) #if CONFIG_BLE_MESH_PRB_SRV bt_mesh_private_beacon_disable(); -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ bt_mesh_comp_unprovision(); @@ -165,7 +173,7 @@ void bt_mesh_node_reset(void) bt_mesh_clear_role(); #if CONFIG_BLE_MESH_DF_SRV bt_mesh_clear_all_directed_forwarding_table_data(); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } memset(bt_mesh.flags, 0, sizeof(bt_mesh.flags)); @@ -177,34 +185,52 @@ void bt_mesh_node_reset(void) bool bt_mesh_is_node(void) { - return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_NODE); + bool is_node = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_NODE); + + BT_DBG("IsNode %u", is_node); + + return is_node; } bool bt_mesh_is_provisioned(void) { + bool is_provisioned = false; + if (bt_mesh_is_node()) { - return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID); - } else { - return false; + is_provisioned = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID); } + + BT_DBG("IsProvisioned %u", is_provisioned); + + return is_provisioned; } bool bt_mesh_is_provisioner(void) { - return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_PROVISIONER); + bool is_pvnr = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_PROVISIONER); + + BT_DBG("IsPvnr %u", is_pvnr); + + return is_pvnr; } bool bt_mesh_is_provisioner_en(void) { + bool is_pvnr_en = false; + if (bt_mesh_is_provisioner()) { - return bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID_PROV); + is_pvnr_en = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID_PROV); } - return false; + BT_DBG("IsPvnrEn %u", is_pvnr_en); + + return is_pvnr_en; } static bool prov_bearers_valid(bt_mesh_prov_bearer_t bearers) { + BT_DBG("ProvBearersValid, Bearers 0x%02x", bearers); + if ((!(bearers & (BLE_MESH_PROV_ADV | BLE_MESH_PROV_GATT))) || (IS_ENABLED(CONFIG_BLE_MESH_PB_ADV) && !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && @@ -215,6 +241,7 @@ static bool prov_bearers_valid(bt_mesh_prov_bearer_t bearers) BT_ERR("Invalid bearers 0x%02x", bearers); return false; } + return true; } @@ -222,6 +249,8 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) { int err = 0; + BT_DBG("ProvEnable, Bearers 0x%02x", bearers); + if (bt_mesh_is_provisioned()) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -247,6 +276,7 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) if (role == BLE_MESH_SETTINGS_ROLE_NONE) { bt_mesh_atomic_set_bit(bt_mesh.flags, BLE_MESH_NODE); } + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS_BACKWARD_COMPATIBILITY) || role == BLE_MESH_SETTINGS_ROLE_NONE) { if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { @@ -277,6 +307,8 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers) int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) { + BT_DBG("ProvDisable, Bearers 0x%02x", bearers); + if (bt_mesh_is_provisioned()) { BT_WARN("%s, Already provisioned", __func__); return -EALREADY; @@ -309,6 +341,8 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("ModelSuspend, Vnd %u Primary %u", vnd, primary); + if (mod->pub && mod->pub->update) { mod->pub->count = 0U; k_delayed_work_cancel(&mod->pub->timer); @@ -319,6 +353,8 @@ int bt_mesh_suspend(void) { int err = 0; + BT_DBG("Suspend"); + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { return -EINVAL; } @@ -344,7 +380,7 @@ int bt_mesh_suspend(void) if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_disable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ bt_mesh_model_foreach(model_suspend, NULL); @@ -354,6 +390,8 @@ int bt_mesh_suspend(void) static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("ModelResume, Vnd %u Primary %u", vnd, primary); + if (mod->pub && mod->pub->update) { int32_t period_ms = bt_mesh_model_pub_period_get(mod); @@ -367,6 +405,8 @@ int bt_mesh_resume(void) { int err = 0; + BT_DBG("Resume"); + if (!bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_VALID)) { return -EINVAL; } @@ -390,7 +430,7 @@ int bt_mesh_resume(void) if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_enable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ bt_mesh_model_foreach(model_resume, NULL); @@ -402,6 +442,8 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, { int err = 0; + BT_DBG("Init"); + if (mesh_init == true) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -414,7 +456,7 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, BT_ERR("Bluetooth Mesh v1.1 init failed"); return err; } -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ bt_mesh_mutex_init(); @@ -452,7 +494,7 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, if (err) { return err; } -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC */ if (IS_ENABLED(CONFIG_BLE_MESH_PROV)) { err = bt_mesh_prov_set(prov); @@ -507,6 +549,8 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param) { int err = 0; + BT_DBG("Deinit"); + if (param == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -522,7 +566,7 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param) #if CONFIG_BLE_MESH_PRB_SRV bt_mesh_private_beacon_disable(); -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node()) { if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && @@ -583,7 +627,7 @@ int bt_mesh_deinit(struct bt_mesh_deinit_param *param) #if CONFIG_BLE_MESH_PROXY_SOLIC bt_mesh_proxy_solic_deinit(); -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC */ if ((IS_ENABLED(CONFIG_BLE_MESH_NODE) && IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) || @@ -638,6 +682,8 @@ int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) { int err = 0; + BT_DBG("PvnrEnable, Bearers 0x%02x", bearers); + if (bt_mesh_is_provisioner_en()) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -703,7 +749,7 @@ int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) BLE_MESH_EXCEP_LIST_TYPE_MESH_PROV_ADV, NULL); } -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && (bearers & BLE_MESH_PROV_GATT)) { @@ -722,7 +768,7 @@ int bt_mesh_provisioner_enable(bt_mesh_prov_bearer_t bearers) if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_enable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ err = bt_mesh_scan_enable(); if (err) { @@ -736,6 +782,8 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) { bt_mesh_prov_bearer_t enable = 0U; + BT_DBG("PvnrDisable, Bearers 0x%02x", bearers); + if (!bt_mesh_is_provisioner_en()) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -762,7 +810,7 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_REMOVE, BLE_MESH_EXCEP_LIST_TYPE_MESH_PROV_ADV, NULL); -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ } if (!(enable & (~bearers))) { @@ -776,7 +824,7 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, NULL); } -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ /* Clear corresponding flags */ bt_mesh_atomic_and(bt_mesh.flags, ~(BIT(BLE_MESH_PROVISIONER) | BIT(BLE_MESH_VALID_PROV))); @@ -794,7 +842,7 @@ int bt_mesh_provisioner_disable(bt_mesh_prov_bearer_t bearers) if (bt_mesh_private_beacon_state_get() == BLE_MESH_PRIVATE_BEACON_ENABLED) { bt_mesh_private_beacon_disable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { bt_mesh_friend_clear_net_idx(BLE_MESH_KEY_ANY); diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index 3d14092704..5ddbb46ca0 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.c @@ -33,7 +33,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ /* Minimum valid Mesh Network PDU length. The Network headers * themselves take up 9 bytes. After that there is a minimum of 1 byte @@ -41,23 +41,27 @@ * PDUs must use a 64-bit (8 byte) NetMIC, whereas CTL=0 PDUs have at least * a 32-bit (4 byte) NetMIC and AppMIC giving again a total of 8 bytes. */ -#define BLE_MESH_NET_MIN_PDU_LEN (BLE_MESH_NET_HDR_LEN + 1 + 8) +#define BLE_MESH_NET_MIN_PDU_LEN (BLE_MESH_NET_HDR_LEN + 1 + 8) /* Seq limit after IV Update is triggered */ -#define IV_UPDATE_SEQ_LIMIT 8000000 +#define IV_UPDATE_SEQ_LIMIT 8000000 /* Determine how many friendship credentials we need */ #if CONFIG_BLE_MESH_FRIEND -#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_FRIEND_LPN_COUNT +#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_FRIEND_LPN_COUNT #elif CONFIG_BLE_MESH_LOW_POWER -#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_SUBNET_COUNT +#define FRIEND_CRED_COUNT CONFIG_BLE_MESH_SUBNET_COUNT #else -#define FRIEND_CRED_COUNT 0 +#define FRIEND_CRED_COUNT 0 #endif +#if CONFIG_BLE_MESH_RELAY_ADV_BUF +#define MAX_STORED_RELAY_COUNT (CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT / 2) +#endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ + #if FRIEND_CRED_COUNT > 0 static struct friend_cred friend_cred[FRIEND_CRED_COUNT]; -#endif +#endif /* FRIEND_CRED_COUNT > 0 */ static struct { uint32_t src:15, /* MSB of source address is always 0 */ @@ -83,10 +87,6 @@ struct bt_mesh_net bt_mesh = { static uint32_t dup_cache[4]; static int dup_cache_next; -#if CONFIG_BLE_MESH_RELAY_ADV_BUF -#define BLE_MESH_MAX_STORED_RELAY_COUNT (CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT / 2) -#endif - static bool check_dup(struct net_buf_simple *data) { const uint8_t *tail = net_buf_simple_tail(data); @@ -95,12 +95,17 @@ static bool check_dup(struct net_buf_simple *data) val = sys_get_be32(tail - 4) ^ sys_get_be32(tail - 8); + BT_DBG("CheckDup, Val 0x%08lx", val); + for (i = 0; i < ARRAY_SIZE(dup_cache); i++) { if (dup_cache[i] == val) { + BT_DBG("DupCacheFound"); return true; } } + BT_DBG("DupCacheAdd, CacheNext %ld", val, dup_cache_next); + dup_cache[dup_cache_next++] = val; dup_cache_next %= ARRAY_SIZE(dup_cache); @@ -112,9 +117,13 @@ static bool msg_cache_match(struct bt_mesh_net_rx *rx, { int i; + BT_DBG("MsgCacheMatch"); + for (i = 0; i < ARRAY_SIZE(msg_cache); i++) { if (msg_cache[i].src == BLE_MESH_NET_HDR_SRC(pdu->data) && msg_cache[i].seq == (BLE_MESH_NET_HDR_SEQ(pdu->data) & BIT_MASK(17))) { + BT_DBG("CacheFound, Src 0x%04x Seq 0x%06x", + msg_cache[i].src, msg_cache[i].seq); return true; } } @@ -124,6 +133,9 @@ static bool msg_cache_match(struct bt_mesh_net_rx *rx, static void msg_cache_add(struct bt_mesh_net_rx *rx) { + BT_DBG("MsgCacheAdd, Src 0x%04x Seq 0x%06x CacheNext %u", + rx->ctx.addr, rx->seq, msg_cache_next); + rx->msg_cache_idx = msg_cache_next++; msg_cache[rx->msg_cache_idx].src = rx->ctx.addr; msg_cache[rx->msg_cache_idx].seq = rx->seq; @@ -135,6 +147,8 @@ void bt_mesh_msg_cache_clear(uint16_t unicast_addr, uint8_t elem_num) { int i; + BT_DBG("MsgCacheClear, Addr 0x%04x ElemNum %u", unicast_addr, elem_num); + for (i = 0; i < ARRAY_SIZE(msg_cache); i++) { if (msg_cache[i].src >= unicast_addr && msg_cache[i].src < unicast_addr + elem_num) { @@ -146,6 +160,8 @@ void bt_mesh_msg_cache_clear(uint16_t unicast_addr, uint8_t elem_num) struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) { + BT_DBG("SubnetGet, NetIdx 0x%04x", net_idx); + if (bt_mesh_is_provisioned()) { #if CONFIG_BLE_MESH_NODE if (!IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { @@ -161,7 +177,7 @@ struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) } else { return bt_mesh_fast_prov_subnet_get(net_idx); } -#endif +#endif /* CONFIG_BLE_MESH_NODE */ } else if (bt_mesh_is_provisioner_en()) { #if CONFIG_BLE_MESH_PROVISIONER if (net_idx == BLE_MESH_KEY_ANY) { @@ -174,7 +190,7 @@ struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx) return bt_mesh.p_sub[i]; } } -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ } return NULL; @@ -187,6 +203,8 @@ int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, uint8_t nid = 0U; int err = 0; + BT_DBG("NetKeysCreate"); + err = bt_mesh_k2(key, p, sizeof(p), &nid, keys->enc, keys->privacy); if (err) { BT_ERR("Unable to generate NID, EncKey & PrivacyKey"); @@ -258,6 +276,9 @@ int friend_cred_set(struct friend_cred *cred, uint8_t idx, const uint8_t net_key uint8_t p[9] = {0}; int err = 0; + BT_DBG("FrndCredSet, NetIdx 0x%04x Addr 0x%04x Idx %u", + cred->net_idx, cred->addr, idx); + #if CONFIG_BLE_MESH_LOW_POWER if (cred->addr == bt_mesh.lpn.frnd) { lpn_addr = bt_mesh_primary_addr(); @@ -266,14 +287,13 @@ int friend_cred_set(struct friend_cred *cred, uint8_t idx, const uint8_t net_key lpn_addr = cred->addr; frnd_addr = bt_mesh_primary_addr(); } -#else +#else /* CONFIG_BLE_MESH_LOW_POWER */ lpn_addr = cred->addr; frnd_addr = bt_mesh_primary_addr(); -#endif +#endif /* CONFIG_BLE_MESH_LOW_POWER */ - BT_DBG("LPNAddress 0x%04x FriendAddress 0x%04x", lpn_addr, frnd_addr); - BT_DBG("LPNCounter 0x%04x FriendCounter 0x%04x", cred->lpn_counter, - cred->frnd_counter); + BT_DBG("LPN 0x%04x Frnd 0x%04x LPNCounter %u FrndCounter %u", + lpn_addr, frnd_addr, cred->lpn_counter, cred->frnd_counter); p[0] = 0x01; sys_put_be16(lpn_addr, p + 1); @@ -288,9 +308,9 @@ int friend_cred_set(struct friend_cred *cred, uint8_t idx, const uint8_t net_key return err; } - BT_DBG("Friend NID 0x%02x EncKey %s", cred->cred[idx].nid, - bt_hex(cred->cred[idx].enc, 16)); - BT_DBG("Friend PrivacyKey %s", bt_hex(cred->cred[idx].privacy, 16)); + BT_DBG("FrndNID 0x%02x EncKey %s", + cred->cred[idx].nid, bt_hex(cred->cred[idx].enc, 16)); + BT_DBG("FrndPrivacyKey %s", bt_hex(cred->cred[idx].privacy, 16)); return 0; } @@ -299,11 +319,14 @@ void friend_cred_refresh(uint16_t net_idx) { int i; + BT_DBG("FrndCredRefresh, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; if (cred->addr != BLE_MESH_ADDR_UNASSIGNED && cred->net_idx == net_idx) { + BT_DBG("Refreshed, Addr 0x%04x", cred->addr); memcpy(&cred->cred[0], &cred->cred[1], sizeof(cred->cred[0])); } @@ -314,7 +337,7 @@ int friend_cred_update(struct bt_mesh_subnet *sub) { int err = 0, i; - BT_DBG("net_idx 0x%04x", sub->net_idx); + BT_DBG("FrndCredUpdate, NetIdx 0x%04x", sub->net_idx); for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; @@ -324,6 +347,8 @@ int friend_cred_update(struct bt_mesh_subnet *sub) continue; } + BT_DBG("UpdateFound, Addr 0x%04x", cred->addr); + err = friend_cred_set(cred, 1, sub->keys[1].net); if (err) { return err; @@ -339,7 +364,8 @@ struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, uint16_t addr struct friend_cred *cred = NULL; int i, err = 0; - BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr); + BT_DBG("FrndCredCreate, NetIdx 0x%04x KrFlag %u Addr 0x%04x", + sub->net_idx, sub->kr_flag, addr); for (cred = NULL, i = 0; i < ARRAY_SIZE(friend_cred); i++) { if ((friend_cred[i].addr == BLE_MESH_ADDR_UNASSIGNED) || @@ -379,6 +405,8 @@ struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, uint16_t addr void friend_cred_clear(struct friend_cred *cred) { + BT_DBG("FrndCredClear, NetIdx 0x%04x Addr 0x%04x", cred->net_idx, cred->addr); + cred->net_idx = BLE_MESH_KEY_UNUSED; cred->addr = BLE_MESH_ADDR_UNASSIGNED; cred->lpn_counter = 0U; @@ -390,9 +418,13 @@ int friend_cred_del(uint16_t net_idx, uint16_t addr) { int i; + BT_DBG("FrndCredDel, NetIdx 0x%04x Addr 0x%04x", net_idx, addr); + for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; + BT_DBG("%u: NetIdx 0x%04x Addr 0x%04x", i, cred->net_idx, cred->addr); + if (cred->addr == addr && cred->net_idx == net_idx) { friend_cred_clear(cred); return 0; @@ -407,7 +439,8 @@ int friend_cred_get(struct bt_mesh_subnet *sub, uint16_t addr, uint8_t *nid, { int i; - BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr); + BT_DBG("FrndCredGet, NetIdx 0x%04x KrFlag %u Addr 0x%04x", + sub->net_idx, sub->kr_flag, addr); for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; @@ -437,13 +470,15 @@ int friend_cred_get(struct bt_mesh_subnet *sub, uint16_t addr, uint8_t *nid, return -ENOENT; } -#else +#else /* (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) */ int friend_cred_get(struct bt_mesh_subnet *sub, uint16_t addr, uint8_t *nid, const uint8_t **enc, const uint8_t **priv) { + BT_DBG("FrndCredGetNoEnt"); + return -ENOENT; } -#endif /* FRIEND || LOW_POWER */ +#endif /* (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) */ uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) { @@ -457,36 +492,40 @@ uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) flags |= BLE_MESH_NET_FLAG_IVU; } + BT_DBG("NetFlags 0x%02x", flags); + return flags; } int bt_mesh_net_secure_beacon_update(struct bt_mesh_subnet *sub) { - uint8_t flags = bt_mesh_net_flags(sub); struct bt_mesh_subnet_keys *keys = NULL; + uint8_t flags = 0; + + BT_DBG("SecureBeaconUpdate, NetIdx 0x%04x KrFlag %u IVIndex %lu", + sub->net_idx, sub->kr_flag, bt_mesh.iv_index); if (sub->kr_flag) { - BT_DBG("NetIndex %u Using new key", sub->net_idx); keys = &sub->keys[1]; } else { - BT_DBG("NetIndex %u Using current key", sub->net_idx); keys = &sub->keys[0]; } - BT_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index); + flags = bt_mesh_net_flags(sub); return bt_mesh_secure_beacon_auth(keys->beacon, flags, keys->net_id, bt_mesh.iv_index, sub->auth); } -int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], +int bt_mesh_net_create(uint16_t net_idx, uint8_t flags, const uint8_t key[16], uint32_t iv_index) { struct bt_mesh_subnet *sub = NULL; int err = 0; - BT_DBG("idx %u flags 0x%02x iv_index %u", idx, flags, iv_index); - + BT_DBG("NetCreate"); + BT_DBG("NetIdx 0x%04x Flags 0x%02x IVIndex %lu Hours %u", + net_idx, flags, iv_index, BLE_MESH_IVU_HOURS); BT_DBG("NetKey %s", bt_hex(key, 16)); (void)memset(msg_cache, 0, sizeof(msg_cache)); @@ -509,7 +548,7 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], } } - sub->net_idx = idx; + sub->net_idx = net_idx; if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER)) { sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; @@ -517,7 +556,7 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], sub->node_id = BLE_MESH_NODE_IDENTITY_NOT_SUPPORTED; #if CONFIG_BLE_MESH_PRB_SRV sub->private_node_id = BLE_MESH_PRIVATE_NODE_IDENTITY_NOT_SUPPORTED; -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } bt_mesh.iv_index = iv_index; @@ -535,27 +574,29 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], #if CONFIG_BLE_MESH_DF_SRV return bt_mesh_directed_forwarding_sub_init(sub); -#endif - +#else /* CONFIG_BLE_MESH_DF_SRV */ return 0; +#endif /* CONFIG_BLE_MESH_DF_SRV */ } void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub) { int i; - BT_DBG("idx 0x%04x", sub->net_idx); + BT_DBG("RevokeKeys, NetIdx 0x%04x", sub->net_idx); memcpy(&sub->keys[0], &sub->keys[1], sizeof(sub->keys[0])); if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Store updated NetKey persistently"); bt_mesh_store_subnet(sub); } for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { struct bt_mesh_app_key *key = &bt_mesh.app_keys[i]; + BT_DBG("Revoke, NetIdx 0x%04x AppIdx 0x%04x KeyUpdated %u", + key->net_idx, key->app_idx, key->updated); + if (key->net_idx != sub->net_idx || !key->updated) { continue; } @@ -564,7 +605,6 @@ void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub) key->updated = false; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Store updated AppKey persistently"); bt_mesh_store_app_key(key); } } @@ -572,6 +612,9 @@ void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub) bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) { + BT_DBG("KrUpdate, NewKr %u NewKey %u KrFlag %u KrPhase %u", + new_kr, new_key, sub->kr_flag, sub->kr_phase); + if (new_kr != sub->kr_flag && sub->kr_phase == BLE_MESH_KR_NORMAL) { BT_WARN("KR change in normal operation. Are we blacklisted?"); return false; @@ -582,10 +625,10 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) if (sub->kr_flag) { if (sub->kr_phase == BLE_MESH_KR_PHASE_1) { BT_INFO("Phase 1 -> Phase 2"); + sub->kr_phase = BLE_MESH_KR_PHASE_2; if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { - BT_DBG("Storing kr phase persistently"); bt_mesh_store_subnet(sub); } @@ -606,14 +649,14 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) * Intentional fall-through. */ case BLE_MESH_KR_PHASE_2: - BT_INFO("KR Phase 0x%02x -> Normal", sub->kr_phase); + BT_INFO("KrPhase 0x%02x -> Normal", sub->kr_phase); #if CONFIG_BLE_MESH_PRB_SRV /* In this case, consider that kr_flag has changed, so * need to modify the content of the random field. */ bt_mesh_private_beacon_update_random(sub); -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ sub->kr_phase = BLE_MESH_KR_NORMAL; bt_mesh_net_revoke_keys(sub); @@ -633,15 +676,21 @@ bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, uint8_t new_kr, bool new_key) #if CONFIG_BLE_MESH_IV_UPDATE_TEST void bt_mesh_iv_update_test(bool enable) { + BT_DBG("IVUpdateTest, Enable %u", enable); + bt_mesh_atomic_set_bit_to(bt_mesh.flags, BLE_MESH_IVU_TEST, enable); + /* Reset the duration variable - needed for some PTS tests */ bt_mesh.ivu_duration = 0U; } bool bt_mesh_iv_update(void) { + BT_DBG("IVUpdate, IVIndex %lu InProgress %u", bt_mesh.iv_index, + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)); + if (!bt_mesh_is_provisioned()) { - BT_ERR("Not yet provisioned"); + BT_ERR("NotProvisioned"); return false; } @@ -660,6 +709,8 @@ bool bt_mesh_iv_update(void) /* Used for sending immediate beacons to Friend queues and GATT clients */ void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub) { + BT_DBG("NetSecUpdate, NetIdx 0x%04x", sub ? sub->net_idx : BLE_MESH_KEY_ANY); + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { bt_mesh_friend_sec_update(sub ? sub->net_idx : BLE_MESH_KEY_ANY); } @@ -667,8 +718,8 @@ void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub) if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED #if CONFIG_BLE_MESH_PRB_SRV - || bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED -#endif + || bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED +#endif /* CONFIG_BLE_MESH_PRB_SRV */ )) { bt_mesh_proxy_server_beacon_send(sub); } @@ -678,6 +729,11 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) { int i; + BT_DBG("NetIVUpdate"); + BT_DBG("IVIndex %lu/%lu IVU %u InProgress %u", + iv_index, bt_mesh.iv_index, iv_update, + bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)); + /* If a node in Normal Operation receives a Secure Network beacon or * a Mesh Private beacon with an IV index less than the last known * IV Index or greater than the last known IV Index + 42, the Secure @@ -685,7 +741,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) */ if (iv_index < bt_mesh.iv_index || iv_index > bt_mesh.iv_index + 42) { - BT_ERR("IV Index out of sync: 0x%08x != 0x%08x", + BT_ERR("IVIndex out of sync: 0x%08x != 0x%08x", iv_index, bt_mesh.iv_index); return false; } @@ -721,7 +777,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) if ((iv_index > bt_mesh.iv_index + 1) #if CONFIG_BLE_MESH_IVU_RECOVERY_IVI || (iv_index == bt_mesh.iv_index + 1 && !iv_update) -#endif +#endif /* CONFIG_BLE_MESH_IVU_RECOVERY_IVI */ ) { BT_WARN("Performing IV Index Recovery"); (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); @@ -742,7 +798,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) BT_WARN("Ignoring new index in normal mode"); return false; } -#endif +#endif /* !CONFIG_BLE_MESH_IVU_RECOVERY_IVI */ if (!iv_update) { /* Nothing to do */ @@ -802,9 +858,11 @@ do_update: bool bt_mesh_primary_subnet_exist(void) { if (bt_mesh_subnet_get(BLE_MESH_KEY_PRIMARY)) { + BT_DBG("PrimarySubnetExist"); return true; } + BT_DBG("PrimarySubnetNotExist"); return false; } @@ -812,6 +870,8 @@ uint32_t bt_mesh_next_seq(void) { uint32_t seq = bt_mesh.seq++; + BT_DBG("NextSeq %lu", seq); + if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) { bt_mesh_store_seq(); } @@ -839,8 +899,9 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, /* The variable is not used when proxy server or proxy client is disabled. */ ARG_UNUSED(dst); - BT_DBG("net_idx 0x%04x new_key %u len %u", sub->net_idx, new_key, - buf->len); + BT_DBG("NetResend"); + BT_DBG("NetIdx 0x%04x NewKey %u Len %u Tag 0x%02x", + sub->net_idx, new_key, buf->len, tx_tag); /* Previously when resending the segments, only managed flooding * security credentials will be used. @@ -887,13 +948,11 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, err = bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_TX, priv); if (err) { - BT_ERR("De-obfuscate failed (err %d)", err); return err; } err = bt_mesh_net_decrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false, false); if (err) { - BT_ERR("Decrypt failed (err %d)", err); return err; } @@ -906,20 +965,18 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, err = bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_TX, false, false); if (err) { - BT_ERR("Encrypt failed (err %d)", err); return err; } err = bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_TX, priv); if (err) { - BT_ERR("Obfuscate failed (err %d)", err); return err; } - /** - * TODO: Find a way to determine how the message was sent previously + /* TODO: + * Find a way to determine how the message was sent previously * during a retransmission, to avoid ineffective advertising. - */ + */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (bt_mesh_proxy_server_relay(&buf->b, dst) && BLE_MESH_ADDR_IS_UNICAST(dst) && @@ -927,13 +984,14 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf, send_cb_finalize(cb, cb_data); return 0; } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT bt_mesh_proxy_client_relay(&buf->b, dst); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ bt_mesh_adv_send(buf, BLE_MESH_ADV(buf)->xmit, cb, cb_data); + return 0; } @@ -941,8 +999,10 @@ static void bt_mesh_net_local(void) { struct net_buf *buf = NULL; + BT_DBG("NetLocal"); + while ((buf = net_buf_slist_get(&bt_mesh.local_queue))) { - BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_net_recv(&buf->b, 0, BLE_MESH_NET_IF_LOCAL); net_buf_unref(buf); } @@ -956,6 +1016,10 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, uint8_t nid = 0U; int err = 0; + BT_DBG("NetEncode"); + BT_DBG("Src 0x%04x Dst 0x%04x Cred 0x%02x CTL %u Proxy %u", + tx->src, tx->ctx->addr, tx->ctx->send_cred, ctl, proxy); + if (ctl && net_buf_simple_tailroom(buf) < BLE_MESH_MIC_LONG) { BT_ERR("Insufficient MIC space for CTL PDU"); return -EINVAL; @@ -966,9 +1030,6 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, return -EINVAL; } - BT_DBG("src 0x%04x dst 0x%04x ctl %u seq 0x%06x", - tx->src, tx->ctx->addr, ctl, bt_mesh.seq); - net_buf_simple_push_be16(buf, tx->ctx->addr); net_buf_simple_push_be16(buf, tx->src); @@ -980,8 +1041,6 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf, net_buf_simple_push_u8(buf, tx->ctx->send_ttl); } - BT_INFO("Use security credentials 0x%02x, proxy %d", tx->ctx->send_cred, proxy); - if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && tx->ctx->send_cred == BLE_MESH_FRIENDSHIP_CRED) { err = friend_cred_get(tx->sub, BLE_MESH_ADDR_UNASSIGNED, @@ -1042,16 +1101,13 @@ static void bt_mesh_net_adv_xmit_update(struct bt_mesh_net_tx *tx) */ if (bt_mesh_tag_friendship(tx->ctx->send_tag)) { tx->xmit = BLE_MESH_TRANSMIT(0, BLE_MESH_TRANSMIT_INT(bt_mesh_net_transmit_get())); - return; - } - - if (bt_mesh_tag_relay(tx->ctx->send_tag)) { + } else if (bt_mesh_tag_relay(tx->ctx->send_tag)) { tx->xmit = bt_mesh_relay_retransmit_get(); } else { tx->xmit = bt_mesh_net_transmit_get(); } - return; + BT_INFO("NetAdvXmitUpdate, Tag 0x%02x Xmit 0x%02x", tx->ctx->send_tag, tx->xmit); } #endif /* !CONFIG_BLE_MESH_V11_SUPPORT */ @@ -1062,11 +1118,11 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, uint8_t bearer = BLE_MESH_ALL_BEARERS; int err = 0; - BT_DBG("src 0x%04x dst 0x%04x len %u headroom %u tailroom %u", - tx->src, tx->ctx->addr, buf->len, net_buf_headroom(buf), - net_buf_tailroom(buf)); - BT_DBG("Payload len %u: %s", buf->len, bt_hex(buf->data, buf->len)); - BT_DBG("Seq 0x%06x", bt_mesh.seq); + BT_DBG("NetSend"); + BT_DBG("Src 0x%04x Dst 0x%04x TTL %u Cred %u Tag 0x%02x Seq 0x%06x Room %u/%u", + tx->src, tx->ctx->addr, tx->ctx->send_ttl, tx->ctx->send_cred, + tx->ctx->send_tag, bt_mesh.seq, net_buf_headroom(buf), net_buf_tailroom(buf)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (tx->ctx->send_ttl == BLE_MESH_TTL_DEFAULT) { tx->ctx->send_ttl = bt_mesh_default_ttl_get(); @@ -1100,6 +1156,8 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, #if CONFIG_BLE_MESH_DF_SRV bt_mesh_update_net_send_cred(tx, &bearer); + + BT_DBG("TxBearer 0x%02x", bearer); #endif /* CONFIG_BLE_MESH_DF_SRV */ err = bt_mesh_net_encode(tx, &buf->b, false); @@ -1140,9 +1198,10 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, * a advertising method. */ if (bt_mesh_proxy_server_find_client_by_addr(tx->ctx->addr)) { + BT_DBG("ProxyClientFound"); + send_cb_finalize(send_cb, cb_data); send_cb = NULL; - goto done; } @@ -1154,6 +1213,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT /* This message will not be transmitted by proxy client */ if (!bt_mesh_proxy_client_get_conn_count()) { + BT_DBG("ProxyClientNoConn"); goto done; } #endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ @@ -1167,6 +1227,8 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, (tx->ctx->send_ttl != 1U || bt_mesh_tag_relay(tx->ctx->send_tag)) && tx->ctx->send_cred != BLE_MESH_FRIENDSHIP_CRED) { if (bt_mesh_proxy_client_relay(&buf->b, tx->ctx->addr)) { + BT_DBG("ProxyClientRelay"); + /* If Proxy Client succeeds to send messages with GATT bearer, * we can directly finish here. And if not, which means no * connection has been created with Proxy Client, here we will @@ -1175,7 +1237,6 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, if ((bearer & (~BLE_MESH_GATT_BEARER)) == 0) { send_cb_finalize(send_cb, cb_data); send_cb = NULL; - goto done; } } @@ -1203,11 +1264,11 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, } bt_mesh_net_local(); - goto done; } net_buf_slist_put(&bt_mesh.local_queue, net_buf_ref(buf)); + bt_mesh_net_local(); } @@ -1226,16 +1287,12 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf, */ bt_mesh_net_adv_xmit_update(tx); - BT_INFO("Network PDU, count %d, interval %d", - BLE_MESH_TRANSMIT_COUNT(tx->xmit), BLE_MESH_TRANSMIT_INT(tx->xmit)); bt_mesh_adv_send(buf, tx->xmit, cb, cb_data); - goto done; } - BT_WARN("Not sent, src 0x%04x, dst 0x%04x, ttl %d, cred 0x%02x, tag 0x%02x", - tx->src, tx->ctx->addr, tx->ctx->send_ttl, tx->ctx->send_cred, - tx->ctx->send_tag); + BT_WARN("NetNotSend"); + err = -EIO; done: @@ -1249,7 +1306,10 @@ static bool auth_match(struct bt_mesh_subnet_keys *keys, { uint8_t net_auth[8] = {0}; + BT_DBG("AuthMatch"); + if (memcmp(net_id, keys->net_id, 8)) { + BT_DBG("NetID %s != %s", bt_hex(net_id, 8), bt_hex(keys->net_id, 8)); return false; } @@ -1257,8 +1317,7 @@ static bool auth_match(struct bt_mesh_subnet_keys *keys, net_auth); if (memcmp(auth, net_auth, 8)) { - BT_WARN("Authentication Value %s != %s", - bt_hex(auth, 8), bt_hex(net_auth, 8)); + BT_WARN("NetAuth %s != %s", bt_hex(auth, 8), bt_hex(net_auth, 8)); return false; } @@ -1274,6 +1333,8 @@ struct bt_mesh_subnet *bt_mesh_subnet_find_with_snb(const uint8_t net_id[8], uin subnet_size = bt_mesh_rx_netkey_size(); + BT_DBG("SubnetFindWithSnb, Size %lu", subnet_size); + for (i = 0; i < subnet_size; i++) { struct bt_mesh_subnet *sub = bt_mesh_rx_netkey_get(i); @@ -1304,8 +1365,10 @@ int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, size_t data_len, struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) { - BT_DBG("NID 0x%02x net_idx 0x%04x", BLE_MESH_NET_HDR_NID(data), sub->net_idx); - BT_DBG("IVI %u net->iv_index 0x%08x", BLE_MESH_NET_HDR_IVI(data), bt_mesh.iv_index); + BT_DBG("NetDecrypt"); + BT_DBG("IVI %u NID 0x%02x NetIdx 0x%04x IVIndex %lu NetIf %u", + BLE_MESH_NET_HDR_IVI(data), BLE_MESH_NET_HDR_NID(data), + sub->net_idx, bt_mesh.iv_index, rx->net_if); rx->old_iv = (BLE_MESH_NET_HDR_IVI(data) != (bt_mesh.iv_index & 0x01)); @@ -1327,12 +1390,11 @@ int net_decrypt(struct bt_mesh_subnet *sub, const uint8_t *enc, return -EALREADY; } - BT_DBG("src 0x%04x", rx->ctx.addr); + BT_DBG("Src 0x%04x", rx->ctx.addr); if (IS_ENABLED(CONFIG_BLE_MESH_PROXY) && rx->net_if == BLE_MESH_NET_IF_PROXY_CFG) { - return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), - true, false); + return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), true, false); } return bt_mesh_net_decrypt(enc, buf, BLE_MESH_NET_IVI_RX(rx), false, false); @@ -1345,7 +1407,9 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, { int i; - BT_DBG("NID 0x%02x net_idx 0x%04x", BLE_MESH_NET_HDR_NID(data), sub->net_idx); + BT_DBG("FrndDecrypt"); + BT_DBG("NID 0x%02x NetIdx 0x%04x KrPhase %u", + BLE_MESH_NET_HDR_NID(data), sub->net_idx, sub->kr_phase); for (i = 0; i < ARRAY_SIZE(friend_cred); i++) { struct friend_cred *cred = &friend_cred[i]; @@ -1357,6 +1421,7 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, if (BLE_MESH_NET_HDR_NID(data) == cred->cred[0].nid && !net_decrypt(sub, cred->cred[0].enc, cred->cred[0].privacy, data, data_len, rx, buf)) { + BT_DBG("UseOldKey"); return 0; } @@ -1367,6 +1432,7 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, if (BLE_MESH_NET_HDR_NID(data) == cred->cred[1].nid && !net_decrypt(sub, cred->cred[1].enc, cred->cred[1].privacy, data, data_len, rx, buf)) { + BT_DBG("UseNewKey"); rx->new_key = 1U; return 0; } @@ -1380,11 +1446,14 @@ static int flooding_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, size_t data_len, struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) { - BT_DBG("NID 0x%02x net_idx 0x%04x", BLE_MESH_NET_HDR_NID(data), sub->net_idx); + BT_DBG("FloodingDecrypt"); + BT_DBG("NID 0x%02x NetIdx 0x%04x KrPhase %u", + BLE_MESH_NET_HDR_NID(data), sub->net_idx, sub->kr_phase); if (BLE_MESH_NET_HDR_NID(data) == sub->keys[0].nid && !net_decrypt(sub, sub->keys[0].enc, sub->keys[0].privacy, data, data_len, rx, buf)) { + BT_DBG("UseOldKey"); return 0; } @@ -1395,6 +1464,7 @@ static int flooding_decrypt(struct bt_mesh_subnet *sub, const uint8_t *data, if (BLE_MESH_NET_HDR_NID(data) == sub->keys[1].nid && !net_decrypt(sub, sub->keys[1].enc, sub->keys[1].privacy, data, data_len, rx, buf)) { + BT_DBG("UseNewKey"); rx->new_key = 1U; return 0; } @@ -1412,10 +1482,12 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, array_size = bt_mesh_rx_netkey_size(); + BT_DBG("NetFindAndDecrypt, Size %u", array_size); + for (i = 0; i < array_size; i++) { sub = bt_mesh_rx_netkey_get(i); if (!sub) { - BT_DBG("Subnet not found"); + BT_DBG("SubNotFound"); continue; } @@ -1425,7 +1497,7 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, #if CONFIG_BLE_MESH_BRC_SRV sub->sbr_net_idx = BLE_MESH_KEY_UNUSED; -#endif +#endif /* CONFIG_BLE_MESH_BRC_SRV */ #if (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) if (!friend_decrypt(sub, data, data_len, rx, buf)) { @@ -1434,7 +1506,7 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, rx->sub = sub; return true; } -#endif +#endif /* (CONFIG_BLE_MESH_LOW_POWER || CONFIG_BLE_MESH_FRIEND) */ #if CONFIG_BLE_MESH_DF_SRV if (!bt_mesh_directed_decrypt(sub, data, data_len, rx, buf)) { @@ -1463,6 +1535,8 @@ static bool net_find_and_decrypt(const uint8_t *data, size_t data_len, */ static bool relay_to_adv(enum bt_mesh_net_if net_if) { + BT_DBG("RelayToAdv, NetIf %u", net_if); + switch (net_if) { case BLE_MESH_NET_IF_LOCAL: return true; @@ -1472,7 +1546,7 @@ static bool relay_to_adv(enum bt_mesh_net_if net_if) return (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED #if CONFIG_BLE_MESH_PRB_SRV || bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ ); default: return false; @@ -1483,6 +1557,8 @@ static bool relay_to_adv(enum bt_mesh_net_if net_if) static uint8_t net_retransmission_adv(struct bt_mesh_net_rx *rx, uint8_t *cred, uint8_t *tag) { + BT_DBG("NetRetransmissionAdv"); + if (rx->ctx.recv_cred == BLE_MESH_FLOODING_CRED) { uint8_t bearer = BLE_MESH_NONE_BEARER; @@ -1506,6 +1582,8 @@ static uint8_t net_retransmission_adv(struct bt_mesh_net_rx *rx, *cred = BLE_MESH_FLOODING_CRED; } + BT_DBG("FloodingBearer 0x%02x", bearer); + return bearer; } @@ -1515,6 +1593,9 @@ static uint8_t net_retransmission_adv(struct bt_mesh_net_rx *rx, /* Condition: Directed friend is disabled. */ *cred = BLE_MESH_FLOODING_CRED; + + BT_DBG("FrndBearerAll"); + return BLE_MESH_ALL_BEARERS; } @@ -1524,6 +1605,8 @@ static uint8_t net_retransmission_adv(struct bt_mesh_net_rx *rx, static uint8_t net_retransmission_gatt(struct bt_mesh_net_rx *rx, uint8_t *cred, uint8_t *tag) { + BT_DBG("NetRetransmissionGatt"); + if (rx->ctx.recv_cred == BLE_MESH_FLOODING_CRED) { /* Inbound bearer: GATT; * Inbound Security Material: managed flooding; @@ -1533,6 +1616,9 @@ static uint8_t net_retransmission_gatt(struct bt_mesh_net_rx *rx, bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { /* Condition: Directed proxy is disabled. */ *cred = BLE_MESH_FLOODING_CRED; + + BT_DBG("FloodingBearerAll"); + return BLE_MESH_ALL_BEARERS; } @@ -1561,14 +1647,19 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, struct bt_mesh_net_rx *rx) { const uint8_t *enc = NULL, *priv = NULL; + bool netkey_changed = false; struct net_buf *buf = NULL; uint8_t bearer = 0; uint8_t xmit = 0U; uint8_t cred = 0; uint8_t nid = 0U; - bool netkey_changed = false; uint8_t tag = 0; + BT_DBG("NetRelay"); + BT_DBG("TTL %u CTL %u Dst 0x%04x RecvCred %u NetIf %u", + rx->ctx.recv_ttl, rx->ctl, rx->ctx.recv_dst, + rx->ctx.recv_cred, rx->net_if); + if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { /* Locally originated PDUs with TTL=1 will only be delivered * to local elements as per Mesh Profile 1.0 section 3.4.5.2: @@ -1624,12 +1715,12 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, BT_ERR("Bridge RPL attack"); goto done; } -#endif +#endif /* CONFIG_BLE_MESH_BRC_SRV */ if (cred != BLE_MESH_FLOODING_CRED #if CONFIG_BLE_MESH_DF_SRV - && cred != BLE_MESH_DIRECTED_CRED -#endif + && cred != BLE_MESH_DIRECTED_CRED +#endif /* CONFIG_BLE_MESH_DF_SRV */ ) { BT_WARN("No outbound security cred found, inbound cred %d", rx->ctx.recv_cred); return; @@ -1645,8 +1736,6 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, return; } - BT_DBG("TTL %u CTL %u dst 0x%04x", rx->ctx.recv_ttl, rx->ctl, rx->ctx.recv_dst); - /* The Relay Retransmit state is only applied to adv-adv relaying. * Anything else (like GATT to adv, or locally originated packets) * use the Network Transmit state. @@ -1698,7 +1787,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, /* Check if the number of relay packets in queue is too large, if so * use minimum relay retransmit value for later relay packets. */ - if (bt_mesh_get_stored_relay_count() >= BLE_MESH_MAX_STORED_RELAY_COUNT) { + if (bt_mesh_get_stored_relay_count() >= MAX_STORED_RELAY_COUNT) { xmit = BLE_MESH_TRANSMIT(0, 20); } #if CONFIG_BLE_MESH_EXT_ADV @@ -1754,10 +1843,12 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, /* Check if subnet bridge is supported & decide which NetKey is used */ if (bt_mesh_subnet_bridge_state_get() == BLE_MESH_SUBNET_BRIDGE_ENABLED) { netkey_changed = bt_mesh_bridge_change_net_key(rx, &enc, &priv, &nid, cred); - } -#endif - BT_DBG("Relaying packet. TTL is now %u", BLE_MESH_NET_HDR_TTL(buf->data)); + BT_DBG("NetKeyChanged %u", netkey_changed); + } +#endif /* CONFIG_BLE_MESH_BRC_SRV */ + + BT_DBG("Relaying, NewTTL %u", BLE_MESH_NET_HDR_TTL(buf->data)); /* 1. Update NID if RX or RX was with friend credentials(included by case 3). * 2. Update NID if the net_key has changed. @@ -1773,12 +1864,10 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, * layer nonce includes the IVI. */ if (bt_mesh_net_encrypt(enc, &buf->b, BLE_MESH_NET_IVI_RX(rx), false, false)) { - BT_ERR("Re-encrypting failed"); goto done; } if (bt_mesh_net_obfuscate(buf->data, BLE_MESH_NET_IVI_RX(rx), priv)) { - BT_ERR("Re-obfuscating failed"); goto done; } @@ -1795,14 +1884,15 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, cred != BLE_MESH_FRIENDSHIP_CRED) || #if CONFIG_BLE_MESH_PRB_SRV bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED || -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ rx->net_if == BLE_MESH_NET_IF_LOCAL || rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED)) { if (bt_mesh_proxy_server_relay(&buf->b, rx->ctx.recv_dst) && BLE_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) { - + /* Not relay if only GATT bearer is chosen or found Proxy Client */ if (((bearer & (~BLE_MESH_GATT_BEARER)) == 0) || bt_mesh_proxy_server_find_client_by_addr(rx->ctx.recv_dst)) { + BT_DBG("ProxyNotRelay"); goto done; } } @@ -1814,9 +1904,9 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf, rx->ctx.recv_cred == BLE_MESH_FRIENDSHIP_CRED) { #if !CONFIG_BLE_MESH_RELAY_ADV_BUF bt_mesh_adv_send(buf, xmit, NULL, NULL); -#else +#else /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ bt_mesh_relay_adv_send(buf, xmit, rx->ctx.addr, rx->ctx.recv_dst, NULL, NULL); -#endif +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF */ } done: @@ -1826,6 +1916,8 @@ done: void bt_mesh_net_header_parse(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) { + BT_DBG("NetHeaderParse"); + rx->old_iv = (BLE_MESH_NET_HDR_IVI(buf->data) != (bt_mesh.iv_index & 0x01)); rx->ctl = BLE_MESH_NET_HDR_CTL(buf->data); rx->ctx.recv_ttl = BLE_MESH_NET_HDR_TTL(buf->data); @@ -1837,9 +1929,10 @@ void bt_mesh_net_header_parse(struct net_buf_simple *buf, int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) { + BT_DBG("NetDecode, NetIf %u", net_if); + if (data->len < BLE_MESH_NET_MIN_PDU_LEN) { BT_WARN("Dropping too short mesh packet (len %u)", data->len); - BT_WARN("%s", bt_hex(data->data, data->len)); return -EINVAL; } @@ -1847,7 +1940,7 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, return -EINVAL; } - BT_DBG("%u bytes: %s", data->len, bt_hex(data->data, data->len)); + BT_DBG("Len %u: %s", data->len, bt_hex(data->data, data->len)); rx->net_if = net_if; @@ -1883,8 +1976,6 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, rx->seq = BLE_MESH_NET_HDR_SEQ(buf->data); rx->ctx.recv_dst = BLE_MESH_NET_HDR_DST(buf->data); - BT_DBG("Decryption successful. Payload len %u", buf->len); - if (net_if != BLE_MESH_NET_IF_PROXY_CFG && rx->ctx.recv_dst == BLE_MESH_ADDR_UNASSIGNED) { BT_ERR("Destination address is unassigned; dropping packet"); @@ -1897,16 +1988,15 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, BT_ERR("Destination address is RFU; dropping packet 0x%02x", rx->ctx.recv_dst); return -EBADMSG; } -#endif +#endif /* !CONFIG_BLE_MESH_BQB_TEST */ if (net_if != BLE_MESH_NET_IF_LOCAL && bt_mesh_elem_find(rx->ctx.addr)) { BT_DBG("Dropping locally originated packet"); return -EBADMSG; } - BT_DBG("src 0x%04x dst 0x%04x ttl %u", rx->ctx.addr, rx->ctx.recv_dst, - rx->ctx.recv_ttl); - BT_DBG("PDU: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Src 0x%04x Dst 0x%04x TTL %u", rx->ctx.addr, rx->ctx.recv_dst, rx->ctx.recv_ttl); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); msg_cache_add(rx); @@ -1916,25 +2006,31 @@ int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if, static bool ready_to_recv(void) { if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { + BT_DBG("NodeReadyToRecv"); return true; } if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { if (bt_mesh_provisioner_get_node_count()) { + BT_DBG("PvnrReadyToRecv"); return true; } } + BT_DBG("NotReadyToRecv"); return false; } static bool ignore_net_msg(uint16_t src, uint16_t dst) { + BT_DBG("IgnoreNetMsg, Src 0x%04x Dst 0x%04x", src, dst); + if (IS_ENABLED(CONFIG_BLE_MESH_FAST_PROV)) { /* When fast provisioning is enabled, the node addr * message will be sent to the Primary Provisioner, * which shall not be ignored here. */ + BT_DBG("FastProvNotIgnoreNetMsg"); return false; } @@ -1949,11 +2045,12 @@ static bool ignore_net_msg(uint16_t src, uint16_t dst) */ if (!bt_mesh_provisioner_get_node_with_addr(src) && !bt_mesh_elem_find(src)) { - BT_INFO("Not found node address 0x%04x", src); + BT_INFO("PvnrIgnoreNetMsg"); return true; } } + BT_DBG("NotIgnoreNetMsg"); return false; } @@ -1982,10 +2079,15 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, BT_DBG("rssi %d net_if %u", rx->ctx.recv_rssi, net_if); if (bt_mesh_net_decode(data, net_if, rx, buf)) { + BT_DBG("DecodeFailed"); goto free_net_msg_buf; } + BT_DBG("NetRecv, Src 0x%04x Dst 0x%04x Rssi %d NetIf %u", + rx->ctx.addr, rx->ctx.recv_dst, rx->ctx.recv_rssi, net_if); + if (ignore_net_msg(rx->ctx.addr, rx->ctx.recv_dst)) { + BT_DBG("IgnoreNetMsg"); goto free_net_msg_buf; } @@ -2003,8 +2105,8 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, * corresponding subnet. */ rx->local_match = (bt_mesh_fixed_group_match(rx->ctx.recv_dst) || - bt_mesh_fixed_direct_match(rx->sub, rx->ctx.recv_dst) || - bt_mesh_elem_find(rx->ctx.recv_dst)); + bt_mesh_fixed_direct_match(rx->sub, rx->ctx.recv_dst) || + bt_mesh_elem_find(rx->ctx.recv_dst)); #if CONFIG_BLE_MESH_LONG_PACKET /* It should be noted that if the length of buf @@ -2018,8 +2120,10 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && #if CONFIG_BLE_MESH_PRB_SRV bt_mesh_private_gatt_proxy_state_get() != BLE_MESH_PRIVATE_GATT_PROXY_ENABLED && -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ net_if == BLE_MESH_NET_IF_PROXY) { + BT_DBG("ProxyServerAddrAdd"); + bt_mesh_proxy_server_addr_add(data, rx->ctx.addr); if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_DISABLED && @@ -2040,6 +2144,7 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, rx->sub->use_directed == BLE_MESH_PROXY_USE_DIRECTED_ENABLED && !bt_mesh_addr_in_uar(&rx->sub->proxy_client_uar, rx->ctx.addr) && !bt_mesh_proxy_server_find_client_by_addr(rx->ctx.addr)) { + BT_DBG("ImmutableCredTag"); rx->ctx.recv_tag |= BLE_MESH_TAG_IMMUTABLE_CRED; } #endif /* CONFIG_BLE_MESH_DF_SRV */ @@ -2080,7 +2185,7 @@ static void ivu_refresh(struct k_work *work) { bt_mesh.ivu_duration += BLE_MESH_IVU_HOURS; - BT_INFO("%s for %u hour%s", + BT_INFO("IVURefresh, %s for %u hour%s", bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS) ? "IVU in Progress" : "IVU Normal mode", bt_mesh.ivu_duration, bt_mesh.ivu_duration == 1U ? "" : "s"); @@ -2104,6 +2209,8 @@ static void ivu_refresh(struct k_work *work) void bt_mesh_net_start(void) { + BT_DBG("NetStart"); + if (bt_mesh_secure_beacon_get() == BLE_MESH_SECURE_BEACON_ENABLED) { bt_mesh_secure_beacon_enable(); } else { @@ -2116,7 +2223,7 @@ void bt_mesh_net_start(void) } else { bt_mesh_private_beacon_disable(); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && bt_mesh_gatt_proxy_get() != BLE_MESH_GATT_PROXY_NOT_SUPPORTED) { @@ -2129,7 +2236,7 @@ void bt_mesh_net_start(void) bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, BLE_MESH_EXCEP_LIST_TYPE_MESH_BEACON, NULL); -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER)) { /* TODO: Enable duplicate scan in Low Power Mode */ @@ -2148,6 +2255,7 @@ void bt_mesh_net_start(void) uint32_t iv_index = bt_mesh.iv_index; uint8_t flags = (uint8_t)bt_mesh.sub[0].kr_flag; const uint8_t *net_key = bt_mesh.sub[0].keys[flags].net; + if (bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS)) { flags |= BLE_MESH_NET_FLAG_IVU; } @@ -2158,16 +2266,20 @@ void bt_mesh_net_start(void) void bt_mesh_net_init(void) { + BT_DBG("NetInit"); + k_delayed_work_init(&bt_mesh.ivu_timer, ivu_refresh); } void bt_mesh_net_reset(void) { + BT_DBG("NetReset"); + k_delayed_work_cancel(&bt_mesh.ivu_timer); #if FRIEND_CRED_COUNT > 0 memset(friend_cred, 0, sizeof(friend_cred)); -#endif +#endif /* FRIEND_CRED_COUNT > 0 */ memset(msg_cache, 0, sizeof(msg_cache)); msg_cache_next = 0U; @@ -2182,6 +2294,8 @@ void bt_mesh_net_reset(void) #if CONFIG_BLE_MESH_DEINIT void bt_mesh_net_deinit(void) { + BT_DBG("NetDeinit"); + bt_mesh_net_reset(); k_delayed_work_free(&bt_mesh.ivu_timer); diff --git a/components/bt/esp_ble_mesh/core/net.h b/components/bt/esp_ble_mesh/core/net.h index e946daef0f..1141bd2bd9 100644 --- a/components/bt/esp_ble_mesh/core/net.h +++ b/components/bt/esp_ble_mesh/core/net.h @@ -66,7 +66,7 @@ struct bt_mesh_subnet { #if CONFIG_BLE_MESH_BRC_SRV uint16_t sbr_net_idx; /* NetKeyIndex of bridged subnet */ -#endif +#endif /* CONFIG_BLE_MESH_BRC_SRV */ bool kr_flag; /* Key Refresh Flag */ uint8_t kr_phase; /* Key Refresh Phase */ @@ -163,17 +163,17 @@ struct bt_mesh_rpl { bool old_iv; #if CONFIG_BLE_MESH_SETTINGS bool store; -#endif +#endif /* CONFIG_BLE_MESH_SETTINGS */ uint32_t seq; }; #if CONFIG_BLE_MESH_FRIEND #define FRIEND_SEG_RX CONFIG_BLE_MESH_FRIEND_SEG_RX #define FRIEND_SUB_LIST_SIZE CONFIG_BLE_MESH_FRIEND_SUB_LIST_SIZE -#else +#else /* CONFIG_BLE_MESH_FRIEND */ #define FRIEND_SEG_RX 0 #define FRIEND_SUB_LIST_SIZE 0 -#endif +#endif /* CONFIG_BLE_MESH_FRIEND */ struct bt_mesh_friend { uint16_t lpn; @@ -220,10 +220,10 @@ struct bt_mesh_friend { }; #if CONFIG_BLE_MESH_LOW_POWER -#define LPN_GROUPS CONFIG_BLE_MESH_LPN_GROUPS -#else -#define LPN_GROUPS 0 -#endif +#define LPN_GROUPS CONFIG_BLE_MESH_LPN_GROUPS +#else /* CONFIG_BLE_MESH_LOW_POWER */ +#define LPN_GROUPS 0 +#endif /* CONFIG_BLE_MESH_LOW_POWER */ /* Low Power Node state */ struct bt_mesh_lpn { @@ -275,7 +275,7 @@ struct bt_mesh_lpn { #if CONFIG_BLE_MESH_DF_SRV uint8_t old_directed_forwarding; -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ /* Duration reported for last advertising packet */ uint16_t adv_duration; @@ -331,11 +331,11 @@ struct bt_mesh_net { #if CONFIG_BLE_MESH_FRIEND /* Friend state, unique for each LPN that we're Friends for */ struct bt_mesh_friend frnd[CONFIG_BLE_MESH_FRIEND_LPN_COUNT]; -#endif +#endif /* CONFIG_BLE_MESH_FRIEND */ #if CONFIG_BLE_MESH_LOW_POWER struct bt_mesh_lpn lpn; /* Low Power Node state */ -#endif +#endif /* CONFIG_BLE_MESH_LOW_POWER */ /* Number of hours in current IV Update state */ uint8_t ivu_duration; @@ -362,7 +362,7 @@ struct bt_mesh_net { struct bt_mesh_subnet *p_sub[CONFIG_BLE_MESH_PROVISIONER_SUBNET_COUNT]; /* Next net_idx can be assigned */ uint16_t p_net_idx_next; -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ }; /* Network interface */ @@ -393,7 +393,7 @@ struct bt_mesh_net_rx { friend_match:1, /* Matched an LPN we're friends for */ #if CONFIG_BLE_MESH_NOT_RELAY_REPLAY_MSG replay_msg:1, /* Replayed messages */ -#endif +#endif /* CONFIG_BLE_MESH_NOT_RELAY_REPLAY_MSG */ sbr_rpl:1; /* Bridge RPL attacker */ uint16_t msg_cache_idx; /* Index of entry in message cache */ }; @@ -431,7 +431,7 @@ void bt_mesh_msg_cache_clear(uint16_t unicast_addr, uint8_t elem_num); int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys, const uint8_t key[16]); -int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], +int bt_mesh_net_create(uint16_t net_idx, uint8_t flags, const uint8_t key[16], uint32_t iv_index); uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub); diff --git a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c index d89c63b349..4d598a333e 100644 --- a/components/bt/esp_ble_mesh/core/nimble_host/adapter.c +++ b/components/bt/esp_ble_mesh/core/nimble_host/adapter.c @@ -993,8 +993,8 @@ static int gap_event_cb(struct ble_gap_event *event, void *arg) return 0; case BLE_GAP_EVENT_ADV_COMPLETE: - BT_DBG("advertise complete; reason=%d", - event->adv_complete.reason); + BT_DBG("advertise complete; reason=%d", event->adv_complete.reason); + #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV bt_mesh_adv_task_wakeup(ADV_TASK_ADV_INST_EVT(event->adv_complete.instance)); diff --git a/components/bt/esp_ble_mesh/core/prov_common.c b/components/bt/esp_ble_mesh/core/prov_common.c index 6f9e1dfa41..a29ba8fb4f 100644 --- a/components/bt/esp_ble_mesh/core/prov_common.c +++ b/components/bt/esp_ble_mesh/core/prov_common.c @@ -419,6 +419,9 @@ static void prov_retransmit(struct k_work *work) } #if CONFIG_BLE_MESH_FAST_PROV + BT_DBG("FastProv, TxPDUType %u LastTxPDU %u", + link->tx_pdu_type, link->last_tx_pdu); + if (link->tx_pdu_type >= link->last_tx_pdu) { timeout = K_SECONDS(30); } @@ -651,6 +654,9 @@ int bt_mesh_prov_send_adv(struct bt_mesh_prov_link *link, struct net_buf_simple send_reliable(link, PROV_XMIT); #if CONFIG_BLE_MESH_FAST_PROV + BT_DBG("FastProv, TxPDUType %u LastTxPDU %u", + link->tx_pdu_type, link->last_tx_pdu); + if (link->tx_pdu_type >= link->last_tx_pdu) { timeout = K_SECONDS(60); } diff --git a/components/bt/esp_ble_mesh/core/proxy_client.c b/components/bt/esp_ble_mesh/core/proxy_client.c index ac05f92ffe..710159fd25 100644 --- a/components/bt/esp_ble_mesh/core/proxy_client.c +++ b/components/bt/esp_ble_mesh/core/proxy_client.c @@ -23,11 +23,11 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ - (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) static struct bt_mesh_proxy_server { struct bt_mesh_conn *conn; @@ -40,7 +40,8 @@ static struct bt_mesh_proxy_server { #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT uint16_t net_idx; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + uint8_t msg_type; struct k_delayed_work sar_timer; @@ -53,7 +54,7 @@ static struct { struct bt_mesh_prov_link *link; bt_mesh_addr_t addr; } waiting_conn_link[BLE_MESH_MAX_CONN]; -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT */ static uint8_t server_buf_data[BLE_MESH_PROXY_BUF_SIZE * BLE_MESH_MAX_CONN]; @@ -61,6 +62,8 @@ static struct bt_mesh_proxy_server *find_server(struct bt_mesh_conn *conn) { int i; + BT_DBG("FindServer, ConnHandle 0x%04x", conn->handle); + for (i = 0; i < ARRAY_SIZE(servers); i++) { if (servers[i].conn == conn) { return &servers[i]; @@ -74,15 +77,16 @@ static void proxy_sar_timeout(struct k_work *work) { struct bt_mesh_proxy_server *server = NULL; - BT_WARN("%s", __func__); + BT_WARN("ProxySARTimeout"); server = CONTAINER_OF(work, struct bt_mesh_proxy_server, sar_timer.work); if (!server || !server->conn) { - BT_ERR("Invalid proxy server parameter"); + BT_ERR("InvalidProxyServerParam"); return; } net_buf_simple_reset(&server->buf); + bt_mesh_gattc_disconnect(server->conn); } @@ -90,6 +94,8 @@ static void proxy_sar_timeout(struct k_work *work) int bt_mesh_rpr_srv_set_waiting_prov_link(struct bt_mesh_prov_link *link, bt_mesh_addr_t *addr) { + BT_DBG("RPRSrvSetWaitingProvLink"); + for (size_t i = 0; i < ARRAY_SIZE(waiting_conn_link);i++) { if (waiting_conn_link[i].link == NULL) { waiting_conn_link[i].link = link; @@ -103,8 +109,7 @@ int bt_mesh_rpr_srv_set_waiting_prov_link(struct bt_mesh_prov_link *link, #endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT */ #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT -/** - * The following callbacks are used to notify proper information +/* The following callbacks are used to notify proper information * to the application layer. */ static proxy_client_recv_adv_cb_t proxy_client_adv_recv_cb; @@ -139,6 +144,8 @@ static void filter_status(struct bt_mesh_proxy_server *server, uint8_t filter_type = 0U; uint16_t list_size = 0U; + BT_DBG("FilterStatus"); + if (buf->len != 3) { BT_ERR("Invalid Proxy Filter Status length %d", buf->len); return; @@ -152,10 +159,11 @@ static void filter_status(struct bt_mesh_proxy_server *server, list_size = net_buf_simple_pull_be16(buf); - BT_INFO("filter_type 0x%02x, list_size %d", filter_type, list_size); + BT_INFO("FilterType %u ListSize %u", filter_type, list_size); if (proxy_client_filter_status_recv_cb) { - proxy_client_filter_status_recv_cb(server - servers, rx->ctx.addr, server->net_idx, filter_type, list_size); + proxy_client_filter_status_recv_cb(server - servers, rx->ctx.addr, + server->net_idx, filter_type, list_size); } } @@ -167,7 +175,7 @@ static void recv_directed_proxy_caps_status(struct bt_mesh_proxy_server *server, uint8_t directed_proxy = net_buf_simple_pull_u8(buf); uint8_t use_directed = net_buf_simple_pull_u8(buf); - BT_INFO("Directed Proxy 0x%02x, Use Directed 0x%02x", directed_proxy, use_directed); + BT_INFO("DirectedProxy %u UseDirected %u", directed_proxy, use_directed); ARG_UNUSED(directed_proxy); ARG_UNUSED(use_directed); @@ -181,13 +189,14 @@ static void proxy_cfg(struct bt_mesh_proxy_server *server) uint8_t opcode = 0U; int err = 0; + BT_DBG("ProxyCfg"); + if (server->buf.len > 29) { BT_ERR("Too large proxy cfg pdu (len %d)", server->buf.len); return; } - err = bt_mesh_net_decode(&server->buf, BLE_MESH_NET_IF_PROXY_CFG, - &rx, &buf); + err = bt_mesh_net_decode(&server->buf, BLE_MESH_NET_IF_PROXY_CFG, &rx, &buf); if (err) { BT_ERR("Failed to decode Proxy Configuration (err %d)", err); return; @@ -201,7 +210,7 @@ static void proxy_cfg(struct bt_mesh_proxy_server *server) rx.local_match = 1U; if (bt_mesh_rpl_check(&rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", rx.ctx.addr, rx.ctx.recv_dst, rx.seq); return; } @@ -209,7 +218,7 @@ static void proxy_cfg(struct bt_mesh_proxy_server *server) /* Remove network headers */ net_buf_simple_pull(&buf, BLE_MESH_NET_HDR_LEN); - BT_DBG("%u bytes: %s", buf.len, bt_hex(buf.data, buf.len)); + BT_DBG("Len %u: %s", buf.len, bt_hex(buf.data, buf.len)); if (buf.len < 3) { BT_WARN("Too short proxy configuration PDU"); @@ -243,6 +252,8 @@ static void proxy_cfg(struct bt_mesh_proxy_server *server) static void proxy_complete_pdu(struct bt_mesh_proxy_server *server) { + BT_DBG("ProxyCompletePDU"); + switch (server->msg_type) { #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT case BLE_MESH_PROXY_NET_PDU: @@ -265,14 +276,14 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_server *server) if (server->conn == bt_mesh_prov_node_get_link()->conn) { bt_mesh_pb_gatt_recv(server->conn, &server->buf); } else -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ { #if CONFIG_BLE_MESH_PROVISIONER bt_mesh_provisioner_pb_gatt_recv(server->conn, &server->buf); -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ } break; -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT && (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ default: BT_WARN("Unhandled Message Type 0x%02x", server->msg_type); break; @@ -291,6 +302,8 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, const uint8_t *data = buf; uint16_t srvc_uuid = 0U; + BT_DBG("ProxyRecv, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -377,7 +390,8 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, static int proxy_send(struct bt_mesh_conn *conn, const void *data, uint16_t len) { - BT_DBG("%u bytes: %s", len, bt_hex(data, len)); + BT_DBG("ProxySend"); + BT_DBG("Len %u: %s", len, bt_hex(data, len)); return bt_mesh_gattc_write_no_rsp(conn, NULL, data, len); } @@ -388,13 +402,15 @@ int bt_mesh_proxy_client_segment_send(struct bt_mesh_conn *conn, uint8_t type, uint16_t mtu = 0U; int err = 0; + BT_DBG("ProxyClientSegSend"); + if (conn == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } - BT_DBG("conn %p type 0x%02x len %u: %s", conn, type, msg->len, - bt_hex(msg->data, msg->len)); + BT_DBG("ConnHandle 0x%04x Type %u", conn->handle, type); + BT_DBG("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); mtu = bt_mesh_gattc_get_mtu_info(conn); if (!mtu) { @@ -402,6 +418,8 @@ int bt_mesh_proxy_client_segment_send(struct bt_mesh_conn *conn, uint8_t type, return -ENOTCONN; } + BT_DBG("MTU %u", mtu); + /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ mtu -= 3; if (mtu > msg->len) { @@ -433,6 +451,8 @@ int bt_mesh_proxy_client_send(struct bt_mesh_conn *conn, uint8_t type, { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProxyClientSend, ConnHandle 0x%04x Type %u", conn->handle, type); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -450,6 +470,8 @@ static void proxy_connected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, int { struct bt_mesh_proxy_server *server = NULL; + BT_DBG("ProxyConnected, ConnHandle 0x%04x ID %d", conn->handle, id); + if (!servers[id].conn) { server = &servers[id]; } @@ -475,7 +497,7 @@ static void proxy_connected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, int break; } } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT */ bt_mesh_gattc_exchange_mtu(id); } @@ -484,7 +506,7 @@ static void proxy_disconnected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, { struct bt_mesh_proxy_server *server = find_server(conn); - BT_DBG("conn %p, handle is %d, reason 0x%02x", conn, conn->handle, reason); + BT_DBG("ProxyDisconnected, ConnHandle 0x%04x Reason 0x%02x", conn->handle, reason); if (!server) { BT_ERR("No Proxy Server object found"); @@ -521,14 +543,15 @@ static void proxy_disconnected(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn, proxy_client_disconnect_cb(addr, server - servers, server->net_idx, reason); } } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ k_delayed_work_cancel(&server->sar_timer); + server->conn = NULL; server->conn_type = CLI_NONE; #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT server->net_idx = BLE_MESH_KEY_UNUSED; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ } #if CONFIG_BLE_MESH_PB_GATT && \ @@ -537,6 +560,8 @@ static ssize_t prov_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProvWriteCCC, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -555,11 +580,11 @@ static ssize_t prov_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) return bt_mesh_rpr_srv_recv_link_ack(addr->val, false); } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ #if CONFIG_BLE_MESH_PROVISIONER return bt_mesh_provisioner_pb_gatt_open(conn, addr->val); -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ } return -ENOMEM; @@ -569,6 +594,8 @@ static ssize_t prov_recv_ntf(struct bt_mesh_conn *conn, uint8_t *data, uint16_t { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProvRecvNtf, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -585,6 +612,8 @@ int bt_mesh_proxy_client_prov_enable(void) { int i; + BT_DBG("ProxyClientProvEnable"); + for (i = 0; i < ARRAY_SIZE(servers); i++) { if (servers[i].conn) { servers[i].conn_type = CLI_PROV; @@ -598,6 +627,8 @@ int bt_mesh_proxy_client_prov_disable(void) { int i; + BT_DBG("ProxyClientProvDisable"); + for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; @@ -616,6 +647,8 @@ static ssize_t proxy_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProxyWriteCCC, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; @@ -631,11 +664,12 @@ static ssize_t proxy_write_ccc(bt_mesh_addr_t *addr, struct bt_mesh_conn *conn) } #if CONFIG_BLE_MESH_BQB_TEST - /* notify maybe received first */ + /* Notification maybe received firstly */ if (server->conn_type == CLI_PROXY) { return 0; } -#endif +#endif /* CONFIG_BLE_MESH_BQB_TEST */ + return -EINVAL; } @@ -643,20 +677,23 @@ static ssize_t proxy_recv_ntf(struct bt_mesh_conn *conn, uint8_t *data, uint16_t { struct bt_mesh_proxy_server *server = find_server(conn); + BT_DBG("ProxyRecvNtf, ConnHandle 0x%04x", conn->handle); + if (!server) { BT_ERR("No Proxy Server object found"); return -ENOTCONN; } #if CONFIG_BLE_MESH_BQB_TEST - /* update conn type if notify received before write ccc */ + /* Update conn type if notification received before writing ccc */ if (server->conn_type == CLI_NONE) { server->conn_type = CLI_PROXY; + if (proxy_client_connect_cb) { proxy_client_connect_cb(&server->addr, server - servers, server->net_idx); } } -#endif +#endif /* CONFIG_BLE_MESH_BQB_TEST */ if (server->conn_type == CLI_PROXY) { return proxy_recv(conn, NULL, data, len, 0, 0); @@ -665,8 +702,7 @@ static ssize_t proxy_recv_ntf(struct bt_mesh_conn *conn, uint8_t *data, uint16_t return -EINVAL; } -/** - * Currently proxy client doesn't need bt_mesh_proxy_client_gatt_enable() +/* Currently proxy client doesn't need bt_mesh_proxy_client_gatt_enable() * and bt_mesh_proxy_client_gatt_disable() functions, and once they are * used, proxy client can be enabled to parse node_id_adv and net_id_adv * in order to support proxy client role. @@ -677,6 +713,8 @@ int bt_mesh_proxy_client_gatt_enable(void) { int i; + BT_DBG("ProxyClientGattEnable"); + for (i = 0; i < ARRAY_SIZE(servers); i++) { if (servers[i].conn) { servers[i].conn_type = CLI_PROXY; @@ -696,8 +734,9 @@ int bt_mesh_proxy_client_gatt_disable(void) { int i; - /** - * TODO: + BT_DBG("ProxyClientGattDisable"); + + /* TODO: * Once this function is invoked, proxy client shall stop handling * node_id & net_id adv packets, and if proxy connection exists, * it should be disconnected. @@ -739,6 +778,8 @@ static struct bt_mesh_subnet *bt_mesh_is_net_id_exist(const uint8_t net_id[8]) size = bt_mesh_rx_netkey_size(); + BT_DBG("IsNetIDExist, Size %u", size); + for (i = 0U; i < size; i++) { sub = bt_mesh_rx_netkey_get(i); if (sub && !memcmp(sub->keys[sub->kr_flag].net_id, net_id, 8)) { @@ -753,8 +794,11 @@ void bt_mesh_proxy_client_gatt_adv_recv(struct net_buf_simple *buf, const bt_mesh_addr_t *addr, int8_t rssi) { bt_mesh_proxy_adv_ctx_t ctx = {0}; + struct bt_mesh_subnet *sub = NULL; uint8_t type = 0U; + BT_DBG("ProxyClientGattAdvRecv, Rssi %d", rssi); + /* Check if connection reaches the maximum limitation */ if (bt_mesh_gattc_get_free_conn_count() == 0) { BT_INFO("BLE connections for mesh reach max limit"); @@ -763,14 +807,15 @@ void bt_mesh_proxy_client_gatt_adv_recv(struct net_buf_simple *buf, type = net_buf_simple_pull_u8(buf); + BT_DBG("Type %u", type); + switch (type) { - case BLE_MESH_PROXY_ADV_NET_ID: { + case BLE_MESH_PROXY_ADV_NET_ID: if (buf->len != sizeof(ctx.net_id.net_id)) { BT_WARN("Malformed Network ID"); return; } - struct bt_mesh_subnet *sub = NULL; sub = bt_mesh_is_net_id_exist(buf->data); if (!sub) { return; @@ -779,7 +824,6 @@ void bt_mesh_proxy_client_gatt_adv_recv(struct net_buf_simple *buf, memcpy(ctx.net_id.net_id, buf->data, buf->len); ctx.net_id.net_idx = sub->net_idx; break; - } case BLE_MESH_PROXY_ADV_NODE_ID: /* Gets node identity information. * hash = aes-ecb(identity key, 16 octets(padding + random + src)) mod 2^64, @@ -808,6 +852,8 @@ int bt_mesh_proxy_client_connect(const uint8_t addr[6], uint8_t addr_type, uint1 bt_mesh_addr_t remote_addr = {0}; int result = 0; + BT_DBG("ProxyClientConnect, NetIdx 0x%04x", net_idx); + if (!addr || addr_type > BLE_MESH_ADDR_RANDOM) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -830,13 +876,13 @@ int bt_mesh_proxy_client_disconnect(uint8_t conn_handle) { struct bt_mesh_conn *conn = NULL; + BT_DBG("ProxyClientDisconnect, ConnHandle 0x%04x", conn_handle); + if (conn_handle >= BLE_MESH_MAX_CONN) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } - BT_DBG("conn_handle %d", conn_handle); - conn = servers[conn_handle].conn; if (!conn) { BT_ERR("Not connected, conn handle %d", conn_handle); @@ -861,6 +907,8 @@ uint16_t bt_mesh_proxy_client_get_conn_count(void) count++; } + BT_DBG("ProxyClientGetConnCount, Count %u", count); + return count; } @@ -870,6 +918,8 @@ bool bt_mesh_proxy_client_relay(struct net_buf_simple *buf, uint16_t dst) int err = 0; int i; + BT_DBG("ProxyClientRelay, Dst 0x%04x", dst); + for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; NET_BUF_SIMPLE_DEFINE(msg, 32); @@ -900,12 +950,15 @@ static int beacon_send(struct bt_mesh_conn *conn, struct bt_mesh_subnet *sub, bo { NET_BUF_SIMPLE_DEFINE(buf, 28); + BT_DBG("BeaconSend, ConnHandle 0x%04x Private %u", conn->handle, private); + net_buf_simple_reserve(&buf, 1); + #if CONFIG_BLE_MESH_PRB_SRV if (private) { bt_mesh_private_beacon_create(sub, &buf); } else -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ { bt_mesh_secure_beacon_create(sub, &buf); } @@ -919,6 +972,8 @@ bool bt_mesh_proxy_client_beacon_send(struct bt_mesh_subnet *sub, bool private) int err = 0; int i; + BT_DBG("ProxyClientBeaconSend, Private %u", private); + /* NULL means we send Secure Network Beacon or Mesh Private Beacon on all subnets */ if (!sub) { #if CONFIG_BLE_MESH_NODE @@ -975,6 +1030,8 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt uint16_t alloc_len = 0U; int err = 0; + BT_DBG("SendProxyCfg, ConnHandle 0x%04x NetIdx 0x%04x", conn->handle, net_idx); + tx.sub = bt_mesh_subnet_get(net_idx); if (!tx.sub) { BT_ERR("NetKey 0x%04x not found", net_idx); @@ -1038,6 +1095,7 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt */ buf = bt_mesh_alloc_buf(1 + BLE_MESH_NET_HDR_LEN + alloc_len + 8); if (!buf) { + BT_ERR("Out of memory"); return -ENOMEM; } @@ -1072,11 +1130,10 @@ static int send_proxy_cfg(struct bt_mesh_conn *conn, uint16_t net_idx, struct bt #endif /* CONFIG_BLE_MESH_DF_SRV */ } - BT_DBG("len %u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); err = bt_mesh_net_encode(&tx, buf, true); if (err) { - BT_ERR("Encoding proxy cfg message failed (err %d)", err); goto end; } @@ -1095,13 +1152,14 @@ int bt_mesh_proxy_client_cfg_send(uint8_t conn_handle, uint16_t net_idx, { struct bt_mesh_conn *conn = NULL; - if (conn_handle >= BLE_MESH_MAX_CONN || !pdu || pdu->opcode > BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL) { + BT_DBG("ProxyClientCfgSend, ConnHandle 0x%04x NetIdx 0x%04x", conn_handle, net_idx); + + if (conn_handle >= BLE_MESH_MAX_CONN || !pdu || + pdu->opcode > BLE_MESH_PROXY_CFG_DIRECTED_PROXY_CONTROL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } - BT_DBG("conn_handle %d, net_idx 0x%04x", conn_handle, net_idx); - conn = servers[conn_handle].conn; if (!conn) { BT_ERR("Not connected, conn handle %d", conn_handle); @@ -1113,7 +1171,7 @@ int bt_mesh_proxy_client_cfg_send(uint8_t conn_handle, uint16_t net_idx, */ if (servers[conn_handle].net_idx != net_idx) { BT_ERR("NetKeyIndex 0x%04x mismatch, expect 0x%04x", - net_idx, servers[conn_handle].net_idx); + net_idx, servers[conn_handle].net_idx); return -EIO; } @@ -1125,16 +1183,19 @@ int bt_mesh_proxy_client_init(void) { int i; + BT_DBG("ProxyClientInit"); + /* Initialize the server receive buffers */ for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; k_delayed_work_init(&server->sar_timer, proxy_sar_timeout); + server->buf.size = BLE_MESH_PROXY_BUF_SIZE; server->buf.__buf = server_buf_data + (i * BLE_MESH_PROXY_BUF_SIZE); #if CONFIG_BLE_MESH_GATT_PROXY_CLIENT server->net_idx = BLE_MESH_KEY_UNUSED; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ } bt_mesh_gattc_conn_cb_register(&conn_callbacks); @@ -1143,7 +1204,7 @@ int bt_mesh_proxy_client_init(void) bt_mesh_update_exceptional_list(BLE_MESH_EXCEP_LIST_SUB_CODE_ADD, BLE_MESH_EXCEP_LIST_TYPE_MESH_PROXY_ADV, NULL); -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN && CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ return 0; } @@ -1153,6 +1214,8 @@ int bt_mesh_proxy_client_deinit(void) { int i; + BT_DBG("ProxyClientDeinit"); + /* Initialize the server receive buffers */ for (i = 0; i < ARRAY_SIZE(servers); i++) { struct bt_mesh_proxy_server *server = &servers[i]; diff --git a/components/bt/esp_ble_mesh/core/proxy_server.c b/components/bt/esp_ble_mesh/core/proxy_server.c index c6cc15cab6..6a498f7508 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.c +++ b/components/bt/esp_ble_mesh/core/proxy_server.c @@ -24,7 +24,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #if (CONFIG_BLE_MESH_NODE && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_SERVER @@ -37,7 +37,7 @@ _Static_assert(!(IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && IS_ENABLED(CON #if CONFIG_BLE_MESH_USE_BLE_50 static uint8_t proxy_adv_inst = BLE_MESH_ADV_INS_UNUSED; -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #define ADV_OPT (BLE_MESH_ADV_OPT_CONNECTABLE | BLE_MESH_ADV_OPT_ONE_TIME) @@ -58,7 +58,7 @@ static const struct bt_mesh_adv_param slow_adv_param = { .interval_max = BLE_MESH_GAP_ADV_SLOW_INT_MAX, .channel_map = BLE_MESH_ADV_CHAN_DEFAULT, #if CONFIG_BLE_MESH_USE_BLE_50 - .primary_phy = BLE_MESH_ADV_PHY_1M, + .primary_phy = BLE_MESH_ADV_PHY_1M, .secondary_phy = BLE_MESH_ADV_PHY_1M, .adv_duration = 0, .adv_count = 0, @@ -73,7 +73,7 @@ static const struct bt_mesh_adv_param fast_adv_param = { .interval_max = BLE_MESH_GAP_ADV_FAST_INT_MAX_0, .channel_map = BLE_MESH_ADV_CHAN_DEFAULT, #if CONFIG_BLE_MESH_USE_BLE_50 - .primary_phy = BLE_MESH_ADV_PHY_1M, + .primary_phy = BLE_MESH_ADV_PHY_1M, .secondary_phy = BLE_MESH_ADV_PHY_1M, .adv_duration = 0, .adv_count = 0, @@ -87,19 +87,19 @@ static bool proxy_adv_enabled; #if CONFIG_BLE_MESH_GATT_PROXY_SERVER static void proxy_send_beacons(struct k_work *work); static uint16_t proxy_ccc_val; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT static uint16_t prov_ccc_val; static bool prov_fast_adv; static uint32_t prov_start_time; -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ static struct bt_mesh_proxy_client clients[BLE_MESH_MAX_CONN] = { [0 ... (BLE_MESH_MAX_CONN - 1)] = { #if CONFIG_BLE_MESH_PROXY_PRIVACY .proxy_privacy = BLE_MESH_PROXY_PRIVACY_DISABLED, -#endif +#endif /* CONFIG_BLE_MESH_PROXY_PRIVACY */ }, }; @@ -116,6 +116,8 @@ static char device_name[DEVICE_NAME_SIZE + 1]; struct bt_mesh_proxy_client *bt_mesh_proxy_server_get_client(uint8_t index) { + BT_DBG("ProxyServerGetClient, Index %u", index); + return &clients[0]; } @@ -126,11 +128,15 @@ uint8_t bt_mesh_proxy_server_get_client_count(void) int bt_mesh_set_device_name(const char *name) { + BT_DBG("SetDeviceName"); + if (!name) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; } + BT_DBG("Name %s", name); + if (strlen(name) > DEVICE_NAME_SIZE) { BT_ERR("Too long device name (len %d)", strlen(name)); return -EINVAL; @@ -144,6 +150,8 @@ int bt_mesh_set_device_name(const char *name) const char *bt_mesh_get_device_name(void) { + BT_DBG("GetDeviceName %s", device_name); + return device_name; } @@ -151,6 +159,8 @@ static struct bt_mesh_proxy_client *find_client(struct bt_mesh_conn *conn) { int i; + BT_DBG("FindClient, ConnHandle 0x%04x", conn->handle); + for (i = 0; i < ARRAY_SIZE(clients); i++) { if (clients[i].conn == conn) { return &clients[i]; @@ -164,7 +174,7 @@ static void proxy_sar_timeout(struct k_work *work) { struct bt_mesh_proxy_client *client = NULL; - BT_WARN("Proxy SAR timeout"); + BT_WARN("ProxySARTimeout"); client = CONTAINER_OF(work, struct bt_mesh_proxy_client, sar_timer.work); if (!client || !client->conn) { @@ -178,12 +188,13 @@ static void proxy_sar_timeout(struct k_work *work) void bt_mesh_proxy_server_adv_flag_set(bool enable) { + BT_DBG("ProxyServerAdvFlagSet, Enable %u/%u", proxy_adv_enabled, enable); + proxy_adv_enabled = enable; } #if CONFIG_BLE_MESH_GATT_PROXY_SERVER -/** - * The following callbacks are used to notify proper information +/* The following callbacks are used to notify proper information * to the application layer. */ static proxy_server_connect_cb_t proxy_server_connect_cb; @@ -204,6 +215,8 @@ static int next_idx; bool bt_mesh_proxy_server_find_client_by_addr(uint16_t addr) { + BT_DBG("ProxyServerFindClient, Addr 0x%04x", addr); + for (size_t i = 0; i < ARRAY_SIZE(clients); i++) { if (clients[i].conn) { for (size_t j = 0; j < ARRAY_SIZE(clients[i].filter); j++) { @@ -231,6 +244,8 @@ uint8_t bt_mesh_proxy_server_get_all_client_type(void) } } + BT_DBG("ProxyServerGetAllClientType, type 0x%02x", client_type); + return client_type; } @@ -239,13 +254,16 @@ static int filter_set(struct bt_mesh_proxy_client *client, { uint8_t type = 0U; + BT_INFO("FilterSet"); + if (buf->len < 1) { BT_WARN("Too short Filter Set message"); return -EINVAL; } type = net_buf_simple_pull_u8(buf); - BT_INFO("Set filter type 0x%02x", type); + + BT_INFO("Type 0x%02x", type); switch (type) { case 0x00: @@ -276,7 +294,7 @@ static void filter_add(struct bt_mesh_proxy_client *client, * is the element address of Proxy Client. */ - BT_DBG("addr 0x%04x", addr); + BT_DBG("FilterAdd, Addr 0x%04x ProxyClient %u", addr, proxy_client); if (addr == BLE_MESH_ADDR_UNASSIGNED) { return; @@ -306,14 +324,14 @@ static void filter_add(struct bt_mesh_proxy_client *client, } } - BT_WARN("Proxy filter is full!"); + BT_WARN("ProxyFilterFull"); } static void filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr) { int i; - BT_DBG("addr 0x%04x", addr); + BT_DBG("FilterRemove, Addr 0x%04x", addr); if (addr == BLE_MESH_ADDR_UNASSIGNED) { return; @@ -341,6 +359,8 @@ static void send_filter_status(struct bt_mesh_proxy_client *client, uint16_t filter_size = 0U; int i, err = 0; + BT_DBG("SetFilterStatus"); + /* Configuration messages always have dst unassigned */ tx.ctx->addr = BLE_MESH_ADDR_UNASSIGNED; tx.ctx->send_cred = BLE_MESH_FLOODING_CRED, @@ -364,11 +384,10 @@ static void send_filter_status(struct bt_mesh_proxy_client *client, net_buf_simple_add_be16(buf, filter_size); - BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); err = bt_mesh_net_encode(&tx, buf, true); if (err) { - BT_ERR("Encoding proxy filter status failed (err %d)", err); return; } @@ -385,13 +404,14 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client) uint8_t opcode = 0U; int err = 0; + BT_DBG("ProxyCfg"); + if (client->buf.len > 29) { BT_ERR("Too large proxy cfg pdu (len %d)", client->buf.len); return; } - err = bt_mesh_net_decode(&client->buf, BLE_MESH_NET_IF_PROXY_CFG, - &rx, &buf); + err = bt_mesh_net_decode(&client->buf, BLE_MESH_NET_IF_PROXY_CFG, &rx, &buf); if (err) { BT_ERR("Failed to decode Proxy Configuration (err %d)", err); return; @@ -400,7 +420,7 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client) rx.local_match = 1U; if (bt_mesh_rpl_check(&rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", rx.ctx.addr, rx.ctx.recv_dst, rx.seq); return; } @@ -408,7 +428,7 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client) /* Remove network headers */ net_buf_simple_pull(&buf, BLE_MESH_NET_HDR_LEN); - BT_DBG("%u bytes: %s", buf.len, bt_hex(buf.data, buf.len)); + BT_DBG("Len %u: %s", buf.len, bt_hex(buf.data, buf.len)); if (buf.len < 1) { BT_WARN("Too short proxy configuration PDU"); @@ -464,6 +484,8 @@ static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subne { NET_BUF_SIMPLE_DEFINE(buf, 28); + BT_DBG("BeaconSend"); + net_buf_simple_reserve(&buf, 1); #if CONFIG_BLE_MESH_PROXY_PRIVACY @@ -475,7 +497,7 @@ static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subne bt_mesh_private_beacon_create(sub, &buf); } else -#endif +#endif /* CONFIG_BLE_MESH_PROXY_PRIVACY */ { bt_mesh_secure_beacon_create(sub, &buf); } @@ -485,10 +507,12 @@ static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subne static void proxy_send_beacons(struct k_work *work) { - struct bt_mesh_proxy_client *client = NULL; + struct bt_mesh_proxy_client *client = CONTAINER_OF(work, + struct bt_mesh_proxy_client, + send_beacons);; int i; - client = CONTAINER_OF(work, struct bt_mesh_proxy_client, send_beacons); + BT_DBG("ProxySendBeacons"); /* Upon connection, the Proxy Server shall evaluate Proxy Privacy parameter * for the connection and the Proxy Server shall retain the value of the @@ -523,7 +547,7 @@ static void proxy_send_beacons(struct k_work *work) } else if (sub->proxy_privacy == BLE_MESH_PROXY_PRIVACY_ENABLED) { #if CONFIG_BLE_MESH_PRB_SRV /* TODO: Send Mesh Private Beacon */ -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } } #endif @@ -534,6 +558,8 @@ void bt_mesh_proxy_server_beacon_send(struct bt_mesh_subnet *sub) { int i; + BT_DBG("ProxyServerBeaconSend, Sub %p", sub); + if (!sub) { /* NULL means we send on all subnets */ for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { @@ -559,10 +585,14 @@ void bt_mesh_proxy_server_identity_start(struct bt_mesh_subnet *sub) /* Prioritize the recently enabled subnet */ next_idx = sub - bt_mesh.sub; + + BT_DBG("ProxyServerIdentityStart, NextIdx %d", next_idx); } void bt_mesh_proxy_server_identity_stop(struct bt_mesh_subnet *sub) { + BT_DBG("ProxyServerIdentityStop"); + sub->node_id = BLE_MESH_NODE_IDENTITY_STOPPED; sub->node_id_start = 0U; } @@ -571,7 +601,10 @@ int bt_mesh_proxy_identity_enable(void) { int i, count = 0; + BT_DBG("ProxyIdentityEnable"); + if (!bt_mesh_is_provisioned()) { + BT_DBG("NotProvisioned"); return -EAGAIN; } @@ -587,9 +620,12 @@ int bt_mesh_proxy_identity_enable(void) } bt_mesh_proxy_server_identity_start(sub); + count++; } + BT_DBG("SubCount %u", count); + if (count) { bt_mesh_adv_update(); } @@ -605,16 +641,22 @@ void bt_mesh_proxy_server_private_identity_start(struct bt_mesh_subnet *sub) /* Prioritize the recently enabled subnet */ next_idx = sub - bt_mesh.sub; + + BT_DBG("ProxyServerPrivateIdentityStart, NextIdx %d", next_idx); } void bt_mesh_proxy_server_private_identity_stop(struct bt_mesh_subnet *sub) { + BT_DBG("ProxyServerPrivateIdentityStop"); + sub->private_node_id = BLE_MESH_PRIVATE_NODE_IDENTITY_STOPPED; sub->node_id_start = 0U; } bool bt_mesh_proxy_server_is_node_id_enable(void) { + BT_DBG("ProxyServerIsNodeIDEnable"); + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { /* If the Node Identity state of the node for any subnet * is 0x01 (i.e. running), return true. @@ -634,22 +676,27 @@ static bool is_exist_private_node_id_enable(void) { for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { /* If the value of the Node Identity state of the node - * for any subnet is 0x01,If exist return true. + * for any subnet is 0x01, if exist return true. */ struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; if (sub->net_idx != BLE_MESH_KEY_UNUSED && sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING) { + BT_DBG("PrivateNodeIDExist, NetIdx 0x%04x", sub->net_idx); return true; } } + BT_DBG("PrivateNodeIDNotExist"); return false; } int bt_mesh_proxy_private_identity_disable(void) { + BT_DBG("ProxyPrivateIdentityDisable"); + if (!bt_mesh_is_provisioned()) { + BT_DBG("NotProvisioned"); return -EAGAIN; } @@ -675,7 +722,10 @@ int bt_mesh_proxy_private_identity_enable(void) { int count = 0; + BT_DBG("ProxyPrivateIdentityEnable"); + if (!bt_mesh_is_provisioned()) { + BT_DBG("NotProvisioned"); return -EAGAIN; } @@ -691,9 +741,12 @@ int bt_mesh_proxy_private_identity_enable(void) } bt_mesh_proxy_server_private_identity_start(sub); + count++; } + BT_DBG("SubCount %u", count); + if (count) { bt_mesh_adv_update(); } @@ -701,10 +754,12 @@ int bt_mesh_proxy_private_identity_enable(void) return 0; } #endif /* CONFIG_BLE_MESH_PRB_SRV */ -#endif /* GATT_PROXY */ +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) { + BT_DBG("ProxyCompletePDU"); + switch (client->msg_type) { #if CONFIG_BLE_MESH_GATT_PROXY_SERVER case BLE_MESH_PROXY_NET_PDU: @@ -719,13 +774,13 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) BT_DBG("Mesh Configuration PDU"); proxy_cfg(client); break; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT case BLE_MESH_PROXY_PROV: BT_DBG("Mesh Provisioning PDU"); bt_mesh_pb_gatt_recv(client->conn, &client->buf); break; -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ default: BT_WARN("Unhandled Message Type 0x%02x", client->msg_type); break; @@ -736,27 +791,35 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) #if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (client->msg_type < BLE_MESH_PROXY_PROV && client->proxy_msg_recv == false) { - client->proxy_msg_recv = true; - /** - * @Spec: P626 - * When a new connection is established between a Proxy Client and the Directed Proxy Server, and the - * first message received from the Proxy Client is a successfully processed DIRECTED_PROXY_CONTROL - * message, then the Directed Proxy Server shall set the Proxy_Client_Type parameter to Directed Proxy Client, - * shall set the Use_Directed parameter to Disable for all subnets known to the Directed Proxy Server - * except the subnet identified by the received message; - * otherwise, the Directed Proxy Server shall set the Proxy_Client_Type parameter to Proxy Client. + /* @Spec: P626 + * When a new connection is established between a Proxy Client and + * the Directed Proxy Server, and the first message received from + * the Proxy Client is a successfully processed DIRECTED_PROXY_CONTROL + * message, then the Directed Proxy Server shall set the Proxy_Client_Type + * parameter to Directed Proxy Client, shall set the Use_Directed + * parameter to Disable for all subnets known to the Directed Proxy + * Server except the subnet identified by the received message; + * otherwise, the Directed Proxy Server shall set the Proxy_Client_Type + * parameter to Proxy Client. * - * If the first message received is DIRECTED_PROXY_CONTROL, proxy_client_type will be set to Directed Proxy Client, - * But if device didn't receive DIRECTED_PROXY_CONTROL message and all received is normal proxy message, That - * client type will be always in UNSET state, because we set client type in handle function of DIRECTED_PROXY_CONTROL. + * If the first message received is DIRECTED_PROXY_CONTROL, proxy_client_type + * will be set to Directed Proxy Client. + * But if device didn't receive DIRECTED_PROXY_CONTROL message and all + * received is normal proxy message, That client type will be always in + * UNSET state, because we set client type in handle function of + * DIRECTED_PROXY_CONTROL. * * So the flowing code was used to avoid that situation. - */ + */ + client->proxy_msg_recv = true; + + BT_DBG("ProxyClientTypeUpdate"); + if (client->proxy_client_type == BLE_MESH_PROXY_CLI_TYPE_UNSET) { client->proxy_client_type = BLE_MESH_PROXY_CLI_TYPE_PROXY_CLIENT; } } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ } #define ATTR_IS_PROV(attr) (attr->user_data != NULL) @@ -768,6 +831,8 @@ static ssize_t proxy_recv(struct bt_mesh_conn *conn, struct bt_mesh_proxy_client *client = find_client(conn); const uint8_t *data = buf; + BT_DBG("ProxyRecv"); + if (!client) { BT_ERR("No Proxy Client found"); return -ENOTCONN; @@ -853,7 +918,7 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) struct bt_mesh_proxy_client *client = NULL; int i; - BT_DBG("conn %p err 0x%02x", conn, err); + BT_DBG("ProxyConnected, ConnHandle 0x%04x Err 0x%02x", conn->handle, err); if (gatt_svc == MESH_GATT_PROV && conn_count == 1) { BT_WARN("Only one prov connection could exists"); @@ -866,7 +931,7 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) /* Since we use ADV_OPT_ONE_TIME */ #if !CONFIG_BLE_MESH_USE_BLE_50 bt_mesh_proxy_server_adv_flag_set(false); -#endif +#endif /* !CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX /* Before re-enabling advertising, stop advertising @@ -874,7 +939,9 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) * Network Identity type. */ bt_mesh_proxy_server_stop_solic_adv_priv_net_id(); -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ + + BT_DBG("ConnCount %u vs. %u", conn_count, BLE_MESH_MAX_CONN); /* Try to re-enable advertising in case it's possible */ if (conn_count < BLE_MESH_MAX_CONN) { @@ -895,13 +962,15 @@ static void proxy_connected(struct bt_mesh_conn *conn, uint8_t err) client->conn = bt_mesh_conn_ref(conn); client->filter_type = SRV_NONE; + #if CONFIG_BLE_MESH_GATT_PROXY_SERVER (void)memset(client->filter, 0, sizeof(client->filter)); if (proxy_server_connect_cb) { proxy_server_connect_cb(conn->handle); } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + net_buf_simple_reset(&client->buf); } @@ -909,7 +978,8 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) { int i; - BT_DBG("conn %p reason 0x%02x", conn, reason); + BT_DBG("ProxyDisconnected, ConnHandle 0x%04x Count %u Reason 0x%02x", + conn->handle, conn_count, reason); conn_count--; @@ -921,7 +991,8 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) if (proxy_server_disconnect_cb) { proxy_server_disconnect_cb(conn->handle, reason); } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ + if (IS_ENABLED(CONFIG_BLE_MESH_PB_GATT) && client->filter_type == SRV_PROV) { bt_mesh_pb_gatt_close(conn, reason); @@ -929,11 +1000,11 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) #if CONFIG_BLE_MESH_PROXY_PRIVACY client->proxy_privacy = BLE_MESH_PROXY_PRIVACY_DISABLED; -#endif +#endif /* CONFIG_BLE_MESH_PROXY_PRIVACY */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV k_delayed_work_cancel(&rand_upd_timer); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV */ k_delayed_work_cancel(&client->sar_timer); bt_mesh_conn_unref(client->conn); @@ -953,13 +1024,15 @@ static void proxy_disconnected(struct bt_mesh_conn *conn, uint8_t reason) if (bt_mesh_directed_proxy_server_update_dep_node(NULL, &clients[i], 0)) { BT_ERR("Proxy disconnected, failed to update dependent node"); } -#endif /* CONFIG_BLE_MESH_DF_SRV */ +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_DF_SRV */ } struct net_buf_simple *bt_mesh_proxy_server_get_buf(void) { struct net_buf_simple *buf = &clients[0].buf; + BT_DBG("ProxyServerGetBuf"); + net_buf_simple_reset(buf); return buf; @@ -974,9 +1047,11 @@ static ssize_t prov_ccc_write(struct bt_mesh_conn *conn, struct bt_mesh_proxy_client *client = NULL; uint16_t *value = attr->user_data; - BT_DBG("len %u: %s", len, bt_hex(buf, len)); + BT_DBG("ProvCCCWrite"); + BT_DBG("Len %u: %s", len, bt_hex(buf, len)); if (len != sizeof(*value)) { + BT_WARN("MismatchLen %u != %u", len, sizeof(*value)); return BLE_MESH_GATT_ERR(BLE_MESH_ATT_ERR_INVALID_ATTRIBUTE_LEN); } @@ -1007,6 +1082,8 @@ static ssize_t prov_ccc_read(struct bt_mesh_conn *conn, { uint16_t *value = attr->user_data; + BT_DBG("ProvCCCRead, Len %u", len); + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, value, sizeof(*value)); } @@ -1036,6 +1113,8 @@ int bt_mesh_proxy_server_prov_enable(void) { int i; + BT_DBG("ProxyServerProvEnable"); + if (gatt_svc == MESH_GATT_PROV) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1063,6 +1142,8 @@ int bt_mesh_proxy_server_prov_disable(bool disconnect) { int i; + BT_DBG("ProxyServerProvDisable, Disconnect %u", disconnect); + if (gatt_svc == MESH_GATT_NONE) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1106,9 +1187,11 @@ static ssize_t proxy_ccc_write(struct bt_mesh_conn *conn, struct bt_mesh_proxy_client *client = NULL; uint16_t value = 0U; - BT_DBG("len %u: %s", len, bt_hex(buf, len)); + BT_DBG("ProxyCCCWrite"); + BT_DBG("Len %u: %s", len, bt_hex(buf, len)); if (len != sizeof(value)) { + BT_WARN("MismatchLen %u != %u", len, sizeof(value)); return BLE_MESH_GATT_ERR(BLE_MESH_ATT_ERR_INVALID_ATTRIBUTE_LEN); } @@ -1163,6 +1246,8 @@ static ssize_t proxy_ccc_read(struct bt_mesh_conn *conn, { uint16_t *value = attr->user_data; + BT_DBG("ProxyCCCRead, Len %u", len); + return bt_mesh_gatts_attr_read(conn, attr, buf, len, offset, value, sizeof(*value)); } @@ -1192,6 +1277,8 @@ int bt_mesh_proxy_server_gatt_enable(void) { int i; + BT_DBG("ProxyServerGattEnable"); + if (gatt_svc == MESH_GATT_PROXY) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1218,6 +1305,8 @@ void bt_mesh_proxy_server_gatt_disconnect(void) { int i; + BT_DBG("ProxyServerGattDisconnect"); + for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; @@ -1231,6 +1320,8 @@ void bt_mesh_proxy_server_gatt_disconnect(void) int bt_mesh_proxy_server_gatt_disable(void) { + BT_DBG("ProxyServerGattDisable"); + if (gatt_svc == MESH_GATT_NONE) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -1255,7 +1346,7 @@ void bt_mesh_proxy_server_addr_add(struct net_buf_simple *buf, uint16_t addr) struct bt_mesh_proxy_client, buf); - BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); + BT_DBG("ProxyServerAddrAdd, Type %u Addr 0x%04x", client->filter_type, addr); if (client->filter_type == SRV_WHITELIST) { filter_add(client, addr, true); @@ -1264,16 +1355,16 @@ void bt_mesh_proxy_server_addr_add(struct net_buf_simple *buf, uint16_t addr) } } -static bool client_filter_match(struct bt_mesh_proxy_client *client, - uint16_t addr) +static bool client_filter_match(struct bt_mesh_proxy_client *client, uint16_t addr) { int i; - BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); + BT_DBG("ClientFilterMatch, Type %u Addr 0x%04x", client->filter_type, addr); if (client->filter_type == SRV_BLACKLIST) { for (i = 0; i < ARRAY_SIZE(client->filter); i++) { if (client->filter[i].addr == addr) { + BT_DBG("InBlackList"); return false; } } @@ -1282,12 +1373,14 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client, } if (addr == BLE_MESH_ADDR_ALL_NODES) { + BT_DBG("AllNodes"); return true; } if (client->filter_type == SRV_WHITELIST) { for (i = 0; i < ARRAY_SIZE(client->filter); i++) { if (client->filter[i].addr == addr) { + BT_DBG("InWhiteList"); return true; } } @@ -1301,7 +1394,7 @@ bool bt_mesh_proxy_server_relay(struct net_buf_simple *buf, uint16_t dst) bool relayed = false; int i; - BT_DBG("%u bytes to dst 0x%04x", buf->len, dst); + BT_DBG("ProxyServerRelay, Len %u Dst 0x%04x", buf->len, dst); for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; @@ -1327,24 +1420,24 @@ bool bt_mesh_proxy_server_relay(struct net_buf_simple *buf, uint16_t dst) return relayed; } - #endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ static int proxy_send(struct bt_mesh_conn *conn, const void *data, uint16_t len) { - BT_DBG("%u bytes: %s", len, bt_hex(data, len)); + BT_DBG("ProxySend"); + BT_DBG("Len %u: %s", len, bt_hex(data, len)); #if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (gatt_svc == MESH_GATT_PROXY) { return bt_mesh_gatts_notify(conn, &proxy_attrs[4], data, len); } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT if (gatt_svc == MESH_GATT_PROV) { return bt_mesh_gatts_notify(conn, &prov_attrs[4], data, len); } -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ return 0; } @@ -1354,11 +1447,15 @@ int bt_mesh_proxy_server_segment_send(struct bt_mesh_conn *conn, uint8_t type, { uint16_t mtu = 0U; - BT_DBG("conn %p type 0x%02x len %u: %s", conn, type, msg->len, - bt_hex(msg->data, msg->len)); + BT_DBG("ProxyServerSegSend"); + BT_DBG("ConnHandle 0x%04x Type %u", conn->handle, type); + BT_DBG("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ mtu = bt_mesh_gatt_get_mtu(conn) - 3; + + BT_DBG("MTU %u", mtu); + if (mtu > msg->len) { net_buf_simple_push_u8(msg, BLE_MESH_PROXY_PDU_HDR(BLE_MESH_PROXY_SAR_COMP, type)); return proxy_send(conn, msg->data, msg->len); @@ -1388,6 +1485,8 @@ int bt_mesh_proxy_server_send(struct bt_mesh_conn *conn, uint8_t type, { struct bt_mesh_proxy_client *client = find_client(conn); + BT_DBG("ProxyServerSend, Type 0x%02x", type); + if (!client) { BT_ERR("No Proxy Client found"); return -ENOTCONN; @@ -1409,10 +1508,9 @@ static const struct bt_mesh_adv_data prov_ad[] = { BLE_MESH_ADV_DATA_BYTES(BLE_MESH_DATA_UUID16_ALL, 0x27, 0x18), BLE_MESH_ADV_DATA(BLE_MESH_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), }; -#endif /* PB_GATT */ +#endif /* CONFIG_BLE_MESH_PB_GATT */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER - #define NET_ID_LEN 11 #define NODE_ID_LEN 19 #define PRIVATE_NET_ID_LEN 19 @@ -1460,6 +1558,9 @@ static size_t gatt_proxy_adv_create(struct bt_mesh_adv_data *proxy_sd) /* One octet for Length, and another octet for AD type */ size_t sd_space = 29; + BT_DBG("GattProxyAdvCreate"); + BT_DBG("Name %u: %s", name_len, name); + if (name_len > sd_space) { proxy_sd->type = BLE_MESH_DATA_NAME_SHORTENED; proxy_sd->data_len = sd_space; @@ -1480,6 +1581,8 @@ static int node_id_adv(struct bt_mesh_subnet *sub) uint8_t tmp[16] = {0}; int err = 0; + BT_DBG("NodeIDAdv, NetIdx 0x%04x", sub->net_idx); + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_NODE_ID; err = bt_mesh_rand(proxy_svc_data + 11, 8); @@ -1502,10 +1605,10 @@ static int node_id_adv(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_USE_BLE_50 err = bt_le_ext_adv_start(proxy_adv_inst, &fast_adv_param, node_id_ad, ARRAY_SIZE(node_id_ad), &proxy_sd, proxy_sd_len); -#else +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_start(&fast_adv_param, node_id_ad, ARRAY_SIZE(node_id_ad), &proxy_sd, proxy_sd_len); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_WARN("Failed to advertise using Node ID (err %d)", err); return err; @@ -1522,10 +1625,10 @@ static int net_id_adv(struct bt_mesh_subnet *sub) size_t proxy_sd_len = 0U; int err = 0; - proxy_svc_data[2] = BLE_MESH_PROXY_ADV_NET_ID; + BT_DBG("NetIDAdv, NetIdx 0x%04x", sub->net_idx); + BT_DBG("NetId %s", bt_hex(sub->keys[sub->kr_flag].net_id, 8)); - BT_DBG("Advertising with NetId %s", - bt_hex(sub->keys[sub->kr_flag].net_id, 8)); + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_NET_ID; memcpy(proxy_svc_data + 3, sub->keys[sub->kr_flag].net_id, 8); proxy_sd_len = gatt_proxy_adv_create(&proxy_sd); @@ -1533,10 +1636,10 @@ static int net_id_adv(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_USE_BLE_50 err = bt_le_ext_adv_start(proxy_adv_inst, &slow_adv_param, net_id_ad, ARRAY_SIZE(net_id_ad), &proxy_sd, proxy_sd_len); -#else +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_start(&slow_adv_param, net_id_ad, ARRAY_SIZE(net_id_ad), &proxy_sd, proxy_sd_len); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_WARN("Failed to advertise using Network ID (err %d)", err); return err; @@ -1550,11 +1653,15 @@ static int net_id_adv(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_PRB_SRV void bt_mesh_proxy_server_update_net_id_rand(void) { + BT_DBG("ProxyServerUpdateNetIDRand"); + k_delayed_work_submit(&rand_upd_timer, RAND_UPDATE_INTERVAL); } void bt_mesh_proxy_server_update_net_id_rand_stop(void) { + BT_DBG("ProxyServerUpdateNetIDRandStop"); + k_delayed_work_cancel(&rand_upd_timer); } @@ -1562,6 +1669,8 @@ static void random_update_timeout(struct k_work *work) { int err = 0; + BT_DBG("RandomUpdateTimeout"); + err = bt_mesh_rand(net_id_random, 8); if (err) { BT_ERR("Generate random value failed"); @@ -1578,6 +1687,8 @@ static int private_node_id_adv(struct bt_mesh_subnet *sub) uint8_t tmp[16] = {0}; int err = 0; + BT_DBG("PrivateNodeIDAdv, NetIdx 0x%04x", sub->net_idx); + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_PRIVATE_NODE_ID; err = bt_mesh_rand(proxy_svc_data + 11, 8); @@ -1616,8 +1727,7 @@ static int private_node_id_adv(struct bt_mesh_subnet *sub) } #endif /* CONFIG_BLE_MESH_PRB_SRV */ -#if (CONFIG_BLE_MESH_PRB_SRV || \ - CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) +#if (CONFIG_BLE_MESH_PRB_SRV || CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) static int private_net_id_adv(struct bt_mesh_subnet *sub) { struct bt_mesh_adv_data proxy_sd = {0}; @@ -1625,6 +1735,8 @@ static int private_net_id_adv(struct bt_mesh_subnet *sub) uint8_t tmp[16] = {0}; int err = 0; + BT_DBG("PrivateNetIDAdv, NetIdx 0x%04x", sub->net_idx); + proxy_svc_data[2] = BLE_MESH_PROXY_ADV_PRIVATE_NET_ID; /* TODO: @@ -1663,11 +1775,12 @@ static int private_net_id_adv(struct bt_mesh_subnet *sub) return 0; } -#endif /* (CONFIG_BLE_MESH_PRB_SRV || \ - CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) */ +#endif /* (CONFIG_BLE_MESH_PRB_SRV || CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX) */ static bool advertise_subnet(struct bt_mesh_subnet *sub) { + BT_DBG("AdvSubnet, NetIdx 0x%04x", sub->net_idx); + if (sub->net_idx == BLE_MESH_KEY_UNUSED) { return false; } @@ -1677,7 +1790,7 @@ static bool advertise_subnet(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_PRB_SRV || sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING || bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ ); } @@ -1686,10 +1799,13 @@ static struct bt_mesh_subnet *next_sub(void) struct bt_mesh_subnet *sub = NULL; int i; + BT_DBG("NextSub"); + for (i = next_idx; i < ARRAY_SIZE(bt_mesh.sub); i++) { sub = &bt_mesh.sub[i]; if (advertise_subnet(sub)) { next_idx = (i + 1) % ARRAY_SIZE(bt_mesh.sub); + BT_DBG("NextIdx %d", next_idx); return sub; } } @@ -1701,6 +1817,7 @@ static struct bt_mesh_subnet *next_sub(void) sub = &bt_mesh.sub[i]; if (advertise_subnet(sub)) { next_idx = (i + 1) % ARRAY_SIZE(bt_mesh.sub); + BT_DBG("NextIdx %d", next_idx); return sub; } } @@ -1720,6 +1837,8 @@ static int sub_count(void) } } + BT_DBG("SubCount %ld", count); + return count; } @@ -1729,6 +1848,8 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) int subnet_count = 0; uint32_t active = 0U; + BT_DBG("GattProxyAdvertise"); + if (conn_count == BLE_MESH_MAX_CONN) { BT_WARN("Connectable advertising deferred (max connections %d)", conn_count); return remaining; @@ -1739,6 +1860,8 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) return remaining; } + BT_DBG("NetIdx 0x%04x NodeID %u", sub->net_idx, sub->node_id); + if (sub->node_id == BLE_MESH_NODE_IDENTITY_RUNNING) { active = k_uptime_get_32() - sub->node_id_start; @@ -1751,6 +1874,7 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) BT_DBG("Node ID stopped"); } } + #if CONFIG_BLE_MESH_PRB_SRV else if (sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_RUNNING) { active = k_uptime_get_32() - sub->node_id_start; @@ -1769,7 +1893,7 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) if (sub->node_id == BLE_MESH_NODE_IDENTITY_STOPPED #if CONFIG_BLE_MESH_PRB_SRV && sub->private_node_id == BLE_MESH_PRIVATE_NODE_IDENTITY_STOPPED -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ ) { /* advertising node identity forever */ if (bt_mesh_gatt_proxy_get() == BLE_MESH_GATT_PROXY_ENABLED) { @@ -1779,11 +1903,10 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) else if (bt_mesh_private_gatt_proxy_state_get() == BLE_MESH_PRIVATE_GATT_PROXY_ENABLED) { private_net_id_adv(sub); } -#endif +#endif /* CONFIG_BLE_MESH_PRB_SRV */ } subnet_count = sub_count(); - BT_DBG("sub_count %u", subnet_count); if (subnet_count > 1) { int32_t max_timeout = 0; @@ -1796,16 +1919,18 @@ static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) max_timeout = NODE_ID_TIMEOUT / MAX(subnet_count, 6); max_timeout = MAX(max_timeout, K_SECONDS(1)); + BT_DBG("Remaining %d MaxTimeout %d", remaining, max_timeout); + if (remaining > max_timeout || remaining < 0) { remaining = max_timeout; } } - BT_DBG("Advertising %d ms for net_idx 0x%04x", remaining, sub->net_idx); + BT_DBG("Remaining %d NetIdx 0x%04x", remaining, sub->net_idx); return remaining; } -#endif /* GATT_PROXY */ +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT static size_t gatt_prov_adv_create(struct bt_mesh_adv_data prov_sd[2]) @@ -1815,6 +1940,8 @@ static size_t gatt_prov_adv_create(struct bt_mesh_adv_data prov_sd[2]) size_t prov_sd_len = 0U; size_t sd_space = 31U; + BT_DBG("GattProvAdvCreate"); + if (bt_mesh_prov_get() == NULL) { BT_ERR("No provisioning context provided"); return 0; @@ -1865,41 +1992,51 @@ static int32_t solic_adv_private_net_id(void) struct bt_mesh_subnet *sub = NULL; int32_t remaining = 0; + BT_DBG("SolicAdvPrivateNetID"); + remaining = bt_mesh_proxy_server_get_solic_adv_remaining(); if (remaining == 0) { + BT_DBG("RemainingZero"); return 0; } net_idx = bt_mesh_proxy_server_get_solic_adv_net_idx(); if (net_idx == BLE_MESH_KEY_UNUSED) { + BT_DBG("UnusedNetIdx"); return 0; } sub = bt_mesh_subnet_get(net_idx); if (sub == NULL) { + BT_DBG("NoSub"); return 0; } private_net_id_adv(sub); + return remaining; } #endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ int32_t bt_mesh_proxy_server_adv_start(void) { - BT_DBG("proxy server start"); + BT_DBG("ProxyServerAdvStart"); if (gatt_svc == MESH_GATT_NONE) { + BT_DBG("GattSvcNone"); return K_FOREVER; } #if CONFIG_BLE_MESH_USE_BLE_50 if (proxy_adv_inst == BLE_MESH_ADV_INS_UNUSED) { + BT_DBG("ProxyAdvInstUnused"); return K_FOREVER; } -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_PB_GATT + BT_DBG("ProvFastAdv %u", prov_fast_adv); + if (prov_fast_adv) { prov_start_time = k_uptime_get_32(); } @@ -1909,6 +2046,8 @@ int32_t bt_mesh_proxy_server_adv_start(void) struct bt_mesh_adv_data prov_sd[2]; size_t prov_sd_len; + BT_DBG("NotProvisioned"); + if (k_uptime_get_32() - prov_start_time < K_SECONDS(60)) { param = &fast_adv_param; } else { @@ -1924,7 +2063,6 @@ int32_t bt_mesh_proxy_server_adv_start(void) if (bt_le_adv_start(param, prov_ad, ARRAY_SIZE(prov_ad), prov_sd, prov_sd_len) == 0) { #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ - bt_mesh_proxy_server_adv_flag_set(true); /* Advertise 60 seconds using fast interval */ @@ -1934,7 +2072,7 @@ int32_t bt_mesh_proxy_server_adv_start(void) } } } -#endif /* PB_GATT */ +#endif /* CONFIG_BLE_MESH_PB_GATT */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER if (bt_mesh_is_provisioned()) { @@ -1963,6 +2101,8 @@ int bt_mesh_proxy_server_adv_stop(void) { int err = 0; + BT_DBG("ProxyServerAdvStop, Enabled %u", proxy_adv_enabled); + if (!proxy_adv_enabled) { return -EALREADY; } @@ -1974,15 +2114,16 @@ int bt_mesh_proxy_server_adv_stop(void) } err = bt_le_ext_adv_stop(proxy_adv_inst); -#else +#else /* CONFIG_BLE_MESH_USE_BLE_50 */ err = bt_le_adv_stop(); -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ if (err) { BT_ERR("Failed to stop advertising (err %d)", err); return -EINVAL; } bt_mesh_proxy_server_adv_flag_set(false); + return 0; } @@ -1995,21 +2136,23 @@ int bt_mesh_proxy_server_init(void) { int i; + BT_DBG("ProxyServerInit"); + #if CONFIG_BLE_MESH_USE_BLE_50 #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV proxy_adv_inst = CONFIG_BLE_MESH_PROXY_ADV_INST_ID; #else /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ proxy_adv_inst = CONFIG_BLE_MESH_ADV_INST_ID; -#endif -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #if CONFIG_BLE_MESH_GATT_PROXY_SERVER bt_mesh_gatts_service_register(&proxy_svc); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT bt_mesh_gatts_service_register(&prov_svc); -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ /* Initialize the client receive buffers */ for (i = 0; i < ARRAY_SIZE(clients); i++) { @@ -2017,9 +2160,10 @@ int bt_mesh_proxy_server_init(void) client->buf.size = BLE_MESH_PROXY_BUF_SIZE; client->buf.__buf = client_buf_data + (i * BLE_MESH_PROXY_BUF_SIZE); -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER k_delayed_work_init(&client->send_beacons, proxy_send_beacons); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ k_delayed_work_init(&client->sar_timer, proxy_sar_timeout); } @@ -2028,11 +2172,12 @@ int bt_mesh_proxy_server_init(void) BT_ERR("Failed to create a random update timer"); return -EIO; } -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV */ bt_mesh_gatts_conn_cb_register(&conn_callbacks); strncpy(device_name, "ESP-BLE-MESH", DEVICE_NAME_SIZE); + return bt_mesh_gatts_set_local_device_name(device_name); } @@ -2041,9 +2186,11 @@ int bt_mesh_proxy_server_deinit(void) { int i; + BT_DBG("ProxyServerDeinit"); + #if CONFIG_BLE_MESH_USE_BLE_50 proxy_adv_inst = BLE_MESH_ADV_INS_UNUSED; -#endif +#endif /* CONFIG_BLE_MESH_USE_BLE_50 */ bt_mesh_proxy_server_adv_flag_set(false); gatt_svc = MESH_GATT_NONE; @@ -2051,24 +2198,26 @@ int bt_mesh_proxy_server_deinit(void) #if CONFIG_BLE_MESH_GATT_PROXY_SERVER bt_mesh_gatts_service_deregister(&proxy_svc); next_idx = 0; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ #if CONFIG_BLE_MESH_PB_GATT bt_mesh_gatts_service_deregister(&prov_svc); -#endif +#endif /* CONFIG_BLE_MESH_PB_GATT */ for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; -#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER) + +#if CONFIG_BLE_MESH_GATT_PROXY_SERVER k_delayed_work_free(&client->send_beacons); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ k_delayed_work_free(&client->sar_timer); + memset(client, 0, sizeof(struct bt_mesh_proxy_client)); } #if CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV k_delayed_work_free(&rand_upd_timer); -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER && CONFIG_BLE_MESH_PRB_SRV */ memset(client_buf_data, 0, sizeof(client_buf_data)); memset(device_name, 0, sizeof(device_name)); diff --git a/components/bt/esp_ble_mesh/core/proxy_server.h b/components/bt/esp_ble_mesh/core/proxy_server.h index fc4041f877..d16d0d390f 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.h +++ b/components/bt/esp_ble_mesh/core/proxy_server.h @@ -58,7 +58,7 @@ struct bt_mesh_proxy_client { #if CONFIG_BLE_MESH_PROXY_PRIVACY uint8_t proxy_privacy; -#endif +#endif /* CONFIG_BLE_MESH_PROXY_PRIVACY */ #endif /* CONFIG_BLE_MESH_GATT_PROXY_SERVER */ struct k_delayed_work sar_timer; diff --git a/components/bt/esp_ble_mesh/core/rpl.c b/components/bt/esp_ble_mesh/core/rpl.c index 4e3e4c91cb..43f4a4afda 100644 --- a/components/bt/esp_ble_mesh/core/rpl.c +++ b/components/bt/esp_ble_mesh/core/rpl.c @@ -17,6 +17,9 @@ void bt_mesh_update_rpl(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx) { + BT_DBG("UpdateRPL, Src 0x%04x Seq 0x%06x OldIV %u", + rx->ctx.addr, rx->seq, rx->old_iv); + rpl->src = rx->ctx.addr; rpl->seq = rx->seq; rpl->old_iv = rx->old_iv; @@ -33,9 +36,16 @@ void bt_mesh_update_rpl(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx) */ static bool rpl_check_and_store(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) { + BT_DBG("%s, Src 0x%04x Seq %lu OldIV %u", + match ? "RPLOnlyCheck" : "RPLCheckAndStore", + rx->ctx.addr, rx->seq, rx->old_iv); + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + BT_DBG("RPL%u, Src 0x%04x Seq %lu OldIV %u", + i, rpl->src, rpl->seq, rpl->old_iv); + /* Empty slot */ if (rpl->src == BLE_MESH_ADDR_UNASSIGNED) { if (match) { @@ -50,6 +60,7 @@ static bool rpl_check_and_store(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl ** /* Existing slot for given address */ if (rpl->src == rx->ctx.addr) { if (rx->old_iv && !rpl->old_iv) { + BT_DBG("DueToOldIV"); return true; } @@ -66,25 +77,30 @@ static bool rpl_check_and_store(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl ** #if CONFIG_BLE_MESH_NOT_RELAY_REPLAY_MSG rx->replay_msg = 1; -#endif +#endif /* CONFIG_BLE_MESH_NOT_RELAY_REPLAY_MSG */ + BT_DBG("DueToSeq"); return true; } } - BT_ERR("RPL is full!"); + BT_ERR("RPLFull"); return true; } bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match) { + BT_DBG("RPLCheck"); + /* Don't bother checking messages from ourselves */ if (rx->net_if == BLE_MESH_NET_IF_LOCAL) { + BT_DBG("LocalNetIf"); return false; } /* The RPL is used only for the local node */ if (!rx->local_match) { + BT_DBG("LocalNotMatch"); return false; } @@ -96,9 +112,14 @@ void bt_mesh_rpl_update(void) /* Discard "old old" IV Index entries from RPL and flag * any other ones (which are valid) as old. */ + BT_DBG("RPLUpdate"); + for (size_t i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + BT_DBG("RPL%u, Src 0x%04x Seq %lu OldIV %u", + i, rpl->src, rpl->seq, rpl->old_iv); + if (rpl->src) { if (rpl->old_iv) { (void)memset(rpl, 0, sizeof(*rpl)); @@ -115,6 +136,8 @@ void bt_mesh_rpl_update(void) void bt_mesh_rpl_reset_single(uint16_t src, bool erase) { + BT_DBG("RPLResetSingle, Src 0x%04x Erase %u", src, erase); + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { return; } @@ -132,6 +155,8 @@ void bt_mesh_rpl_reset_single(uint16_t src, bool erase) void bt_mesh_rpl_reset(bool erase) { + BT_DBG("RPLReset, Erase %u", erase); + (void)memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl)); if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS) && erase) { diff --git a/components/bt/esp_ble_mesh/core/scan.c b/components/bt/esp_ble_mesh/core/scan.c index c298f18456..a7a685d099 100644 --- a/components/bt/esp_ble_mesh/core/scan.c +++ b/components/bt/esp_ble_mesh/core/scan.c @@ -29,7 +29,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ /* Scan Window and Interval are equal for continuous scanning */ #define SCAN_INTERVAL 0x20 @@ -44,14 +44,14 @@ static struct bt_mesh_scan_param scan_param = { #if CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN .type = BLE_MESH_SCAN_ACTIVE, -#else +#else /* CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ .type = BLE_MESH_SCAN_PASSIVE, -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN .filter_dup = BLE_MESH_SCAN_FILTER_DUP_ENABLE, -#else +#else /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ .filter_dup = BLE_MESH_SCAN_FILTER_DUP_DISABLE, -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ .interval = SCAN_INTERVAL, .window = SCAN_WINDOW, .scan_fil_policy = BLE_MESH_SP_ADV_ALL, @@ -76,6 +76,11 @@ int bt_mesh_unprov_dev_fifo_dequeue(uint8_t *uuid, uint8_t *addr) { uint8_t idx = 0; + BT_DBG("UnprovDevFifoDequeue, PairNum %u StartIdx %u EndIdx %u", + unprov_dev_info_fifo.pair_num, + unprov_dev_info_fifo.start_idx, + unprov_dev_info_fifo.end_idx); + if (unprov_dev_info_fifo.pair_num == 0) { return 0; } @@ -100,9 +105,11 @@ int bt_mesh_unprov_dev_fifo_dequeue(uint8_t *uuid, uint8_t *addr) int bt_mesh_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], uint8_t *adv_type, uint8_t query_type) { + uint8_t pair_num = unprov_dev_info_fifo.pair_num; uint8_t idx = 0; uint8_t cnt = 0; - uint8_t pair_num = unprov_dev_info_fifo.pair_num; + + BT_DBG("UnprovDevInfoQuery, QueryType 0x%02x PairNum %u", query_type, pair_num); if (uuid == NULL && addr == NULL) { BT_WARN("No available information to query"); @@ -111,6 +118,9 @@ int bt_mesh_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], while (cnt < pair_num) { idx = (cnt + unprov_dev_info_fifo.start_idx) % BLE_MESH_STORE_UNPROV_INFO_MAX_NUM; + + BT_DBG("Count %u StartIdx %u Idx %u", cnt, unprov_dev_info_fifo.start_idx, idx); + if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_UUID) { if (!memcmp(unprov_dev_info_fifo.info[idx].addr, addr, 6)) { if (query_type & BLE_MESH_STORE_UNPROV_INFO_QUERY_TYPE_EXISTS) { @@ -132,21 +142,25 @@ int bt_mesh_unprov_dev_info_query(uint8_t uuid[16], uint8_t addr[6], break; } } + cnt++; } if (cnt == pair_num) { + BT_DBG("Count == PairNum"); return -1; } return 0; - } int bt_mesh_unprov_dev_fifo_enqueue(uint8_t uuid[16], const uint8_t addr[6], uint8_t adv_type) { uint8_t idx = 0; + BT_DBG("UnprovDevFifoEnqueue, EndIdx %u PairNum %u", + unprov_dev_info_fifo.end_idx, unprov_dev_info_fifo.pair_num); + if (uuid == NULL || addr == NULL) { BT_ERR("Invalid argument %s", __func__); return -EINVAL; @@ -170,6 +184,9 @@ int bt_mesh_unprov_dev_fifo_enqueue(uint8_t uuid[16], const uint8_t addr[6], uin idx = (idx + 1) % BLE_MESH_STORE_UNPROV_INFO_MAX_NUM; unprov_dev_info_fifo.end_idx = idx; unprov_dev_info_fifo.pair_num++; + + BT_DBG("EndIdx %u PairNum %u", unprov_dev_info_fifo.end_idx, unprov_dev_info_fifo.pair_num); + return 0; } @@ -180,19 +197,22 @@ const bt_mesh_addr_t *bt_mesh_get_unprov_dev_addr(void) uint8_t bt_mesh_get_adv_type(void) { + BT_DBG("CurrentAdvType %u", current_adv_type); + return current_adv_type; } - #endif /* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX || \ - (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) static bool adv_flags_valid(struct net_buf_simple *buf) { uint8_t flags = 0U; + BT_DBG("IsAdvFlagsValid"); + if (buf->len != 1U) { BT_DBG("Unexpected adv flags length %d", buf->len); return false; @@ -200,7 +220,7 @@ static bool adv_flags_valid(struct net_buf_simple *buf) flags = net_buf_simple_pull_u8(buf); - BT_DBG("Received adv pkt with flags: 0x%02x", flags); + BT_DBG("Flags 0x%02x", flags); /* Flags context will not be checked currently */ ARG_UNUSED(flags); @@ -210,6 +230,8 @@ static bool adv_flags_valid(struct net_buf_simple *buf) static bool adv_service_uuid_valid(struct net_buf_simple *buf, uint16_t *uuid) { + BT_DBG("IsAdvServiceUUIDValid"); + if (buf->len != 2U) { BT_DBG("Length not match mesh service uuid"); return false; @@ -217,40 +239,42 @@ static bool adv_service_uuid_valid(struct net_buf_simple *buf, uint16_t *uuid) *uuid = net_buf_simple_pull_le16(buf); - BT_DBG("Received adv pkt with service UUID: %d", *uuid); + BT_DBG("UUID 0x%04x", *uuid); if (*uuid != BLE_MESH_UUID_MESH_PROV_VAL && *uuid != BLE_MESH_UUID_MESH_PROXY_VAL && *uuid != BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL) { + BT_DBG("UnexpectMeshUUID"); return false; } - /** - * @brief In remote provisioning. - * A Node could handle the unprovisioned beacon. + /* In remote provisioning, Node could handle unprovisioned device beacon. * CASE: MESH/SR/RPR/SCN/BV-01-C - */ + */ #if CONFIG_BLE_MESH_RPR_SRV if (*uuid == BLE_MESH_UUID_MESH_PROV_VAL && !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT)) { + BT_DBG("IgnorePBGattUUID"); return false; } -#else +#else /* CONFIG_BLE_MESH_RPR_SRV */ if (*uuid == BLE_MESH_UUID_MESH_PROV_VAL && (bt_mesh_is_provisioner_en() == false || !IS_ENABLED(CONFIG_BLE_MESH_PB_GATT))) { + BT_DBG("IgnorePBGattUUID"); return false; } -#endif - +#endif /* CONFIG_BLE_MESH_RPR_SRV */ if (*uuid == BLE_MESH_UUID_MESH_PROXY_VAL && !IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_CLIENT)) { + BT_DBG("IgnoreProxyUUID"); return false; } if (*uuid == BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL && !IS_ENABLED(CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX)) { + BT_DBG("IgnoreProxySolicUUID"); return false; } @@ -263,6 +287,8 @@ static void handle_adv_service_data(struct net_buf_simple *buf, { uint16_t type = 0U; + BT_DBG("HandleAdvServiceData, UUID 0x%04x", uuid); + if (!buf || !addr) { BT_ERR("%s, Invalid parameter", __func__); return; @@ -270,7 +296,7 @@ static void handle_adv_service_data(struct net_buf_simple *buf, type = net_buf_simple_pull_le16(buf); if (type != uuid) { - BT_DBG("Invalid Mesh Service Data UUID 0x%04x", type); + BT_DBG("UnexpectMeshUUID 0x%04x", type); return; } @@ -292,8 +318,13 @@ static void handle_adv_service_data(struct net_buf_simple *buf, #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_is_provisioned()) { - const bt_mesh_addr_t *addr = bt_mesh_get_unprov_dev_addr(); + const bt_mesh_addr_t *addr = NULL; + + addr = bt_mesh_get_unprov_dev_addr(); + assert(addr); + bt_mesh_unprov_dev_fifo_enqueue(buf->data, addr->val, bt_mesh_get_adv_type()); + bt_mesh_rpr_srv_unprov_beacon_recv(buf, bt_mesh_get_adv_type(), addr, rssi); } #endif /* CONFIG_BLE_MESH_RPR_SRV */ @@ -316,7 +347,8 @@ static void handle_adv_service_data(struct net_buf_simple *buf, BT_DBG("Start to handle Mesh Proxy Service Data"); bt_mesh_proxy_client_gatt_adv_recv(buf, addr, rssi); break; -#endif +#endif /* CONFIG_BLE_MESH_GATT_PROXY_CLIENT */ + #if CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX case BLE_MESH_UUID_MESH_PROXY_SOLIC_VAL: if (buf->len != (1 + BLE_MESH_NET_HDR_LEN + 8)) { @@ -327,7 +359,8 @@ static void handle_adv_service_data(struct net_buf_simple *buf, BT_DBG("Start to handle Mesh Proxy Solic Service Data"); bt_mesh_proxy_server_solic_recv(buf, addr, rssi); break; -#endif +#endif /* CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX */ + default: break; } @@ -342,6 +375,8 @@ static bool ble_scan_en; int bt_mesh_start_ble_scan(struct bt_mesh_ble_scan_param *param) { + BT_DBG("StartBLEScan"); + if (ble_scan_en == true) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -354,6 +389,8 @@ int bt_mesh_start_ble_scan(struct bt_mesh_ble_scan_param *param) int bt_mesh_stop_ble_scan(void) { + BT_DBG("StopBLEScan"); + if (ble_scan_en == false) { BT_WARN("%s, Already", __func__); return -EALREADY; @@ -366,6 +403,8 @@ int bt_mesh_stop_ble_scan(void) bool bt_mesh_ble_scan_state_get(void) { + BT_DBG("BLEScanEn %u", ble_scan_en); + return ble_scan_en; } @@ -375,6 +414,7 @@ static void inline callback_ble_adv_pkt(const bt_mesh_addr_t *addr, { #if !CONFIG_BLE_MESH_USE_BLE_50 bt_mesh_ble_adv_report_t adv_rpt = {0}; + if (ble_scan_en) { memcpy(adv_rpt.addr, addr->val, BD_ADDR_LEN); adv_rpt.addr_type = addr->type; @@ -382,9 +422,12 @@ static void inline callback_ble_adv_pkt(const bt_mesh_addr_t *addr, adv_rpt.length = length; adv_rpt.data = length ? data : NULL; adv_rpt.rssi = rssi; + + BT_DBG("CallbackBLEAdvPkt, AdvType 0x%02x Len %u", adv_type, length); + bt_mesh_ble_scan_cb_evt_to_btc(&adv_rpt); } -#endif +#endif /* !CONFIG_BLE_MESH_USE_BLE_50 */ } #endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ @@ -395,6 +438,8 @@ static bool rpr_ext_scan_handle_adv_pkt(const bt_mesh_addr_t *addr, struct net_buf_simple buf = {0}; bool rpr_adv = false; + BT_DBG("RPRExtScanHandleAdvPkt, Provisioned %u", bt_mesh_is_provisioned()); + if (bt_mesh_is_provisioned() == false) { return false; } @@ -408,19 +453,19 @@ static bool rpr_ext_scan_handle_adv_pkt(const bt_mesh_addr_t *addr, static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) { - struct net_buf_simple_state buf_state = {0}; struct net_buf_simple *buf = &adv_rpt->adv_data; + struct net_buf_simple_state buf_state = {0}; #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ - CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX || \ - (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) uint16_t uuid = 0U; #endif #if (CONFIG_BLE_MESH_RPR_SRV || CONFIG_BLE_MESH_SUPPORT_BLE_SCAN) uint8_t *adv_data = buf->data; uint16_t adv_len = buf->len; -#endif +#endif /* (CONFIG_BLE_MESH_RPR_SRV || CONFIG_BLE_MESH_SUPPORT_BLE_SCAN) */ net_buf_simple_save(buf, &buf_state); @@ -429,40 +474,41 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) adv_rpt->adv_type != 0 && #endif adv_rpt->adv_type != BLE_MESH_ADV_NONCONN_IND && - adv_rpt->adv_type != BLE_MESH_ADV_IND + adv_rpt->adv_type != BLE_MESH_ADV_IND #if CONFIG_BLE_MESH_EXT_ADV - && adv_rpt->adv_type != BLE_MESH_EXT_ADV_NONCONN_IND + && adv_rpt->adv_type != BLE_MESH_EXT_ADV_NONCONN_IND #endif #if CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN - && adv_rpt->adv_type != BLE_MESH_ADV_SCAN_RSP -#endif - ) { + && adv_rpt->adv_type != BLE_MESH_ADV_SCAN_RSP +#endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ + ) { #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } - BT_DBG("scan, len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("MeshScan"); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); #if (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) unprov_dev_addr = &adv_rpt->addr; current_adv_type = adv_rpt->adv_type; -#endif +#endif /* (CONFIG_BLE_MESH_PROVISIONER || CONFIG_BLE_MESH_RPR_SRV) */ #if CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN if (adv_rpt->adv_type == BLE_MESH_ADV_SCAN_RSP) { - /** - * scan response is only visible for remote provisioning extend scan. - */ + /* scan response is only visible for remote provisioning extend scan */ if (rpr_ext_scan_handle_adv_pkt(&adv_rpt->addr, adv_data, adv_len)) { return; } #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); } #endif /* CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_RPR_SRV_ACTIVE_SCAN */ @@ -472,20 +518,24 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) uint8_t len, type; len = net_buf_simple_pull_u8(buf); + /* Check for early termination */ if (len == 0U) { #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } if (len > buf->len) { - BT_DBG("AD malformed"); + BT_DBG("MalformedAD"); + #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } @@ -496,13 +546,15 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) buf->len = len - 1; - if ((type == BLE_MESH_DATA_MESH_PROV || type == BLE_MESH_DATA_MESH_MESSAGE || - type == BLE_MESH_DATA_MESH_BEACON) && (adv_rpt->adv_type != BLE_MESH_ADV_NONCONN_IND + if ((type == BLE_MESH_DATA_MESH_PROV || + type == BLE_MESH_DATA_MESH_MESSAGE || + type == BLE_MESH_DATA_MESH_BEACON) && + (adv_rpt->adv_type != BLE_MESH_ADV_NONCONN_IND #if CONFIG_BLE_MESH_EXT_ADV - && adv_rpt->adv_type != BLE_MESH_EXT_ADV_NONCONN_IND + && adv_rpt->adv_type != BLE_MESH_EXT_ADV_NONCONN_IND #endif )) { - BT_DBG("Ignore mesh packet (type 0x%02x) with adv_type 0x%02x", type, adv_rpt->adv_type); + BT_DBG("IgnorePkt, Type 0x%02x AdvType 0x%02x", type, adv_rpt->adv_type); return; } @@ -526,36 +578,44 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) #endif /* CONFIG_BLE_MESH_EXT_ADV */ bt_mesh_generic_net_recv(buf, &rx, BLE_MESH_NET_IF_ADV); break; + #if CONFIG_BLE_MESH_PB_ADV case BLE_MESH_DATA_MESH_PROV: if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_node()) { bt_mesh_pb_adv_recv(buf); } + if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en()) { bt_mesh_provisioner_pb_adv_recv(buf); } break; #endif /* CONFIG_BLE_MESH_PB_ADV */ + case BLE_MESH_DATA_MESH_BEACON: bt_mesh_beacon_recv(buf, adv_rpt->rssi); break; + #if (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX || \ - (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) case BLE_MESH_DATA_FLAGS: if (!adv_flags_valid(buf)) { BT_DBG("Adv Flags mismatch, ignore this adv pkt"); + #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } break; + case BLE_MESH_DATA_UUID16_ALL: if (!adv_service_uuid_valid(buf, &uuid)) { BT_DBG("Adv Service UUID mismatch, ignore this adv pkt"); + #if CONFIG_BLE_MESH_RPR_SRV if (rpr_ext_scan_handle_adv_pkt(&adv_rpt->addr, adv_data, adv_len)) { /* If handled as extended scan report successfully, then not @@ -563,18 +623,25 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) */ return; } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } break; + case BLE_MESH_DATA_SVC_DATA16: handle_adv_service_data(buf, &adv_rpt->addr, uuid, adv_rpt->rssi); break; -#endif +#endif /* (CONFIG_BLE_MESH_PROVISIONER && CONFIG_BLE_MESH_PB_GATT) || \ + CONFIG_BLE_MESH_GATT_PROXY_CLIENT || \ + CONFIG_BLE_MESH_PROXY_SOLIC_PDU_RX || \ + (CONFIG_BLE_MESH_RPR_SRV && CONFIG_BLE_MESH_PB_GATT) */ + default: #if CONFIG_BLE_MESH_RPR_SRV if (rpr_ext_scan_handle_adv_pkt(&adv_rpt->addr, adv_data, adv_len)) { @@ -583,10 +650,12 @@ static void bt_mesh_scan_cb(struct bt_mesh_adv_report *adv_rpt) */ return; } -#endif +#endif /* CONFIG_BLE_MESH_RPR_SRV */ + #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN callback_ble_adv_pkt(&adv_rpt->addr, adv_rpt->adv_type, adv_data, adv_len, adv_rpt->rssi); -#endif +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_SCAN */ + net_buf_simple_restore(buf, &buf_state); return; } @@ -600,9 +669,11 @@ int bt_mesh_scan_enable(void) { int err = 0; + BT_DBG("ScanEnable"); + err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb); if (err && err != -EALREADY) { - BT_ERR("starting scan failed (err %d)", err); + BT_ERR("StartScanFailed, Err %d", err); return err; } @@ -613,9 +684,11 @@ int bt_mesh_scan_disable(void) { int err = 0; + BT_DBG("ScanDisable"); + err = bt_le_scan_stop(); if (err && err != -EALREADY) { - BT_ERR("stopping scan failed (err %d)", err); + BT_ERR("StopScanFailed, Err %d", err); return err; } @@ -629,9 +702,13 @@ int bt_mesh_scan_param_update(struct bt_mesh_scan_param *param) if (param == NULL || param->interval == 0 || param->interval < param->window) { + BT_ERR("InvalidScanParam"); return -EINVAL; } + BT_DBG("ScanParamUpdate, Type %u Interval %u Window %u", + param->type, param->interval, param->window); + scan_param.interval = param->interval; scan_param.window = param->window; @@ -641,24 +718,22 @@ int bt_mesh_scan_param_update(struct bt_mesh_scan_param *param) BT_INFO("New scan parameters will take effect after scan starts"); return 0; } - BT_ERR("Failed to stop scan (err %d)", err); + + BT_ERR("StopScanFailed, Err %d", err); return err; } - /** - * Since the user only needs to set the scan interval - * and scan window parameters, only the interval and - * window parameters in the `param` are correct. + /* Since the user only needs to set the scan interval and scan window, + * only the interval and window parameters in the `param` are correct. * - * For the aforementioned reason, when updating the scan - * parameters, the other parameters also need to be set - * correctly, and these other parameters are saved in the - * `scan_param`. Therefore, `scan_param` must be used instead - * of `param` here. + * For the aforementioned reason, when updating the scan parameters, + * the other parameters also need to be set correctly, and these other + * parameters are saved in the `scan_param`. Therefore, `scan_param` + * must be used instead of `param` here. */ err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb); if (err && err != -EALREADY) { - BT_ERR("Failed to start scan (err %d)", err); + BT_ERR("StartScanFailed, Err %d", err); return err; } @@ -668,23 +743,24 @@ int bt_mesh_scan_param_update(struct bt_mesh_scan_param *param) #if CONFIG_BLE_MESH_TEST_USE_WHITE_LIST int bt_mesh_scan_with_wl_enable(void) { - int err = 0; - struct bt_mesh_scan_param scan_param = { .type = BLE_MESH_SCAN_PASSIVE, #if CONFIG_BLE_MESH_USE_DUPLICATE_SCAN .filter_dup = BLE_MESH_SCAN_FILTER_DUP_ENABLE, -#else +#else /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ .filter_dup = BLE_MESH_SCAN_FILTER_DUP_DISABLE, -#endif +#endif /* CONFIG_BLE_MESH_USE_DUPLICATE_SCAN */ .interval = SCAN_INTERVAL, .window = SCAN_WINDOW, .scan_fil_policy = BLE_MESH_SP_ADV_WL, }; + int err = 0; + + BT_DBG("ScanWithWLEnable"); err = bt_le_scan_start(&scan_param, bt_mesh_scan_cb); if (err && err != -EALREADY) { - BT_ERR("starting scan failed (err %d)", err); + BT_ERR("StartScanFailed, Err %d", err); return err; } diff --git a/components/bt/esp_ble_mesh/core/storage/settings.c b/components/bt/esp_ble_mesh/core/storage/settings.c index 40cf117f2e..61bc34d8db 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings.c +++ b/components/bt/esp_ble_mesh/core/storage/settings.c @@ -24,7 +24,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ /* BLE Mesh NVS Key and corresponding data struct. * Note: The length of nvs key must be <= 15. @@ -207,6 +207,8 @@ static int role_set(const char *name) bool exist = false; int err = 0; + BT_DBG("RoleSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)bt_mesh.flags, sizeof(bt_mesh.flags), &exist); if (err) { BT_ERR("Failed to load mesh device role"); @@ -219,9 +221,9 @@ static int role_set(const char *name) !IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER)) { bt_mesh_atomic_set_bit(bt_mesh.flags, BLE_MESH_NODE); } -#else +#else /* CONFIG_BLE_MESH_SETTINGS_BACKWARD_COMPATIBILITY */ return 0; -#endif +#endif /* CONFIG_BLE_MESH_SETTINGS_BACKWARD_COMPATIBILITY */ } return 0; @@ -233,6 +235,8 @@ static int net_set(const char *name) bool exist = false; int err = 0; + BT_DBG("NetSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&net, sizeof(net), &exist); if (err) { BT_ERR("Failed to load node net info"); @@ -259,6 +263,8 @@ static int dkca_set(const char *name) bool exist = false; int err = 0; + BT_DBG("DkcaSet, Name %s", name); + err = bt_mesh_load_core_settings(name, bt_mesh.dev_key_ca, sizeof(bt_mesh.dev_key_ca), &exist); if (err) { BT_ERR("Failed to load DevKey Candidate"); @@ -280,6 +286,8 @@ static int iv_set(const char *name) bool exist = false; int err = 0; + BT_DBG("IVSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&iv, sizeof(iv), &exist); if (err) { BT_ERR("Failed to load iv_index"); @@ -297,7 +305,7 @@ static int iv_set(const char *name) bt_mesh.ivu_duration = iv.iv_duration; BT_INFO("Restored IV Index 0x%08x (IV Update Flag %u) duration %u hours", - iv.iv_index, iv.iv_update, iv.iv_duration); + iv.iv_index, iv.iv_update, iv.iv_duration); return 0; } @@ -308,6 +316,8 @@ static int seq_set(const char *name) bool exist = false; int err = 0; + BT_DBG("SeqSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&seq, sizeof(seq), &exist); if (err) { BT_ERR("Failed to load sequence number"); @@ -329,7 +339,7 @@ static int seq_set(const char *name) bt_mesh.seq += (CONFIG_BLE_MESH_SEQ_STORE_RATE - (bt_mesh.seq % CONFIG_BLE_MESH_SEQ_STORE_RATE)); bt_mesh.seq--; -#endif +#endif /* CONFIG_BLE_MESH_SEQ_STORE_RATE > 0 */ BT_INFO("Restored Sequence Number 0x%06x", bt_mesh.seq); @@ -340,6 +350,8 @@ static struct bt_mesh_rpl *rpl_find(uint16_t src) { int i; + BT_DBG("RPLFind, Src 0x%04x", src); + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { if (bt_mesh.rpl[i].src == src) { return &bt_mesh.rpl[i]; @@ -353,6 +365,8 @@ static struct bt_mesh_rpl *rpl_alloc(uint16_t src) { int i; + BT_DBG("RPLAlloc, Src 0x%04x", src); + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { if (bt_mesh.rpl[i].src == BLE_MESH_ADDR_UNASSIGNED) { bt_mesh.rpl[i].src = src; @@ -374,6 +388,8 @@ static int rpl_set(const char *name) int err = 0; int i; + BT_DBG("RPLSet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -427,6 +443,8 @@ static struct bt_mesh_subnet *subnet_exist(uint16_t net_idx) { int i; + BT_DBG("SubnetExist, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { if (bt_mesh.sub[i].net_idx == net_idx) { return &bt_mesh.sub[i]; @@ -440,6 +458,8 @@ static struct bt_mesh_subnet *subnet_alloc(uint16_t net_idx) { int i; + BT_DBG("SubnetAlloc, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { if (bt_mesh.sub[i].net_idx == BLE_MESH_KEY_UNUSED) { bt_mesh.sub[i].net_idx = net_idx; @@ -454,6 +474,8 @@ static struct bt_mesh_app_key *appkey_exist(uint16_t app_idx) { int i; + BT_DBG("AppKeyExist, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.app_keys); i++) { if (bt_mesh.app_keys[i].net_idx != BLE_MESH_KEY_UNUSED && bt_mesh.app_keys[i].app_idx == app_idx) { @@ -475,6 +497,8 @@ static int net_key_set(const char *name) int err = 0; int i; + BT_DBG("NetKeySet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -533,6 +557,8 @@ static int app_key_set(const char *name) int err = 0; int i; + BT_DBG("AppKeySet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -564,7 +590,6 @@ static int app_key_set(const char *name) if (!app) { app = bt_mesh_app_key_alloc(app_idx); if (!app) { - BT_ERR("No space for a new appkey 0x%03x", app_idx); err = -ENOMEM; goto free; } @@ -579,7 +604,7 @@ static int app_key_set(const char *name) bt_mesh_app_id(app->keys[1].val, &app->keys[1].id); BT_INFO("Restored AppKeyIndex 0x%03x, NetKeyIndex 0x%03x", - app->app_idx, app->net_idx); + app->app_idx, app->net_idx); BT_INFO("Restored AppKey %s", bt_hex(app->keys[0].val, 16)); } @@ -595,6 +620,8 @@ static int hb_pub_set(const char *name) bool exist = false; int err = 0; + BT_DBG("HbPubSet, Name %s", name); + if (!hb_pub) { BT_ERR("Invalid heartbeat publication"); return -EINVAL; @@ -639,6 +666,8 @@ static int cfg_set(const char *name) bool exist = false; int err = 0; + BT_DBG("CfgSet, Name %s", name); + if (!cfg) { BT_ERR("Invalid configuration"); stored_cfg.valid = false; @@ -672,6 +701,8 @@ static int model_set_bind(bool vnd, struct bt_mesh_model *model, uint16_t model_ int err = 0; int i; + BT_DBG("ModelSetBind, Key 0x%04x Vnd %u", model_key, vnd); + /* Start with empty array regardless of cleared or set value */ for (i = 0; i < ARRAY_SIZE(model->keys); i++) { model->keys[i] = BLE_MESH_KEY_UNUSED; @@ -698,6 +729,8 @@ static int model_set_sub(bool vnd, struct bt_mesh_model *model, uint16_t model_k int err = 0; int i; + BT_DBG("ModelSetSub, Key 0x%04x Vnd %u", model_key, vnd); + /* Start with empty array regardless of cleared or set value */ for (i = 0; i < ARRAY_SIZE(model->groups); i++) { model->groups[i] = BLE_MESH_ADDR_UNASSIGNED; @@ -724,6 +757,8 @@ static int model_set_pub(bool vnd, struct bt_mesh_model *model, uint16_t model_k bool exist = false; int err = 0; + BT_DBG("ModelSetPub, Key 0x%04x Vnd %u", model_key, vnd); + if (!model->pub) { BT_INFO("Not support publication, model_id 0x%04x, cid 0x%04x", vnd ? model->vnd.id : model->id, vnd ? model->vnd.company : 0xFFFF); @@ -774,6 +809,8 @@ static int model_set(bool vnd, const char *name) size_t length = 0U; int i; + BT_DBG("ModelSet, Name %s Vnd %u", name, vnd); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -790,7 +827,7 @@ static int model_set(bool vnd, const char *name) model = bt_mesh_model_get(vnd, elem_idx, model_idx); if (!model) { BT_ERR("%s model not found, elem_idx %u, model_idx %u", - vnd ? "vnd" : "sig", elem_idx, model_idx); + vnd ? "vnd" : "sig", elem_idx, model_idx); continue; } @@ -825,6 +862,8 @@ static int va_set(const char *name) int err = 0; int i; + BT_DBG("VaSet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -869,7 +908,7 @@ free: bt_mesh_free_buf(buf); return err; } -#endif +#endif /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ #if CONFIG_BLE_MESH_PROVISIONER static int p_prov_set(const char *name) @@ -878,6 +917,8 @@ static int p_prov_set(const char *name) bool exist = false; int err = 0; + BT_DBG("PvnrProvSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&val, sizeof(val), &exist); if (err) { BT_ERR("Failed to load next address allocation"); @@ -891,7 +932,7 @@ static int p_prov_set(const char *name) bt_mesh_provisioner_restore_prov_info(val.primary_addr, val.alloc_addr); BT_INFO("Restored Primary Address 0x%04x, next address alloc 0x%04x", - val.primary_addr, val.alloc_addr); + val.primary_addr, val.alloc_addr); return 0; } @@ -902,6 +943,8 @@ static int p_net_idx_set(const char *name) bool exist = false; int err = 0; + BT_DBG("PvnrNetIdxSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&net_idx, sizeof(net_idx), &exist); if (err) { BT_ERR("Failed to load next NetKeyIndex alloc"); @@ -925,6 +968,8 @@ static int p_app_idx_set(const char *name) bool exist = false; int err = 0; + BT_DBG("PvnrAppIdxSet, Name %s", name); + err = bt_mesh_load_core_settings(name, (uint8_t *)&app_idx, sizeof(app_idx), &exist); if (err) { BT_ERR("Failed to load next AppKeyIndex alloc"); @@ -946,6 +991,8 @@ static struct bt_mesh_subnet *p_subnet_exist(uint16_t net_idx) { int i; + BT_DBG("PvnrSubnetExist, NetIdx 0x%04x", net_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { if (bt_mesh.p_sub[i] && bt_mesh.p_sub[i]->net_idx == net_idx) { @@ -960,6 +1007,8 @@ static struct bt_mesh_subnet *p_subnet_alloc(void) { int i; + BT_DBG("PvnrSubnetAlloc"); + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_sub); i++) { if (bt_mesh.p_sub[i] == NULL) { bt_mesh.p_sub[i] = bt_mesh_calloc(sizeof(struct bt_mesh_subnet)); @@ -979,6 +1028,8 @@ static struct bt_mesh_app_key *p_appkey_exist(uint16_t app_idx) { int i; + BT_DBG("PvnrAppKeyExist, AppIdx 0x%04x", app_idx); + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { if (bt_mesh.p_app_keys[i] && bt_mesh.p_app_keys[i]->net_idx != BLE_MESH_KEY_UNUSED && @@ -994,6 +1045,8 @@ static struct bt_mesh_app_key *p_appkey_alloc(void) { int i; + BT_DBG("PvnrAppKeyAlloc"); + for (i = 0; i < ARRAY_SIZE(bt_mesh.p_app_keys); i++) { if (bt_mesh.p_app_keys[i] == NULL) { bt_mesh.p_app_keys[i] = bt_mesh_calloc(sizeof(struct bt_mesh_app_key)); @@ -1020,6 +1073,8 @@ static int p_net_key_set(const char *name) int err = 0; int i; + BT_DBG("PvnrNetKeySet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -1078,6 +1133,8 @@ static int p_app_key_set(const char *name) int err = 0; int i; + BT_DBG("PvnrAppKeySet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -1124,7 +1181,7 @@ static int p_app_key_set(const char *name) bt_mesh_app_id(app->keys[1].val, &app->keys[1].id); BT_INFO("Restored AppKeyIndex 0x%03x, NetKeyIndex 0x%03x", - app->app_idx, app->net_idx); + app->app_idx, app->net_idx); BT_INFO("Restored AppKey %s", bt_hex(app->keys[0].val, 16)); } @@ -1140,6 +1197,8 @@ static int node_info_set(uint16_t addr, bool *exist) char get[16] = {'\0'}; int err = 0; + BT_DBG("NodeInfoSet, Addr 0x%04x", addr); + sprintf(get, "mesh/pn/%04x/i", addr); err = bt_mesh_load_core_settings(get, (uint8_t *)&info, sizeof(info), exist); if (err) { @@ -1180,6 +1239,8 @@ static int node_name_set(uint16_t addr) bool exist = false; int err = 0; + BT_DBG("NodeNameSet, Addr 0x%04x", addr); + sprintf(get, "mesh/pn/%04x/n", addr); err = bt_mesh_load_core_settings(get, (uint8_t *)name, BLE_MESH_NODE_NAME_SIZE, &exist); if (err) { @@ -1208,6 +1269,8 @@ static int node_comp_data_set(uint16_t addr) char get[16] = {'\0'}; int err = 0; + BT_DBG("NodeCompDataSet, Addr 0x%04x", addr); + sprintf(get, "mesh/pn/%04x/c", addr); buf = bt_mesh_get_core_settings_item(get); if (!buf) { @@ -1232,6 +1295,8 @@ static int p_node_set(const char *name) size_t length = 0U; int i; + BT_DBG("PvnrNodeSet, Name %s", name); + buf = bt_mesh_get_core_settings_item(name); if (!buf) { return 0; @@ -1286,7 +1351,7 @@ const struct bt_mesh_setting { { "mesh/vnd", vnd_mod_set }, /* For Node & Provisioner */ #if CONFIG_BLE_MESH_LABEL_COUNT > 0 { "mesh/vaddr", va_set }, /* For Node */ -#endif +#endif /* CONFIG_BLE_MESH_LABEL_COUNT > 0 */ #if CONFIG_BLE_MESH_PROVISIONER { "mesh/p_prov", p_prov_set }, /* For Provisioner */ { "mesh/p_netidx", p_net_idx_set }, /* For Provisioner */ @@ -1294,7 +1359,7 @@ const struct bt_mesh_setting { { "mesh/p_netkey", p_net_key_set }, /* For Provisioner */ { "mesh/p_appkey", p_app_key_set }, /* For Provisioner */ { "mesh/p_node", p_node_set }, /* For Provisioner */ -#endif +#endif /* CONFIG_BLE_MESH_PROVISIONER */ }; /** @@ -1316,6 +1381,8 @@ int settings_core_load(void) { int i; + BT_DBG("SettingsCoreLoad"); + for (i = 0; i < ARRAY_SIZE(settings); i++) { if ((!strcmp(settings[i].name, "mesh/net") || !strcmp(settings[i].name, "mesh/netkey") || @@ -1367,6 +1434,8 @@ static int subnet_init(struct bt_mesh_subnet *sub) { int err = 0; + BT_DBG("SubnetInit, NetIdx 0x%04x KrPhase %u", sub->net_idx, sub->kr_phase); + err = bt_mesh_net_keys_create(&sub->keys[0], sub->keys[0].net); if (err) { BT_ERR("Unable to generate keys for subnet"); @@ -1394,7 +1463,7 @@ static int subnet_init(struct bt_mesh_subnet *sub) #if CONFIG_BLE_MESH_DF_SRV bt_mesh_directed_forwarding_sub_init(sub); bt_mesh_recovery_directed_forwarding_table(sub); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ return 0; } @@ -1402,8 +1471,10 @@ static int subnet_init(struct bt_mesh_subnet *sub) static void commit_model(struct bt_mesh_model *model, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("CommitModel, Vnd %u Primary %u", vnd, primary); + if (model->pub && model->pub->update && - model->pub->addr != BLE_MESH_ADDR_UNASSIGNED) { + model->pub->addr != BLE_MESH_ADDR_UNASSIGNED) { int32_t ms = bt_mesh_model_pub_period_get(model); if (ms) { BT_DBG("Starting publish timer (period %u ms)", ms); @@ -1418,10 +1489,13 @@ int settings_core_commit(void) int err = 0; int i; + BT_DBG("SettingsCoreCommit"); + #if CONFIG_BLE_MESH_NODE if (bt_mesh_is_node()) { if (bt_mesh.sub[0].net_idx == BLE_MESH_KEY_UNUSED) { /* Nothing to do since we're not yet provisioned */ + BT_INFO("NodeNotYetProvisioned"); return 0; } @@ -1511,20 +1585,22 @@ int settings_core_commit(void) } /* Pending flags that use K_NO_WAIT as the storage timeout */ -#define NO_WAIT_PENDING_BITS (BIT(BLE_MESH_NET_PENDING) | \ - BIT(BLE_MESH_IV_PENDING) | \ - BIT(BLE_MESH_SEQ_PENDING)) +#define NO_WAIT_PENDING_BITS (BIT(BLE_MESH_NET_PENDING) | \ + BIT(BLE_MESH_IV_PENDING) | \ + BIT(BLE_MESH_SEQ_PENDING)) /* Pending flags that use CONFIG_BLE_MESH_STORE_TIMEOUT */ -#define GENERIC_PENDING_BITS (BIT(BLE_MESH_KEYS_PENDING) | \ - BIT(BLE_MESH_HB_PUB_PENDING) | \ - BIT(BLE_MESH_CFG_PENDING) | \ - BIT(BLE_MESH_MOD_PENDING)) +#define GENERIC_PENDING_BITS (BIT(BLE_MESH_KEYS_PENDING) | \ + BIT(BLE_MESH_HB_PUB_PENDING) | \ + BIT(BLE_MESH_CFG_PENDING) | \ + BIT(BLE_MESH_MOD_PENDING)) static void schedule_store(int flag) { int32_t timeout = 0, remaining = 0; + BT_DBG("ScheduleStore, Flag %ld", flag); + bt_mesh_atomic_set_bit(bt_mesh.flags, flag); /* When Node is not provisioned OR Provisioner is disabled, @@ -1562,7 +1638,8 @@ static void schedule_store(int flag) static void clear_net(void) { - BT_DBG("Clearing Network"); + BT_DBG("ClearNet"); + bt_mesh_erase_core_settings("mesh/net"); } @@ -1570,8 +1647,9 @@ static void store_pending_net(void) { struct net_val net = {0}; - BT_DBG("Primary address 0x%04x DevKey %s", bt_mesh_primary_addr(), - bt_hex(bt_mesh.dev_key, 16)); + BT_DBG("StorePendingNet"); + BT_DBG("PrimaryAddr 0x%04x DevKey %s", + bt_mesh_primary_addr(), bt_hex(bt_mesh.dev_key, 16)); net.primary_addr = bt_mesh_primary_addr(); memcpy(net.dev_key, bt_mesh.dev_key, 16); @@ -1581,13 +1659,15 @@ static void store_pending_net(void) void bt_mesh_store_role(void) { - BT_DBG("Store, device role %lu", bt_mesh_atomic_get(bt_mesh.flags) & BLE_MESH_SETTINGS_ROLE_BIT_MASK); + BT_DBG("StoreRole %lu", bt_mesh_atomic_get(bt_mesh.flags) & BLE_MESH_SETTINGS_ROLE_BIT_MASK); bt_mesh_save_core_settings("mesh/role", (const uint8_t *)bt_mesh.flags, sizeof(bt_mesh.flags)); } void bt_mesh_store_net(void) { + BT_DBG("StoreNetSchedule"); + schedule_store(BLE_MESH_NET_PENDING); } @@ -1595,6 +1675,8 @@ static void store_pending_iv(void) { struct iv_val iv = {0}; + BT_DBG("StorePendingIV"); + iv.iv_index = bt_mesh.iv_index; iv.iv_update = bt_mesh_atomic_test_bit(bt_mesh.flags, BLE_MESH_IVU_IN_PROGRESS); iv.iv_duration = bt_mesh.ivu_duration; @@ -1604,6 +1686,8 @@ static void store_pending_iv(void) void bt_mesh_store_iv(bool only_duration) { + BT_DBG("StoreIVSchedule, OnlyDuration %u", only_duration); + schedule_store(BLE_MESH_IV_PENDING); if (!only_duration) { @@ -1614,7 +1698,8 @@ void bt_mesh_store_iv(bool only_duration) static void clear_iv(void) { - BT_DBG("Clearing IV"); + BT_DBG("ClearIV"); + bt_mesh_erase_core_settings("mesh/iv"); } @@ -1622,6 +1707,8 @@ static void store_pending_seq(void) { struct seq_val seq = {0}; + BT_DBG("StorePendingSeq, Seq 0x%06x", bt_mesh.seq); + sys_put_le24(bt_mesh.seq, seq.val); bt_mesh_save_core_settings("mesh/seq", (const uint8_t *)&seq, sizeof(seq)); @@ -1629,6 +1716,8 @@ static void store_pending_seq(void) void bt_mesh_store_seq(void) { + BT_DBG("StoreSeqSchedule, Seq 0x%06x", bt_mesh.seq); + if (CONFIG_BLE_MESH_SEQ_STORE_RATE && (bt_mesh.seq % CONFIG_BLE_MESH_SEQ_STORE_RATE)) { return; @@ -1639,7 +1728,8 @@ void bt_mesh_store_seq(void) void bt_mesh_clear_seq(void) { - BT_DBG("Clearing Seq"); + BT_DBG("ClearSeq"); + bt_mesh_erase_core_settings("mesh/seq"); } @@ -1649,7 +1739,8 @@ static void store_rpl(struct bt_mesh_rpl *entry) char name[16] = {'\0'}; int err = 0; - BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, entry->seq, entry->old_iv); + BT_DBG("StoreRPL"); + BT_DBG("Src 0x%04x Seq 0x%06x OldIV %u", entry->src, entry->seq, entry->old_iv); rpl.seq = entry->seq; rpl.old_iv = entry->old_iv; @@ -1675,6 +1766,8 @@ static void clear_rpl(void) uint16_t src = 0U; int i; + BT_DBG("ClearRPL"); + buf = bt_mesh_get_core_settings_item("mesh/rpl"); if (!buf) { bt_mesh_erase_core_settings("mesh/rpl"); @@ -1704,9 +1797,14 @@ static void store_pending_rpl(void) { int i; + BT_DBG("StorePendingRPL"); + for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; + BT_DBG("%u: Src 0x%04x Seq 0x%06x OldIV %u Store %u", + i, rpl->src, rpl->seq, rpl->old_iv, rpl->store); + if (rpl->store) { rpl->store = false; store_rpl(rpl); @@ -1719,6 +1817,8 @@ static void store_pending_hb_pub(void) struct bt_mesh_hb_pub *hb_pub = bt_mesh_hb_pub_get(); struct hb_pub_val val = {0}; + BT_DBG("StorePendingHbPub"); + if (!hb_pub) { BT_ERR("Invalid heartbeat publication"); return; @@ -1736,7 +1836,8 @@ static void store_pending_hb_pub(void) static void clear_hb_pub(void) { - BT_DBG("Clear heartbeat publication"); + BT_DBG("ClearHbPub"); + bt_mesh_erase_core_settings("mesh/hb_pub"); } @@ -1745,6 +1846,8 @@ static void store_pending_cfg(void) struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); struct cfg_val val = {0}; + BT_DBG("StorePendingCfg"); + if (!cfg) { BT_WARN("NULL configuration state"); return; @@ -1763,7 +1866,8 @@ static void store_pending_cfg(void) static void clear_cfg(void) { - BT_DBG("Clearing configuration"); + BT_DBG("ClearCfg"); + bt_mesh_erase_core_settings("mesh/cfg"); } @@ -1772,7 +1876,7 @@ static void clear_app_key(uint16_t app_idx) char name[16] = {'\0'}; int err = 0; - BT_DBG("AppKeyIndex 0x%03x", app_idx); + BT_DBG("ClearAppKey, AppIdx 0x%04x", app_idx); sprintf(name, "mesh/ak/%04x", app_idx); bt_mesh_erase_core_settings(name); @@ -1788,7 +1892,7 @@ static void clear_net_key(uint16_t net_idx) char name[16] = {'\0'}; int err = 0; - BT_DBG("NetKeyIndex 0x%03x", net_idx); + BT_DBG("ClearNetKey, NetIdx 0x%04x", net_idx); sprintf(name, "mesh/nk/%04x", net_idx); bt_mesh_erase_core_settings(name); @@ -1800,7 +1904,7 @@ static void clear_net_key(uint16_t net_idx) #if CONFIG_BLE_MESH_DF_SRV bt_mesh_clear_directed_forwarding_table_data(net_idx); -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } static void store_net_key(struct bt_mesh_subnet *sub) @@ -1809,8 +1913,8 @@ static void store_net_key(struct bt_mesh_subnet *sub) char name[16] = {'\0'}; int err = 0; - BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, - bt_hex(sub->keys[0].net, 16)); + BT_DBG("StoreNetKey, NetIdx 0x%04x KrFlag %u KrPhase %u", + sub->net_idx, sub->kr_flag, sub->kr_phase); memcpy(&key.val[0], sub->keys[0].net, 16); memcpy(&key.val[1], sub->keys[1].net, 16); @@ -1836,6 +1940,9 @@ static void store_app_key(struct bt_mesh_app_key *app) char name[16] = {'\0'}; int err = 0; + BT_DBG("StoreAppKey, NetIdx 0x%04x AppIdx 0x%04x Updated %u", + app->net_idx, app->app_idx, app->updated); + key.net_idx = app->net_idx; key.updated = app->updated; memcpy(key.val[0], app->keys[0].val, 16); @@ -1858,9 +1965,14 @@ static void store_pending_keys(void) { int i; + BT_DBG("StorePendingKeys"); + for (i = 0; i < ARRAY_SIZE(key_updates); i++) { struct key_update *update = &key_updates[i]; + BT_DBG("%u: KeyIdx 0x%04x Valid %u AppKey %u Clear %u", + i, update->key_idx, update->valid, update->app_key, update->clear); + if (!update->valid) { continue; } @@ -1874,6 +1986,7 @@ static void store_pending_keys(void) } else { if (update->app_key) { struct bt_mesh_app_key *key = NULL; + key = bt_mesh_app_key_get(update->key_idx); if (key) { store_app_key(key); @@ -1882,6 +1995,7 @@ static void store_pending_keys(void) } } else { struct bt_mesh_subnet *sub = NULL; + sub = bt_mesh_subnet_get(update->key_idx); if (sub) { store_net_key(sub); @@ -1901,6 +2015,8 @@ static void store_pending_mod_bind(struct bt_mesh_model *model, bool vnd) uint16_t model_key = 0U; int err = 0; + BT_DBG("StorePendingModBind, Vnd %u", vnd); + model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/b", vnd ? "v" : "s", model_key); @@ -1913,7 +2029,7 @@ static void store_pending_mod_bind(struct bt_mesh_model *model, bool vnd) err = bt_mesh_add_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); if (err) { BT_ERR("Failed to add bound key to %s, model_key 0x%04x", - vnd ? "mesh/vnd" : "mesh/sig", model_key); + vnd ? "mesh/vnd" : "mesh/sig", model_key); } } @@ -1923,6 +2039,8 @@ static void store_pending_mod_sub(struct bt_mesh_model *model, bool vnd) uint16_t model_key = 0U; int err = 0; + BT_DBG("StorePendingModSub, Vnd %u", vnd); + model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/s", vnd ? "v" : "s", model_key); @@ -1935,7 +2053,7 @@ static void store_pending_mod_sub(struct bt_mesh_model *model, bool vnd) err = bt_mesh_add_core_settings_item(vnd ? "mesh/vnd" : "mesh/sig", model_key); if (err) { BT_ERR("Failed to add subscription to %s, model_key 0x%04x", - vnd ? "mesh/vnd" : "mesh/sig", model_key); + vnd ? "mesh/vnd" : "mesh/sig", model_key); } } @@ -1946,6 +2064,8 @@ static void store_pending_mod_pub(struct bt_mesh_model *model, bool vnd) uint16_t model_key = 0U; int err = 0; + BT_DBG("StorePendingModPub, Vnd %u", vnd); + if (!model->pub) { BT_WARN("Model has no publication support"); return; @@ -1964,7 +2084,7 @@ static void store_pending_mod_pub(struct bt_mesh_model *model, bool vnd) #if CONFIG_BLE_MESH_DF_SRV pub.directed_pub_policy = model->pub->directed_pub_policy; /**< Directed publish policy */ -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ err = bt_mesh_save_core_settings(name, (const uint8_t *)&pub, sizeof(pub)); if (err) { @@ -1983,6 +2103,8 @@ static void store_pending_mod(struct bt_mesh_model *model, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("StorePendingMod, Flags %u Vnd %u", model->flags, vnd); + if (!model->flags) { return; } @@ -2008,6 +2130,8 @@ static void clear_mod_bind(struct bt_mesh_model *model, bool vnd) char name[16] = {'\0'}; uint16_t model_key = 0U; + BT_DBG("ClearModBind, Vnd %u", vnd); + model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/b", vnd ? "v" : "s", model_key); @@ -2020,6 +2144,8 @@ static void clear_mod_sub(struct bt_mesh_model *model, bool vnd) char name[16] = {'\0'}; uint16_t model_key = 0U; + BT_DBG("ClearModSub, Vnd %u", vnd); + model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/s", vnd ? "v" : "s", model_key); @@ -2029,8 +2155,10 @@ static void clear_mod_sub(struct bt_mesh_model *model, bool vnd) static void clear_mod_pub(struct bt_mesh_model *model, bool vnd) { - char name[16] = {'\0'}; uint16_t model_key = 0U; + char name[16] = {'\0'}; + + BT_DBG("ClearModPub, Vnd %u", vnd); model_key = BLE_MESH_GET_MODEL_KEY(model->elem_idx, model->model_idx); sprintf(name, "mesh/%s/%04x/p", vnd ? "v" : "s", model_key); @@ -2043,6 +2171,8 @@ static void clear_pending_mod(struct bt_mesh_model *model, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { + BT_DBG("ClearPendingMod, Flags 0x%04x Vnd %u", model->flags, vnd); + if (!model->flags) { return; } @@ -2066,12 +2196,14 @@ static void clear_pending_mod(struct bt_mesh_model *model, #define IS_VA_DEL(_label) ((_label)->ref == 0) static void store_pending_va(void) { + struct label *lab = NULL; struct va_val va = {0}; char name[16] = {'\0'}; - struct label *lab = NULL; uint16_t i = 0U; int err = 0; + BT_DBG("StorePendingVa"); + for (i = 0U; (lab = get_label(i)) != NULL; i++) { if (!bt_mesh_atomic_test_and_clear_bit(lab->flags, BLE_MESH_VA_CHANGED)) { @@ -2090,7 +2222,7 @@ static void store_pending_va(void) } if (err) { BT_ERR("Failed to %s virtual address %s", - IS_VA_DEL(lab) ? "delete" : "store", name); + IS_VA_DEL(lab) ? "delete" : "store", name); return; } @@ -2101,7 +2233,7 @@ static void store_pending_va(void) } if (err) { BT_ERR("Failed to %s 0x%04x in mesh/vaddr", - IS_VA_DEL(lab) ? "delete" : "store", i); + IS_VA_DEL(lab) ? "delete" : "store", i); return; } @@ -2111,6 +2243,8 @@ static void store_pending_va(void) static void store_pending(struct k_work *work) { + BT_DBG("StorePending"); + if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_RPL_PENDING)) { if (bt_mesh_is_provisioned() || bt_mesh_is_provisioner_en()) { store_pending_rpl(); @@ -2172,6 +2306,7 @@ static void store_pending(struct k_work *work) bt_mesh_model_foreach(store_pending_mod, NULL); } else { bt_mesh_model_foreach(clear_pending_mod, NULL); + bt_mesh_erase_core_settings("mesh/sig"); bt_mesh_erase_core_settings("mesh/vnd"); } @@ -2185,6 +2320,9 @@ static void store_pending(struct k_work *work) void bt_mesh_store_rpl(struct bt_mesh_rpl *entry) { + BT_DBG("StoreRPLSchedule"); + BT_DBG("Src 0x%04x Seq 0x%06x OldIV %u", entry->src, entry->seq, entry->old_iv); + entry->store = true; schedule_store(BLE_MESH_RPL_PENDING); } @@ -2197,6 +2335,8 @@ static struct key_update *key_update_find(bool app_key, uint16_t key_idx, *free_slot = NULL; + BT_DBG("KeyUpdateFind, KeyIdx 0x%04x AppKey %u", key_idx, app_key); + for (i = 0; i < ARRAY_SIZE(key_updates); i++) { struct key_update *update = &key_updates[i]; @@ -2222,7 +2362,7 @@ void bt_mesh_store_subnet(struct bt_mesh_subnet *sub) struct key_update *free_slot = NULL; struct key_update *update = NULL; - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + BT_DBG("StoreSubnetSchedule, NetIdx 0x%04x", sub->net_idx); update = key_update_find(false, sub->net_idx, &free_slot); if (update) { @@ -2232,6 +2372,7 @@ void bt_mesh_store_subnet(struct bt_mesh_subnet *sub) } if (!free_slot) { + BT_DBG("NoFreeSlotForSubnet"); store_net_key(sub); return; } @@ -2249,7 +2390,7 @@ void bt_mesh_store_app_key(struct bt_mesh_app_key *key) struct key_update *free_slot = NULL; struct key_update *update = NULL; - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + BT_DBG("StoreAppKeySchedule, AppIdx 0x%04x", key->app_idx); update = key_update_find(true, key->app_idx, &free_slot); if (update) { @@ -2259,6 +2400,7 @@ void bt_mesh_store_app_key(struct bt_mesh_app_key *key) } if (!free_slot) { + BT_DBG("NoFreeSlotForAppKey"); store_app_key(key); return; } @@ -2273,22 +2415,29 @@ void bt_mesh_store_app_key(struct bt_mesh_app_key *key) void bt_mesh_store_hb_pub(void) { + BT_DBG("StoreHbPubSchedule"); + schedule_store(BLE_MESH_HB_PUB_PENDING); } void bt_mesh_store_cfg(void) { + BT_DBG("StoreCfgSchedule"); + schedule_store(BLE_MESH_CFG_PENDING); } void bt_mesh_clear_role(void) { - BT_DBG("Clear device role"); + BT_DBG("ClearRole"); + bt_mesh_erase_core_settings("mesh/role"); } void bt_mesh_clear_net(void) { + BT_DBG("ClearNetSchedule"); + schedule_store(BLE_MESH_NET_PENDING); schedule_store(BLE_MESH_IV_PENDING); schedule_store(BLE_MESH_CFG_PENDING); @@ -2299,7 +2448,7 @@ void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub) struct key_update *free_slot = NULL; struct key_update *update = NULL; - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + BT_DBG("ClearSubnetSchedule, NetIdx 0x%04x", sub->net_idx); update = key_update_find(false, sub->net_idx, &free_slot); if (update) { @@ -2326,7 +2475,7 @@ void bt_mesh_clear_app_key(struct bt_mesh_app_key *key) struct key_update *free_slot = NULL; struct key_update *update = NULL; - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + BT_DBG("ClearAppKeySchedule, AppIdx 0x%04x", key->app_idx); update = key_update_find(true, key->app_idx, &free_slot); if (update) { @@ -2353,6 +2502,8 @@ void bt_mesh_clear_rpl_single(uint16_t src) char name[16] = {'\0'}; int err = 0; + BT_DBG("ClearRPLSingle, Src 0x%04x", src); + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { BT_ERR("Invalid src 0x%04x", src); return; @@ -2369,39 +2520,53 @@ void bt_mesh_clear_rpl_single(uint16_t src) void bt_mesh_clear_rpl(void) { + BT_DBG("ClearRPLSchedule"); + schedule_store(BLE_MESH_RPL_PENDING); } void bt_mesh_store_mod_bind(struct bt_mesh_model *model) { + BT_DBG("StoreModBindSchedule"); + model->flags |= BLE_MESH_MOD_BIND_PENDING; schedule_store(BLE_MESH_MOD_PENDING); } void bt_mesh_store_mod_sub(struct bt_mesh_model *model) { + BT_DBG("StoreModSubSchedule"); + model->flags |= BLE_MESH_MOD_SUB_PENDING; schedule_store(BLE_MESH_MOD_PENDING); } void bt_mesh_store_mod_pub(struct bt_mesh_model *model) { + BT_DBG("StoreModPubSchedule"); + model->flags |= BLE_MESH_MOD_PUB_PENDING; schedule_store(BLE_MESH_MOD_PENDING); } void bt_mesh_store_label(void) { + BT_DBG("StoreLabelSchedule"); + schedule_store(BLE_MESH_VA_PENDING); } void bt_mesh_store_dkca(void) { + BT_DBG("StoreDkca"); + bt_mesh_save_core_settings("mesh/dkca", bt_mesh.dev_key_ca, sizeof(bt_mesh.dev_key_ca)); } void bt_mesh_clear_dkca(void) { + BT_DBG("ClearDkca"); + bt_mesh_erase_core_settings("mesh/dkca"); } @@ -2423,7 +2588,7 @@ void bt_mesh_store_prov_info(uint16_t primary_addr, uint16_t alloc_addr) { struct prov_info val = {0}; - BT_DBG("Primary address 0x%04x, next address allocation 0x%04x", primary_addr, alloc_addr); + BT_DBG("StoreProvInfo, PrimaryAddr 0x%04x AllocAddr 0x%04x", primary_addr, alloc_addr); val.primary_addr = primary_addr; val.alloc_addr = alloc_addr; @@ -2433,7 +2598,8 @@ void bt_mesh_store_prov_info(uint16_t primary_addr, uint16_t alloc_addr) void bt_mesh_clear_prov_info(void) { - BT_DBG("Clearing prov info"); + BT_DBG("ClearProvInfo"); + bt_mesh_erase_core_settings("mesh/p_prov"); } @@ -2443,6 +2609,9 @@ static void store_p_net_key(struct bt_mesh_subnet *sub) char name[16] = {'\0'}; int err = 0; + BT_DBG("StorePvnrNetKey, NetIdx 0x%04x KrFlag %u KrPhase %u", + sub->net_idx, sub->kr_flag, sub->kr_phase); + memcpy(&key.val[0], sub->keys[0].net, 16); memcpy(&key.val[1], sub->keys[1].net, 16); key.kr_flag = sub->kr_flag; @@ -2467,6 +2636,9 @@ static void store_p_app_key(struct bt_mesh_app_key *app) char name[16] = {'\0'}; int err = 0; + BT_DBG("StorePvnrAppKey, NetIdx 0x%04x AppIdx 0x%04x Updated %u", + app->net_idx, app->app_idx, app->updated); + key.net_idx = app->net_idx; key.updated = app->updated; memcpy(key.val[0], app->keys[0].val, 16); @@ -2487,7 +2659,7 @@ static void store_p_app_key(struct bt_mesh_app_key *app) void bt_mesh_store_p_net_idx(void) { - BT_DBG("Store, p_net_idx_next 0x%03x", bt_mesh.p_net_idx_next); + BT_DBG("StorePvnrNetIdx, NetIdxNext 0x%04x", bt_mesh.p_net_idx_next); bt_mesh_save_core_settings("mesh/p_netidx", (const uint8_t *)&bt_mesh.p_net_idx_next, sizeof(bt_mesh.p_net_idx_next)); @@ -2495,13 +2667,14 @@ void bt_mesh_store_p_net_idx(void) void bt_mesh_clear_p_net_idx(void) { - BT_DBG("Clearing NetKey Index"); + BT_DBG("ClearPvnrNetIdx"); + bt_mesh_erase_core_settings("mesh/p_netidx"); } void bt_mesh_store_p_app_idx(void) { - BT_DBG("Store, p_app_idx_next 0x%03x", bt_mesh.p_app_idx_next); + BT_DBG("StorePvnrAppIdx, AppIdxNext 0x%04x", bt_mesh.p_app_idx_next); bt_mesh_save_core_settings("mesh/p_appidx", (const uint8_t *)&bt_mesh.p_app_idx_next, sizeof(bt_mesh.p_app_idx_next)); @@ -2509,32 +2682,37 @@ void bt_mesh_store_p_app_idx(void) void bt_mesh_clear_p_app_idx(void) { - BT_DBG("Clearing AppKey Index"); + BT_DBG("ClearPvnrAppIdx"); + bt_mesh_erase_core_settings("mesh/p_appidx"); } void bt_mesh_store_p_subnet(struct bt_mesh_subnet *sub) { + BT_DBG("StorePvnrSubnet"); + if (sub == NULL) { BT_ERR("Invalid subnet"); return; } - BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, - bt_hex(sub->keys[0].net, 16)); + BT_DBG("NetIdx 0x%04x NetKey %s", + sub->net_idx, bt_hex(sub->keys[0].net, 16)); store_p_net_key(sub); } void bt_mesh_store_p_app_key(struct bt_mesh_app_key *key) { + BT_DBG("StorePvnrAppKey"); + if (key == NULL) { BT_ERR("Invalid AppKey"); return; } - BT_DBG("AppKeyIndex 0x%03x AppKey %s", key->app_idx, - bt_hex(key->keys[0].val, 16)); + BT_DBG("AppIdx 0x%03x AppKey %s", + key->app_idx, bt_hex(key->keys[0].val, 16)); store_p_app_key(key); } @@ -2544,7 +2722,7 @@ void bt_mesh_clear_p_subnet(uint16_t net_idx) char name[16] = {'\0'}; int err = 0; - BT_DBG("NetKeyIndex 0x%03x", net_idx); + BT_DBG("ClearPvnrSubnet, NetIdx 0x%04x", net_idx); sprintf(name, "mesh/pnk/%04x", net_idx); bt_mesh_erase_core_settings(name); @@ -2560,7 +2738,7 @@ void bt_mesh_clear_p_app_key(uint16_t app_idx) char name[16] = {'\0'}; int err = 0; - BT_DBG("AppKeyIndex 0x%03x", app_idx); + BT_DBG("ClearPvnrAppKey, AppIdx 0x%04x", app_idx); sprintf(name, "mesh/pak/%04x", app_idx); bt_mesh_erase_core_settings(name); @@ -2577,11 +2755,17 @@ void bt_mesh_store_node_info(struct bt_mesh_node *node) char name[16] = {'\0'}; int err = 0; + BT_DBG("StoreNodeInfo"); + if (node == NULL) { BT_ERR("Invalid node info"); return; } + BT_DBG("UnicastAddr 0x%04x ElemNum %u NetIdx 0x%04x Flags %u IVIndex %lu", + node->unicast_addr, node->element_num, + node->net_idx, node->flags, node->iv_index); + memcpy(val.addr, node->addr, BLE_MESH_ADDR_LEN); val.addr_type = node->addr_type; memcpy(val.dev_uuid, node->dev_uuid, 16); @@ -2611,6 +2795,8 @@ static void clear_node(uint16_t addr) char name[16] = {'\0'}; int err = 0; + BT_DBG("ClearNode, Addr 0x%04x", addr); + /* Clear node information */ sprintf(name, "mesh/pn/%04x/i", addr); bt_mesh_erase_core_settings(name); @@ -2631,13 +2817,13 @@ static void clear_node(uint16_t addr) void bt_mesh_clear_node_info(uint16_t unicast_addr) { + BT_DBG("ClearNodeInfo, Addr 0x%04x", unicast_addr); + if (!BLE_MESH_ADDR_IS_UNICAST(unicast_addr)) { BT_ERR("Invalid unicast address 0x%04x", unicast_addr); return; } - BT_DBG("Unicast address 0x%04x", unicast_addr); - clear_node(unicast_addr); } @@ -2647,11 +2833,15 @@ void bt_mesh_store_node_name(struct bt_mesh_node *node) char name[16] = {'\0'}; int err = 0; + BT_DBG("StoreNodeName"); + if (node == NULL) { BT_ERR("Invalid node info"); return; } + BT_DBG("UnicastAddr 0x%04x NodeName %s", node->unicast_addr, node->name); + strncpy(node_name, node->name, BLE_MESH_NODE_NAME_SIZE + 1); sprintf(name, "mesh/pn/%04x/n", node->unicast_addr); @@ -2666,11 +2856,15 @@ void bt_mesh_store_node_comp_data(struct bt_mesh_node *node) char name[16] = {'\0'}; int err = 0; + BT_DBG("StoreNodeCompData"); + if (!node || !node->comp_data || node->comp_length == 0U) { BT_ERR("Invalid node info"); return; } + BT_DBG("UnicastAddr 0x%04x CompLength %u", node->unicast_addr, node->comp_length); + sprintf(name, "mesh/pn/%04x/c", node->unicast_addr); err = bt_mesh_save_core_settings(name, (const uint8_t *)node->comp_data, node->comp_length); if (err) { @@ -2681,12 +2875,16 @@ void bt_mesh_store_node_comp_data(struct bt_mesh_node *node) int settings_core_init(void) { + BT_DBG("SettingsCoreInit"); + k_delayed_work_init(&pending_store, store_pending); return 0; } int bt_mesh_settings_init(void) { + BT_DBG("SettingsInit"); + bt_mesh_settings_mutex_new(); bt_mesh_settings_init_foreach(); return 0; @@ -2695,12 +2893,16 @@ int bt_mesh_settings_init(void) #if CONFIG_BLE_MESH_DEINIT int settings_core_deinit(void) { + BT_DBG("SettingsCoreDeinit"); + k_delayed_work_free(&pending_store); return 0; } int settings_core_erase(void) { + BT_DBG("SettingsCoreErase"); + /* Erase here must not use the pending_store timer. * This is used for erasing the information which * could not be erased during the previous deinit @@ -2714,6 +2916,8 @@ int settings_core_erase(void) int bt_mesh_settings_deinit(bool erase) { + BT_DBG("SettingsDeinit, Erase %u", erase); + bt_mesh_settings_deinit_foreach(erase); bt_mesh_settings_mutex_free(); return 0; @@ -2722,6 +2926,8 @@ int bt_mesh_settings_deinit(bool erase) void bt_mesh_settings_reset(bool erase) { + BT_DBG("SettingsReset, Erase %u", erase); + k_delayed_work_cancel(&pending_store); if (erase) { bt_mesh_clear_net(); diff --git a/components/bt/esp_ble_mesh/core/storage/settings_nvs.c b/components/bt/esp_ble_mesh/core/storage/settings_nvs.c index ca3ac144ef..f539c0a35a 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings_nvs.c +++ b/components/bt/esp_ble_mesh/core/storage/settings_nvs.c @@ -17,7 +17,7 @@ enum settings_type { SETTINGS_CORE, #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE SETTINGS_UID, -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ }; struct settings_context { @@ -62,15 +62,20 @@ static struct settings_context settings_ctx[] = { int bt_mesh_settings_nvs_open(const char* name, bt_mesh_nvs_handle_t *handle) { + assert(name); + BT_DBG("SettingsNVSOpen, Name %s", name); + #if CONFIG_BLE_MESH_SPECIFIC_PARTITION return nvs_open_from_partition(CONFIG_BLE_MESH_PARTITION_NAME, name, NVS_READWRITE, handle); -#else +#else /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */ return nvs_open(name, NVS_READWRITE, handle); -#endif +#endif /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */ } void bt_mesh_settings_nvs_close(bt_mesh_nvs_handle_t handle) { + BT_DBG("SettingsNVSClose, Handle %lu", handle); + nvs_close(handle); } @@ -79,6 +84,8 @@ void bt_mesh_settings_init_foreach(void) int err = 0; int i; + BT_DBG("SettingsInitForeach"); + #if CONFIG_BLE_MESH_SPECIFIC_PARTITION err = nvs_flash_init_partition(CONFIG_BLE_MESH_PARTITION_NAME); if (err != ESP_OK) { @@ -134,6 +141,8 @@ void bt_mesh_settings_deinit_foreach(bool erase) { int i; + BT_DBG("SettingsDeinitForeach, Erase %u", erase); + for (i = 0; i < ARRAY_SIZE(settings_ctx); i++) { struct settings_context *ctx = &settings_ctx[i]; @@ -152,7 +161,7 @@ void bt_mesh_settings_deinit_foreach(bool erase) #if CONFIG_BLE_MESH_SPECIFIC_PARTITION nvs_flash_deinit_partition(CONFIG_BLE_MESH_PARTITION_NAME); -#endif +#endif /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */ } #endif /* CONFIG_BLE_MESH_DEINIT */ @@ -161,6 +170,8 @@ int bt_mesh_settings_direct_open(bt_mesh_nvs_handle_t *handle) int err = 0; int i; + BT_DBG("SettingsDirectOpen"); + #if CONFIG_BLE_MESH_SPECIFIC_PARTITION err = nvs_flash_init_partition(CONFIG_BLE_MESH_PARTITION_NAME); if (err != ESP_OK) { @@ -178,6 +189,8 @@ int bt_mesh_settings_direct_open(bt_mesh_nvs_handle_t *handle) return -EIO; } + BT_DBG("%u: NVSName %s Handle %lu", i, ctx->nvs_name, ctx->handle); + if (i == SETTINGS_CORE && handle) { *handle = ctx->handle; } @@ -190,25 +203,30 @@ void bt_mesh_settings_direct_close(void) { int i; + BT_DBG("SettingsDirectClose"); + for (i = 0; i < ARRAY_SIZE(settings_ctx); i++) { bt_mesh_settings_nvs_close(settings_ctx[i].handle); } #if CONFIG_BLE_MESH_SPECIFIC_PARTITION nvs_flash_deinit_partition(CONFIG_BLE_MESH_PARTITION_NAME); -#endif +#endif /* CONFIG_BLE_MESH_SPECIFIC_PARTITION */ } /* API used to get BLE Mesh related nvs handle */ static inline bt_mesh_nvs_handle_t settings_get_nvs_handle(enum settings_type type) { + BT_DBG("SettingsGetNVSHandle, Type %u", type); + #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE if (type == SETTINGS_CORE) { extern bt_mesh_nvs_handle_t get_core_settings_handle(void); return get_core_settings_handle(); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ + return settings_ctx[type].handle; } @@ -218,12 +236,8 @@ static int settings_save(bt_mesh_nvs_handle_t handle, const char *key, const uin { int err = 0; - if (key == NULL) { - BT_ERR("%s, Invalid parameter", __func__); - return -EINVAL; - } - - BT_DBG("nvs %s, key %s", val ? "set" : "erase", key); + BT_DBG("Settings%s, Handle %lu Len %lu Key %s", + val ? "Store" : "Erase", handle, len, key); if (val) { err = nvs_set_blob(handle, key, val, len); @@ -236,7 +250,7 @@ static int settings_save(bt_mesh_nvs_handle_t handle, const char *key, const uin } if (err != ESP_OK) { BT_ERR("Failed to %s %s data (err %d)", - val ? "set" : "erase", key, err); + val ? "set" : "erase", key, err); return -EIO; } @@ -262,6 +276,10 @@ int bt_mesh_save_settings(bt_mesh_nvs_handle_t handle, const char *key, int bt_mesh_save_core_settings(const char *key, const uint8_t *val, size_t len) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("SaveCoreSettings, Handle %lu Len %lu Key %s", handle, len, key); + return bt_mesh_save_settings(handle, key, val, len); } @@ -269,26 +287,39 @@ int bt_mesh_save_core_settings(const char *key, const uint8_t *val, size_t len) int bt_mesh_save_uid_settings(const char *key, const uint8_t *val, size_t len) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("SaveUIDSettings, Handle %lu Len %lu Key %s", handle, len, key); + return bt_mesh_save_settings(handle, key, val, len); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ int bt_mesh_erase_settings(bt_mesh_nvs_handle_t handle, const char *key) { + assert(key); + BT_DBG("EraseSettings, Handle %lu Key %s", handle, key); + return bt_mesh_save_settings(handle, key, NULL, 0); } int bt_mesh_erase_core_settings(const char *key) { + assert(key); + BT_DBG("EraseCoreSettings, Key %s", key); + return bt_mesh_save_core_settings(key, NULL, 0); } #if CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE int bt_mesh_erase_uid_settings(const char *name) { + assert(name); + BT_DBG("EraseUIDSettings, Name %s", name); + return bt_mesh_save_uid_settings(name, NULL, 0); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ /* API used to load BLE Mesh related settings */ @@ -297,10 +328,9 @@ static int settings_load(bt_mesh_nvs_handle_t handle, const char *key, { int err = 0; - if (key == NULL || buf == NULL || exist == NULL) { - BT_ERR("%s, Invalid parameter", __func__); - return -EINVAL; - } + BT_DBG("SettingsLoad, Handle %lu Key %s", handle, key); + + assert(buf && exist); err = nvs_get_blob(handle, key, buf, &buf_len); if (err != ESP_OK) { @@ -331,6 +361,10 @@ int bt_mesh_load_settings(bt_mesh_nvs_handle_t handle, const char *key, int bt_mesh_load_core_settings(const char *key, uint8_t *buf, size_t buf_len, bool *exist) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("LoadCoreSettings, Handle %lu Key %s", handle, key); + return bt_mesh_load_settings(handle, key, buf, buf_len, exist); } @@ -338,9 +372,13 @@ int bt_mesh_load_core_settings(const char *key, uint8_t *buf, size_t buf_len, bo int bt_mesh_load_uid_settings(const char *key, uint8_t *buf, size_t buf_len, bool *exist) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("LoadUIDSettings, Handle %lu Key %s", handle, key); + return bt_mesh_load_settings(handle, key, buf, buf_len, exist); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ /* API used to get length of BLE Mesh related settings */ @@ -349,10 +387,7 @@ static size_t settings_get_length(bt_mesh_nvs_handle_t handle, const char *key) size_t len = 0U; int err = 0; - if (key == NULL) { - BT_ERR("%s, Invalid parameter", __func__); - return 0; - } + BT_DBG("SettingsGetLength, Handle %lu Key %s", handle, key); err = nvs_get_blob(handle, key, NULL, &len); if (err != ESP_OK) { @@ -362,6 +397,8 @@ static size_t settings_get_length(bt_mesh_nvs_handle_t handle, const char *key) return 0; } + BT_DBG("Len %lu", len); + return len; } @@ -419,6 +456,10 @@ struct net_buf_simple *bt_mesh_get_settings_item(bt_mesh_nvs_handle_t handle, co struct net_buf_simple *bt_mesh_get_core_settings_item(const char *key) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("GetCoreSettingsItem, Handle %lu Key %s", handle, key); + return bt_mesh_get_settings_item(handle, key); } @@ -426,9 +467,13 @@ struct net_buf_simple *bt_mesh_get_core_settings_item(const char *key) struct net_buf_simple *bt_mesh_get_uid_settings_item(const char *key) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("GetUIDSettingsItem, Handle %lu Key %s", handle, key); + return bt_mesh_get_settings_item(handle, key); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ /* API used to check if the settings item exists */ @@ -438,6 +483,8 @@ bool bt_mesh_is_settings_item_exist(struct net_buf_simple *buf, const uint16_t v size_t length = 0U; int i; + BT_DBG("IsSettingsItemExist, Val 0x%04x", val); + if (!buf) { return false; } @@ -508,6 +555,10 @@ int bt_mesh_add_settings_item(bt_mesh_nvs_handle_t handle, const char *key, cons int bt_mesh_add_core_settings_item(const char *key, const uint16_t val) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("AddCoreSettingsItem, Handle %lu Val 0x%04x Key %s", handle, val, key); + return bt_mesh_add_settings_item(handle, key, val); } @@ -515,9 +566,13 @@ int bt_mesh_add_core_settings_item(const char *key, const uint16_t val) int bt_mesh_add_uid_settings_item(const char *key, const uint16_t val) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("AddUIDSettingsItem, Handle %lu Val 0x%04x Key %s", handle, val, key); + return bt_mesh_add_settings_item(handle, key, val); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ /* API used to remove the settings item */ @@ -580,6 +635,10 @@ int bt_mesh_remove_settings_item(bt_mesh_nvs_handle_t handle, const char *key, c int bt_mesh_remove_core_settings_item(const char *key, const uint16_t val) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_CORE); + + assert(key); + BT_DBG("RemoveCoreSettingsItem, Val 0x%04x Key %s", val, key); + return bt_mesh_remove_settings_item(handle, key, val); } @@ -587,14 +646,21 @@ int bt_mesh_remove_core_settings_item(const char *key, const uint16_t val) int bt_mesh_remove_uid_settings_item(const char *key, const uint16_t val) { bt_mesh_nvs_handle_t handle = settings_get_nvs_handle(SETTINGS_UID); + + assert(key); + BT_DBG("RemoveUIDSettingsItem, Val 0x%04x Key %s", val, key); + return bt_mesh_remove_settings_item(handle, key, val); } -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ int bt_mesh_settings_erase_key(bt_mesh_nvs_handle_t handle, const char *key) { int err = 0; + assert(key); + BT_DBG("SettingsEraseKey, Handle %lu Key %s", handle, key); + err = nvs_erase_key(handle, key); if (err != ESP_OK) { if (err == ESP_ERR_NVS_NOT_FOUND) { @@ -618,6 +684,8 @@ int bt_mesh_settings_erase_all(bt_mesh_nvs_handle_t handle) { int err = 0; + BT_DBG("SettingsEraseAll, Handle %lu", handle); + err = nvs_erase_all(handle); if (err != ESP_OK) { BT_ERR("Failed to erase all (err %d)", err); @@ -632,4 +700,5 @@ int bt_mesh_settings_erase_all(bt_mesh_nvs_handle_t handle) return 0; } + #endif /* CONFIG_BLE_MESH_SETTINGS */ diff --git a/components/bt/esp_ble_mesh/core/storage/settings_uid.c b/components/bt/esp_ble_mesh/core/storage/settings_uid.c index 511709f1ec..c6bbcf236e 100644 --- a/components/bt/esp_ble_mesh/core/storage/settings_uid.c +++ b/components/bt/esp_ble_mesh/core/storage/settings_uid.c @@ -38,15 +38,22 @@ static int settings_direct_erase(uint8_t index); static inline bool settings_uid_empty(struct settings_uid *uid) { - return (uid->id[0] == '\0') ? true : false; + bool empty = (uid->id[0] == '\0') ? true : false; + + BT_DBG("SettingsUIDEmpty, Empty %u", empty); + + return empty; } bt_mesh_nvs_handle_t get_core_settings_handle(void) { int i; + BT_DBG("GetCoreSettingsHandle"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { if (user_ids[i].open) { + BT_DBG("I %u Handle %lu", i, user_ids[i].handle); return user_ids[i].handle; } } @@ -59,6 +66,8 @@ int settings_uid_init(void) { int i; + BT_DBG("SettingsUIDInit"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { memset(&user_ids[i], 0, sizeof(struct settings_uid)); user_ids[i].handle = INVALID_SETTINGS_HANDLE; @@ -76,6 +85,8 @@ int settings_uid_load(void) int err = 0; int i; + BT_DBG("SettingsUIDLoad"); + /* Before using user id to search settings, we need to * restore all the settings user_ids properly. */ @@ -114,6 +125,8 @@ int settings_uid_deinit(bool erase) { int i; + BT_DBG("SettingsUIDDeinit, Erase %u", erase); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { memset(&user_ids[i], 0, offsetof(struct settings_uid, handle)); /* Can not reset handle here, since it will be used @@ -128,6 +141,8 @@ int settings_uid_erase(void) { int i; + BT_DBG("SettingsUIDErase"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { if (user_ids[i].open == true) { /* When a nvs namespace is open, which means it is @@ -158,6 +173,8 @@ static int settings_direct_erase(uint8_t index) char name[16] = {'\0'}; int err = 0; + BT_DBG("SettingsDirectErase, Index %u", index); + sprintf(name, "%s_%02x", "mesh_core", index); /* Get handle for core settings */ @@ -191,6 +208,8 @@ static uint8_t settings_index_get(const char *id, uint8_t *index) uint8_t idx = 0; int i; + BT_DBG("SettingsIndexGet"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { if (strlen(user_ids[i].id) != strlen(id)) { continue; @@ -206,6 +225,8 @@ static uint8_t settings_index_get(const char *id, uint8_t *index) idx = INVALID_SETTINGS_INDEX; } + BT_DBG("Index %u", idx); + if (index) { *index = idx; } @@ -219,6 +240,8 @@ static int settings_open(uint8_t index) int err = 0; int i; + BT_DBG("SettingsOpen, Index %u UID %s", index, uid->id); + /* Check if the nvs namespace is already open */ if (uid->open == true) { BT_WARN("Settings already open, index %d", index); @@ -251,8 +274,6 @@ static int settings_open(uint8_t index) sprintf(uid->id, "%04x", index); } - BT_INFO("Open settings, index %d, uid %s", index, uid->id); - sprintf(name, "mesh/id/%04x", index); err = bt_mesh_save_uid_settings(name, (const uint8_t *)uid->id, SETTINGS_UID_SIZE); if (err) { @@ -288,6 +309,8 @@ static int settings_open(uint8_t index) int bt_mesh_provisioner_open_settings_with_index(uint8_t index) { + BT_DBG("PvnrOpenSettingsWithIndex, Index %u", index); + if (index >= ARRAY_SIZE(user_ids)) { BT_ERR("Invalid settings index %d", index); return -EINVAL; @@ -301,6 +324,8 @@ int bt_mesh_provisioner_open_settings_with_uid(const char *id, uint8_t *index) uint8_t idx = 0; int i; + BT_DBG("PvnrOpenSettingsWithUID"); + if (!id || strlen(id) > SETTINGS_UID_SIZE) { BT_ERR("Invalid settings uid"); return -EINVAL; @@ -328,6 +353,8 @@ int bt_mesh_provisioner_open_settings_with_uid(const char *id, uint8_t *index) idx = i; } + BT_DBG("Index %u", idx); + return settings_open(idx); } @@ -337,13 +364,14 @@ static int settings_close(uint8_t index, bool erase) char name[16] = {'\0'}; int err = 0; + BT_DBG("SettingsClose"); + BT_DBG("Index %u Erase %u UID %s", index, erase, uid->id); + if (uid->open == false) { BT_ERR("Settings not open, index %d", index); return -EIO; } - BT_INFO("Close settings, index %d, uid %s", index, uid->id); - /* Disable Provisioner firstly */ err = bt_mesh_provisioner_disable(BLE_MESH_PROV_ADV | BLE_MESH_PROV_GATT); if (err && err != -EALREADY) { @@ -378,6 +406,8 @@ static int settings_close(uint8_t index, bool erase) int bt_mesh_provisioner_close_settings_with_index(uint8_t index, bool erase) { + BT_DBG("PvnrCloseSettingsWithIndex, Index %u Erase %u", index, erase); + if (index >= ARRAY_SIZE(user_ids)) { BT_ERR("Invalid settings index %d", index); return -EINVAL; @@ -390,6 +420,8 @@ int bt_mesh_provisioner_close_settings_with_uid(const char *id, bool erase, uint { uint8_t idx = 0; + BT_DBG("PvnrCloseSettingsWithUID, Erase %u", erase); + if (!id || strlen(id) > SETTINGS_UID_SIZE) { BT_ERR("Invalid settings uid"); return -EINVAL; @@ -401,6 +433,8 @@ int bt_mesh_provisioner_close_settings_with_uid(const char *id, bool erase, uint return -ENODEV; } + BT_DBG("Index %u ID %s", idx, id); + return settings_close(idx, erase); } @@ -412,13 +446,13 @@ static int settings_delete(uint8_t index) */ struct settings_uid *uid = &user_ids[index]; + BT_DBG("SettingsDelete, Index %u UID %s", index, uid->id); + if (uid->open == true) { BT_ERR("Settings being used, index %d", index); return -EBUSY; } - BT_INFO("Delete settings, index %d, uid %s", index, uid->id); - settings_direct_erase(index); memset(uid, 0, sizeof(struct settings_uid)); @@ -429,6 +463,8 @@ static int settings_delete(uint8_t index) int bt_mesh_provisioner_delete_settings_with_index(uint8_t index) { + BT_DBG("PvnrDeleteSettingsWithIndex, Index %u", index); + if (index >= ARRAY_SIZE(user_ids)) { BT_ERR("Invalid settings index %d", index); return -EINVAL; @@ -441,6 +477,8 @@ int bt_mesh_provisioner_delete_settings_with_uid(const char *id, uint8_t *index) { uint8_t idx = 0; + BT_DBG("PvnrDeleteSettingsWithUID"); + if (!id || strlen(id) > SETTINGS_UID_SIZE) { BT_ERR("Invalid settings uid"); return -EINVAL; @@ -452,16 +490,22 @@ int bt_mesh_provisioner_delete_settings_with_uid(const char *id, uint8_t *index) return -ENODEV; } + BT_DBG("Index %u ID %s", idx, id); + return settings_delete(idx); } const char *bt_mesh_provisioner_get_settings_uid(uint8_t index) { + BT_DBG("PvnrGetSettingsUID, Index %u", index); + if (index >= ARRAY_SIZE(user_ids)) { BT_ERR("Invalid settings index %d", index); return NULL; } + BT_DBG("ID %s", user_ids[index].id); + return user_ids[index].id; } @@ -469,6 +513,8 @@ uint8_t bt_mesh_provisioner_get_settings_index(const char *id) { uint8_t idx = 0; + BT_DBG("PvnrGetSettingsIndex"); + if (!id || strlen(id) > SETTINGS_UID_SIZE) { BT_ERR("Invalid settings uid"); return INVALID_SETTINGS_INDEX; @@ -479,6 +525,8 @@ uint8_t bt_mesh_provisioner_get_settings_index(const char *id) BT_ERR("Settings uid %s not exists", id); } + BT_DBG("Index %u ID %s", idx, id); + return idx; } @@ -487,12 +535,16 @@ uint8_t bt_mesh_provisioner_get_free_settings_count(void) uint8_t count = 0; int i; + BT_DBG("PvnrGetFreeSettingsCount"); + for (i = 0; i < ARRAY_SIZE(user_ids); i++) { if (settings_uid_empty(&user_ids[i])) { count++; } } + BT_DBG("Count %u", count); + return count; } #endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ @@ -503,6 +555,8 @@ int bt_mesh_provisioner_direct_erase_settings(void) bt_mesh_nvs_handle_t handle = 0; int err = 0; + BT_DBG("PvnrDirectEraseSettings"); + err = bt_mesh_settings_direct_open(&handle); if (err) { return err; @@ -514,9 +568,9 @@ int bt_mesh_provisioner_direct_erase_settings(void) } bt_mesh_erase_uid_settings("mesh/uid"); -#else +#else /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ err = bt_mesh_settings_erase_all(handle); -#endif +#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */ bt_mesh_settings_direct_close(); return err; diff --git a/components/bt/esp_ble_mesh/core/test.c b/components/bt/esp_ble_mesh/core/test.c index 3d3cc3bbd9..6433f9c0d4 100644 --- a/components/bt/esp_ble_mesh/core/test.c +++ b/components/bt/esp_ble_mesh/core/test.c @@ -41,6 +41,8 @@ int bt_mesh_device_auto_enter_network(struct bt_mesh_device_network_info *info) int i, j, k; int err = 0; + BT_DBG("DeviceAutoEnterNetwork"); + if (info == NULL || !BLE_MESH_ADDR_IS_UNICAST(info->unicast_addr) || !BLE_MESH_ADDR_IS_GROUP(info->group_addr)) { return -EINVAL; @@ -139,6 +141,8 @@ int bt_mesh_test_update_white_list(struct bt_mesh_white_list *wl) { int err = 0; + BT_DBG("TestUpdateWhiteList"); + if (wl == NULL) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -157,7 +161,7 @@ int bt_mesh_test_update_white_list(struct bt_mesh_white_list *wl) int bt_mesh_test_start_scanning(bool wl_en) { - BT_INFO("Scan with filter policy %s", wl_en ? "enabled" : "disabled"); + BT_DBG("TestStartScanning, wl_en %u", wl_en); if (wl_en) { return bt_mesh_scan_with_wl_enable(); @@ -168,6 +172,8 @@ int bt_mesh_test_start_scanning(bool wl_en) int bt_mesh_test_stop_scanning(void) { + BT_DBG("TestStopScanning"); + return bt_mesh_scan_disable(); } #endif /* CONFIG_BLE_MESH_TEST_USE_WHITE_LIST */ @@ -181,6 +187,8 @@ void bt_mesh_test_register_net_pdu_cb(bt_mesh_test_net_pdu_cb_t cb) void bt_mesh_test_set_seq(uint32_t seq) { + BT_DBG("TestSetSeq, Seq 0x%06x", seq); + if (seq > 0xFFFFFF) { BT_ERR("Invalid SEQ 0x%08x", seq); return; diff --git a/components/bt/esp_ble_mesh/core/transport.c b/components/bt/esp_ble_mesh/core/transport.c index 797ff2a1ad..62704ccfa8 100644 --- a/components/bt/esp_ble_mesh/core/transport.c +++ b/components/bt/esp_ble_mesh/core/transport.c @@ -29,7 +29,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ /* The transport layer needs at least three buffers for itself to avoid * deadlocks. Ensure that there are a sufficient number of advertising @@ -58,24 +58,24 @@ _Static_assert(CONFIG_BLE_MESH_ADV_BUF_COUNT >= (CONFIG_BLE_MESH_TX_SEG_MAX + 3) /* Number of retransmit attempts (after the initial transmit) per segment */ #define SEG_RETRANSMIT_ATTEMPTS 4 +/* How long to wait for available buffers before giving up */ +#define BUF_TIMEOUT K_NO_WAIT + /* "This timer shall be set to a minimum of 200 + 50 * TTL milliseconds.". * We use 400 since 300 is a common send duration for standard HCI, and we * need to have a timeout that's bigger than that. */ #define SEG_RETRANSMIT_TIMEOUT_UNICAST(tx) (K_MSEC(400) + 50 * (tx)->ttl) + /* When sending to a group, the messages are not acknowledged, and there's no * reason to delay the repetitions significantly. Delaying by more than 0 ms * to avoid flooding the network. */ #define SEG_RETRANSMIT_TIMEOUT_GROUP K_MSEC(50) -#define SEG_RETRANSMIT_TIMEOUT(tx) \ - (BLE_MESH_ADDR_IS_UNICAST((tx)->dst) ? \ - SEG_RETRANSMIT_TIMEOUT_UNICAST(tx) : \ - SEG_RETRANSMIT_TIMEOUT_GROUP) - -/* How long to wait for available buffers before giving up */ -#define BUF_TIMEOUT K_NO_WAIT +#define SEG_RETRANSMIT_TIMEOUT(tx) (BLE_MESH_ADDR_IS_UNICAST((tx)->dst) ? \ + SEG_RETRANSMIT_TIMEOUT_UNICAST(tx) : \ + SEG_RETRANSMIT_TIMEOUT_GROUP) struct seg_info { uint8_t ctl:1; /* Control message */ @@ -160,6 +160,8 @@ static inline void bt_mesh_seg_rx_unlock(void) uint8_t bt_mesh_get_seg_rtx_num(void) { + BT_DBG("SegRTXNum %u", SEG_RETRANSMIT_ATTEMPTS); + return SEG_RETRANSMIT_ATTEMPTS; } @@ -174,6 +176,9 @@ int32_t bt_mesh_get_seg_rtx_timeout(uint16_t dst, uint8_t ttl) struct seg_tx tx = { .ttl = ttl, }; + + BT_DBG("SegRTXTimeout, TTL %u", ttl); + return SEG_RETRANSMIT_TIMEOUT_UNICAST(&tx); } @@ -184,8 +189,10 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, struct net_buf *buf = NULL; enum bt_mesh_adv_type adv_type = BLE_MESH_ADV_DATA; - BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x sdu_len %u", - tx->src, tx->ctx->addr, tx->ctx->app_idx, sdu->len); + BT_DBG("SendUnseg"); + BT_DBG("Src 0x%04x Dst 0x%04x AppIdx 0x%04x CtlOp 0x%02x SduLen %u", + tx->src, tx->ctx->addr, tx->ctx->app_idx, + ctl_op ? *ctl_op : 0xFF, sdu->len); #if CONFIG_BLE_MESH_EXT_ADV #if CONFIG_BLE_MESH_LONG_PACKET @@ -240,13 +247,14 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, tx->src, tx->ctx->addr, NULL, 1)) { + BT_WARN("NoSpaceInFrndQueue, SegCount 1"); + if (BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - BT_ERR("Not enough space in Friend Queue"); + BT_ERR("NotSentToUnicast"); net_buf_unref(buf); return -ENOBUFS; } - BT_WARN("No space in Friend Queue"); goto send; } @@ -256,6 +264,8 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, /* PDUs for a specific Friend should only go * out through the Friend Queue. */ + BT_DBG("FrndTxEnqueued, SegCount 1"); + net_buf_unref(buf); send_cb_finalize(cb, cb_data); return 0; @@ -268,19 +278,25 @@ send: static inline uint8_t seg_len(struct seg_info *si) { + uint8_t len = 0; + if (si->ctl) { - return + len = #if CONFIG_BLE_MESH_LONG_PACKET si->long_pkt ? BLE_MESH_EXT_CTL_SEG_SDU_MAX : #endif BLE_MESH_CTL_SEG_SDU_MAX; + } else { + len = +#if CONFIG_BLE_MESH_LONG_PACKET + si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : +#endif + BLE_MESH_APP_SEG_SDU_MAX; } - return -#if CONFIG_BLE_MESH_LONG_PACKET - si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : -#endif - BLE_MESH_APP_SEG_SDU_MAX; + BT_DBG("SegLen %u", len); + + return len; } bool bt_mesh_tx_in_progress(void) @@ -289,15 +305,18 @@ bool bt_mesh_tx_in_progress(void) for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { if (seg_tx[i].nack_count) { + BT_DBG("SegTxInProgress"); return true; } } + BT_DBG("SegTxNotInProgress"); return false; } static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) { + BT_DBG("SegTxDone, SegIdx %u", seg_idx); /* If the data is sent to itself, then last seg's ref count be equal to 3 */ if (((IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) || (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) && bt_mesh_is_provisioner_en())) && @@ -307,15 +326,17 @@ static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) bt_mesh_adv_buf_ref_debug(__func__, tx->seg[seg_idx], 3U, BLE_MESH_BUF_REF_SMALL); } - /** - * When cancelling a segment that is still in the adv sending queue, `tx->seg_pending` - * must else be decremented by one. More detailed information - * can be found in BLEMESH24-26. + /* When cancelling a segment that is still in the adv sending queue, + * the `tx->seg_pending` must be decremented by one. + * More details could be found in BLEMESH24-26. */ if (bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(tx->seg[seg_idx]), 1, 0)) { + BT_DBG("SegPendingDec %u", tx->seg_pending); tx->seg_pending--; } + BT_DBG("NackCountDec %u", tx->nack_count); + net_buf_unref(tx->seg[seg_idx]); tx->seg[seg_idx] = NULL; tx->nack_count--; @@ -325,6 +346,8 @@ static void seg_tx_reset(struct seg_tx *tx) { int i; + BT_DBG("SegTxReset"); + bt_mesh_seg_tx_lock(tx); k_delayed_work_cancel(&tx->rtx_timer); @@ -349,6 +372,7 @@ static void seg_tx_reset(struct seg_tx *tx) if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_IVU_PENDING)) { BT_DBG("Proceeding with pending IV Update"); + /* bt_mesh_net_iv_update() will re-enable the flag if this * wasn't the only transfer. */ @@ -363,6 +387,8 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err) const struct bt_mesh_send_cb *cb = tx->cb; void *cb_data = tx->cb_data; + BT_DBG("SegTxComplete, Err %d", err); + seg_tx_reset(tx); /* TODO: notify the completion of sending segmented message */ @@ -374,29 +400,36 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err) static void schedule_retransmit(struct seg_tx *tx) { - /* It's possible that a segment broadcast hasn't finished, - * but the tx are already released. Only the seg_pending - * of this segment remains unprocessed. So, here, we - * determine if the tx are released by checking if the - * destination (dst) is unassigned, and then process - * the seg_pending of this segment. + /* It's possible that a segment broadcast hasn't finished, but the tx + * has already been released. Only the seg_pending of this segment + * remains unprocessed. + * So, here we determine if the tx are released by checking if the + * destination (dst) is unassigned, and then process the seg_pending + * of this segment. * See BLEMESH25-92 for details */ + BT_DBG("ScheduleRetransmit, Dst 0x%04x", tx->dst); + bt_mesh_seg_tx_lock(tx); if (tx->dst == BLE_MESH_ADDR_UNASSIGNED) { + BT_DBG("SegPending %u", tx->seg_pending); + if (tx->seg_pending) { tx->seg_pending--; } goto end; } + BT_DBG("SegPending %u Attempts %u", tx->seg_pending, tx->attempts); + if (--tx->seg_pending) { goto end; } if (!BLE_MESH_ADDR_IS_UNICAST(tx->dst) && !tx->attempts) { - BT_INFO("Complete tx sdu to group"); + BT_INFO("TxSduToGroupDone"); + seg_tx_complete(tx, 0); goto end; } @@ -411,6 +444,8 @@ static void seg_first_send_start(uint16_t duration, int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegFirstSendStart, Err %d", err); + if (tx->cb && tx->cb->start) { tx->cb->start(duration, err, tx->cb_data); } @@ -420,6 +455,8 @@ static void seg_send_start(uint16_t duration, int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegSendStart, Err %d", err); + /* If there's an error in transmitting the 'sent' callback will never * be called. Make sure that we kick the retransmit timer also in this * case since otherwise we risk the transmission of becoming stale. @@ -433,6 +470,8 @@ static void seg_sent(int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegSent, Err %d", err); + schedule_retransmit(tx); } @@ -450,17 +489,19 @@ static void seg_tx_send_unacked(struct seg_tx *tx) { int i, err = 0; + BT_DBG("SegTxSendUnacked, Attempts %u", tx->attempts); + bt_mesh_seg_tx_lock(tx); if (!(tx->attempts--)) { BT_WARN("Ran out of retransmit attempts"); + bt_mesh_seg_tx_unlock(tx); + seg_tx_complete(tx, -ETIMEDOUT); return; } - BT_INFO("Attempts: %u", tx->attempts); - for (i = 0; i <= tx->seg_n; i++) { struct net_buf *seg = tx->seg[i]; @@ -473,9 +514,10 @@ static void seg_tx_send_unacked(struct seg_tx *tx) continue; } - tx->seg_pending++; + BT_INFO("SegPendingInc %u", tx->seg_pending); + BT_INFO("SegResend %u/%u Cred %u", i, tx->seg_n, tx->cred); - BT_INFO("Resending %u/%u, cred 0x%02x", i, tx->seg_n, tx->cred); + tx->seg_pending++; /* TODO: * tx->new_key should be replaced with sub->kr_flag, @@ -486,8 +528,10 @@ static void seg_tx_send_unacked(struct seg_tx *tx) &tx->cred, tx->tag, &seg_sent_cb, tx); if (err) { - BT_ERR("Sending segment failed"); + BT_ERR("ResendSegFailed, Err %d", err); + bt_mesh_seg_tx_unlock(tx); + seg_tx_complete(tx, -EIO); return; } @@ -500,6 +544,8 @@ static void seg_retransmit(struct k_work *work) { struct seg_tx *tx = CONTAINER_OF(work, struct seg_tx, rtx_timer); + BT_DBG("SegRetransmit"); + seg_tx_send_unacked(tx); } @@ -516,20 +562,24 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, int err = 0; int i; - BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x aszmic %u sdu_len %u", + BT_DBG("SendSeg"); + BT_DBG("Src 0x%04x Dst 0x%04x AppIdx 0x%04x Aszmic %u SduLen %u", net_tx->src, net_tx->ctx->addr, net_tx->ctx->app_idx, net_tx->aszmic, sdu->len); for (tx = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) { - if (!seg_tx[i].nack_count && - /* In some critical conditions, the tx might be - * reset before a segment broadcast is finished. - * If this happens, the seg_pending of the segment - * hasn't been processed. To avoid assigning this - * uncleared tx to a new message, extra checks for - * seg_pending being 0 are added. See BLEMESH25-92 - * for details.*/ - !seg_tx[i].seg_pending) { + /* In some critical conditions, the tx might be reset before + * a segment transmission is finished. + * If this happens, the seg_pending of the segment will not + * be processed. + * And to avoid assigning this uncleared tx to a new message, + * extra checks for seg_pending being 0 are added. + * See BLEMESH25-92 for details. + */ + BT_DBG("Seg%u: NackCount %u SegPending %u", + i, seg_tx[i].nack_count, seg_tx[i].seg_pending); + + if (!seg_tx[i].nack_count && !seg_tx[i].seg_pending) { tx = &seg_tx[i]; break; } @@ -585,15 +635,16 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, seq_zero = tx->seq_auth & TRANS_SEQ_ZERO_MASK; - BT_DBG("SeqZero 0x%04x", seq_zero); + BT_DBG("SegHdr 0x%02x SegN %u NackCount %u NewKey %u TTL %u SeqZero 0x%04x", + seg_hdr, tx->seg_n, tx->nack_count, tx->new_key, tx->ttl, seq_zero); if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_friend_queue_has_space(tx->sub->net_idx, net_tx->src, tx->dst, &tx->seq_auth, tx->seg_n + 1) && BLE_MESH_ADDR_IS_UNICAST(tx->dst)) { - BT_ERR("Not enough space in Friend Queue for %u segments", - tx->seg_n + 1); + BT_WARN("NoSpaceInFrndQueue, SegCount %u", tx->seg_n + 1); + seg_tx_reset(tx); return -ENOBUFS; } @@ -659,6 +710,8 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, type = BLE_MESH_FRIEND_PDU_PARTIAL; } + BT_DBG("FrndPDUType %u", type); + if (bt_mesh_friend_enqueue_tx(net_tx, type, &tx->seq_auth, tx->seg_n + 1, @@ -667,6 +720,8 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, /* PDUs for a specific Friend should only go * out through the Friend Queue. */ + BT_DBG("FrndTxEnqueued, SegCount %u", tx->seg_n + 1); + net_buf_unref(seg); continue; } @@ -674,14 +729,16 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, tx->seg[seg_o] = net_buf_ref(seg); - BT_DBG("Sending %u/%u", seg_o, tx->seg_n); + BT_INFO("SegPendingInc %u", tx->seg_pending); + BT_INFO("SegSend %u/%u Cred %u", seg_o, tx->seg_n, tx->cred); + tx->seg_pending++; err = bt_mesh_net_send(net_tx, seg, seg_o ? &seg_sent_cb : &first_sent_cb, tx); if (err) { - BT_ERR("Sending segment failed (err %d)", err); + BT_ERR("SendSegFailed, Err %d", err); break; } @@ -690,6 +747,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, * which will be used for retransmission later. */ if (tx->cred != net_tx->ctx->send_cred) { + BT_INFO("OldCred %u NewCred %u", tx->cred, net_tx->ctx->send_cred); tx->cred = net_tx->ctx->send_cred; } } @@ -703,7 +761,10 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, /* This can happen if segments only went into the Friend Queue */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !tx->seg[0]) { + BT_DBG("OnlyToFrndQueue"); + seg_tx_reset(tx); + /* If there was a callback notify sending immediately since * there's no other way to track this (at least currently) * with the Friend Queue. @@ -727,6 +788,8 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, uint8_t aid = 0U; int err = 0; + BT_DBG("TransSend"); + if (msg->len < 1) { BT_ERR("Zero-length SDU not allowed"); return -EINVAL; @@ -752,9 +815,9 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, } #endif - BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->sub->net_idx, - tx->ctx->app_idx, tx->ctx->addr); - BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Dst 0x%04x", + tx->sub->net_idx, tx->ctx->app_idx, tx->ctx->addr); + BT_DBG("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); err = bt_mesh_upper_key_get(tx->sub, tx->ctx->app_idx, &key, &aid, tx->ctx->addr); @@ -772,7 +835,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, tx->aszmic = 1U; } - BT_INFO("%s, send_tag 0x%02x, send_szmic %d, aszmic %d", + BT_INFO("%s, Tag 0x%02x Szmic %u Aszmic %u", bt_mesh_tag_send_segmented(tx->ctx->send_tag) ? "Seg" : "Unseg", tx->ctx->send_tag, tx->ctx->send_szmic, tx->aszmic); @@ -787,7 +850,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, tx->ctx->addr, bt_mesh.seq, BLE_MESH_NET_IVI_TX); if (err) { - BT_ERR("Encrypt failed (err %d)", err); + BT_ERR("AppEncryptFailed, Err %d", err); return err; } @@ -801,7 +864,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, static void revoke_dev_key(const uint8_t *dev_key) { if (!memcmp(dev_key, bt_mesh.dev_key_ca, 16)) { - BT_INFO("Revoke Device Key"); + BT_INFO("RevokeDevKey"); memcpy(bt_mesh.dev_key, bt_mesh.dev_key_ca, 16); memset(bt_mesh.dev_key_ca, 0, 16); @@ -822,8 +885,9 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, size_t i = 0U; int err = 0; - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); - BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("SduRecv"); + BT_DBG("Aszmic %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->len < 1 + APP_MIC_LEN(aszmic)) { BT_ERR("Too short SDU + MIC (len %u)", buf->len); @@ -862,7 +926,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, dev_key = bt_mesh_rx_devkey_get(i, rx->ctx.addr); if (!dev_key) { - BT_DBG("DevKey not found"); + BT_DBG("DevKeyNotFound"); continue; } @@ -873,6 +937,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, rx->ctx.recv_dst, seq, BLE_MESH_NET_IVI_RX(rx)); if (err) { + BT_DBG("DevKeyNotDecrypt"); continue; } @@ -898,6 +963,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } BT_WARN("Unable to decrypt with DevKey"); + bt_mesh_free_buf(sdu); return -ENODEV; } @@ -910,7 +976,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, key = bt_mesh_rx_appkey_get(i); if (!key) { - BT_DBG("AppKey not found"); + BT_DBG("AppKeyNotFound"); continue; } @@ -944,8 +1010,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, bt_hex(sdu->data, sdu->len)); if (err) { - BT_DBG("Unable to decrypt with AppKey 0x%03x", - key->app_idx); + BT_DBG("AppKeyNotDecrypt, AppIdx 0x%04x", key->app_idx); continue; } @@ -957,8 +1022,9 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } if (rx->local_match) { - BT_WARN("No matching AppKey"); + BT_WARN("NoMatchAppKey"); } + bt_mesh_free_buf(sdu); return 0; } @@ -968,6 +1034,8 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, uint16_t add struct seg_tx *tx = NULL; int i; + BT_DBG("SegTxLookup, SeqZero 0x%04x OBO %u Addr 0x%04x", seq_zero, obo, addr); + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { tx = &seg_tx[i]; @@ -976,6 +1044,7 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, uint16_t add } if (tx->dst == addr) { + BT_DBG("SegTxFound, Dst 0x%04x", addr); return tx; } @@ -985,6 +1054,7 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, uint16_t add * responding and therefore accept the message. */ if (obo && tx->nack_count == tx->seg_n + 1) { + BT_DBG("SegTxOboFound, Dst 0x%04x", addr); tx->dst = addr; return tx; } @@ -997,11 +1067,13 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, struct net_buf_simple *buf, uint64_t *seq_auth) { struct seg_tx *tx = NULL; + uint16_t seq_zero = 0U; unsigned int bit = 0; uint32_t ack = 0U; - uint16_t seq_zero = 0U; uint8_t obo = 0U; + BT_DBG("TransAck"); + if (buf->len != 6) { BT_ERR("Malformed Segment Ack (len %u)", buf->len); return -EINVAL; @@ -1020,7 +1092,7 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, ack = net_buf_simple_pull_be32(buf); - BT_DBG("OBO %u seq_zero 0x%04x ack 0x%08x", obo, seq_zero, ack); + BT_DBG("OBO %u SeqZero 0x%04x Ack 0x%08lx", obo, seq_zero, ack); tx = seg_tx_lookup(seq_zero, obo, rx->ctx.addr); if (!tx) { @@ -1051,6 +1123,7 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, while ((bit = find_lsb_set(ack))) { if (tx->seg[bit - 1]) { BT_INFO("Seg %u/%u acked", bit - 1, tx->seg_n); + bt_mesh_seg_tx_lock(tx); seg_tx_done(tx, bit - 1); bt_mesh_seg_tx_unlock(tx); @@ -1075,6 +1148,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, uint8_t init_ttl = 0U, hops = 0U; uint16_t feat = 0U; + BT_DBG("TransHeartbeat"); + if (buf->len != 3) { BT_ERR("Malformed heartbeat message (len %u)", buf->len); return -EINVAL; @@ -1091,9 +1166,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, hops = (init_ttl - rx->ctx.recv_ttl + 1); - BT_INFO("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x", - rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, - (hops == 1U) ? "" : "s", feat); + BT_INFO("Src 0x%04x TTL %u InitTTL %u Hops %u Feat 0x%04x", + rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, feat); if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { bt_mesh_heartbeat_recv(rx->ctx.addr, rx->ctx.recv_dst, hops, feat); @@ -1111,7 +1185,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, { uint8_t ctl_op = TRANS_CTL_OP(&hdr); - BT_DBG("OpCode 0x%02x len %u", ctl_op, buf->len); + BT_DBG("CTLRecv, OpCode 0x%02x Len %u", ctl_op, buf->len); BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, @@ -1128,6 +1202,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, /* Only acks and heartbeats may need processing without local_match */ if (!rx->local_match) { + BT_DBG("LocalNotMatch"); return 0; } @@ -1142,7 +1217,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, case TRANS_CTL_OP_PATH_REQ_SOLIC: return bt_mesh_directed_forwarding_ctl_recv(ctl_op, rx, buf); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_lpn_established()) { switch (ctl_op) { @@ -1195,7 +1270,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, { uint8_t hdr = 0U; - BT_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data)); + BT_DBG("TransUnseg, AKF %u AID 0x%02x", AKF(buf->data), AID(buf->data)); if (buf->len < 1) { BT_ERR("Too small unsegmented PDU"); @@ -1203,7 +1278,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, } if (bt_mesh_rpl_check(rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", rx->ctx.addr, rx->ctx.recv_dst, rx->seq); return -EINVAL; } @@ -1216,6 +1291,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, /* SDUs must match a local element or an LPN of this Friend. */ if (!rx->local_match && !rx->friend_match) { + BT_DBG("LocalAndFrndNotMatch"); return 0; } @@ -1241,6 +1317,8 @@ static inline int32_t ack_timeout(struct seg_rx *rx) /* 100 ms for every not yet received segment */ to += K_MSEC(((rx->seg_n + 1) - popcount(rx->block)) * 100U); + BT_DBG("AckTimeout, TTL %u TO %ld", ttl, to); + /* Make sure we don't send more frequently than the duration for * each packet (default is 300ms). */ @@ -1253,6 +1331,8 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, { struct net_buf_simple buf = {0}; + BT_DBG("CtlSend"); + net_buf_simple_init_with_data(&buf, data, data_len); if (data_len > BLE_MESH_SDU_UNSEG_MAX) { @@ -1262,9 +1342,9 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, /* Set app_idx to unused here since CTL is only encrypted with NetKey */ tx->ctx->app_idx = BLE_MESH_KEY_UNUSED; - BT_DBG("src 0x%04x dst 0x%04x ttl 0x%02x ctl 0x%02x", tx->src, - tx->ctx->addr, tx->ctx->send_ttl, ctl_op); - BT_DBG("len %zu: %s", data_len, bt_hex(data, data_len)); + BT_DBG("Src 0x%04x Dst 0x%04x TTL 0x%02x CTL 0x%02x", + tx->src, tx->ctx->addr, tx->ctx->send_ttl, ctl_op); + BT_DBG("Len %u: %s", data_len, bt_hex(data, data_len)); if (bt_mesh_tag_send_segmented(tx->ctx->send_tag)) { return send_seg(tx, &buf, cb, cb_data, &ctl_op); @@ -1296,7 +1376,7 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, uint16_t seq_zero = *seq_auth & TRANS_SEQ_ZERO_MASK; uint8_t buf[6] = {0}; - BT_DBG("SeqZero 0x%04x Block 0x%08x OBO %u", seq_zero, block, obo); + BT_DBG("SendAck, SeqZero 0x%04x Block 0x%08lx OBO %u", seq_zero, block, obo); if (bt_mesh_lpn_established()) { BT_WARN("Not sending ack when LPN is enabled"); @@ -1320,6 +1400,8 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, static void seg_rx_reset(struct seg_rx *rx, bool full_reset) { + BT_DBG("SegRxReset, FullReset %u", full_reset); + bt_mesh_seg_rx_lock(); k_delayed_work_cancel(&rx->ack_timer); @@ -1364,6 +1446,8 @@ static uint32_t incomplete_timeout(struct seg_rx *rx) /* The less segments being received, the shorter timeout will be used. */ timeout += K_MSEC(ttl * popcount(rx->block) * 100U); + BT_DBG("IncompleteTimeout %lu", timeout); + return MIN(timeout, K_SECONDS(60)); } @@ -1371,11 +1455,15 @@ static void seg_ack(struct k_work *work) { struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack_timer); + BT_DBG("SegAck, Last %lu", rx->last); + bt_mesh_seg_rx_lock(); if (k_uptime_get_32() - rx->last > incomplete_timeout(rx)) { BT_WARN("Incomplete timer expired"); + bt_mesh_seg_rx_unlock(); + seg_rx_reset(rx, false); return; } @@ -1398,6 +1486,8 @@ static void seg_ack(struct k_work *work) static inline uint16_t sdu_len_max(uint8_t seg_n,uint16_t seg_len) { + BT_DBG("IsSduLenOK,Len:%u,SegN:%u", seg_len, seg_n); + return ((seg_n + 1) * seg_len); } @@ -1406,6 +1496,9 @@ static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n, uint16_t buf_len) struct seg_info si = { .ctl = ctl, }; + + BT_DBG("IsSduLenOK, CTL %u SegN %u", ctl, seg_n); + #if CONFIG_BLE_MESH_LONG_PACKET if ((sdu_len_max(seg_n, buf_len) > CONFIG_BLE_MESH_RX_SDU_MAX)) { si.long_pkt = 1; @@ -1422,8 +1515,13 @@ static struct seg_rx *seg_rx_find_with_buf(struct bt_mesh_net_rx *net_rx, { int i; + BT_DBG("SegRxFind, SeqAuth 0x%llx", *seq_auth); for (i = 0; i < rx_buf_size; i++) { struct seg_rx *rx = &rx_buf[i]; + + BT_DBG("Seg%u/%u: Src 0x%04x Dst 0x%04x SeqAuth 0x%llx", + i, rx->seg_n, rx->src, rx->dst, rx->seq_auth); + if (rx->src != net_rx->ctx.addr || rx->dst != net_rx->ctx.recv_dst) { continue; @@ -1434,9 +1532,9 @@ static struct seg_rx *seg_rx_find_with_buf(struct bt_mesh_net_rx *net_rx, */ #if CONFIG_BLE_MESH_DISCARD_OLD_SEQ_AUTH if (rx->seq_auth >= *seq_auth) { -#else +#else /* CONFIG_BLE_MESH_DISCARD_OLD_SEQ_AUTH */ if (rx->seq_auth == *seq_auth) { -#endif +#endif /* CONFIG_BLE_MESH_DISCARD_OLD_SEQ_AUTH */ return rx; } @@ -1517,6 +1615,8 @@ static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, static bool seg_rx_is_valid(struct seg_rx *rx, struct bt_mesh_net_rx *net_rx, const uint8_t *hdr, uint8_t seg_n) { + BT_DBG("IsSegRxValid"); + if (rx->hdr != *hdr || rx->seg_n != seg_n) { BT_ERR("Invalid segment for ongoing session"); return false; @@ -1557,6 +1657,8 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, } #endif + BT_DBG("SegRxAlloc, SegN %u", seg_n); + for (i = 0; i < rx_buf_size; i++) { struct seg_rx *rx = &seg_rx_buf[i]; @@ -1601,18 +1703,20 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, uint8_t seg_o = 0U; int err = 0; + BT_DBG("TransSeg"); + if (buf->len < 5) { BT_ERR("Too short segmented message (len %u)", buf->len); return -EINVAL; } if (bt_mesh_rpl_check(net_rx, &rpl)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", net_rx->ctx.addr, net_rx->ctx.recv_dst, net_rx->seq); return -EINVAL; } - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); + BT_DBG("Aszmic %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); net_buf_simple_pull(buf, 1); @@ -1657,13 +1761,15 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, *seg_count = seg_n + 1; + BT_DBG("Src 0x%04x Dst 0x%04x SeqAuth 0x%llx SegCount %u", + net_rx->ctx.addr, net_rx->ctx.recv_dst, *seq_auth, *seg_count); + /* Look for old RX sessions */ rx = seg_rx_find(net_rx, seq_auth); if (rx) { /* Discard old SeqAuth packet */ if (rx->seq_auth > *seq_auth) { - BT_WARN("Ignoring old SeqAuth, src 0x%04x, dst 0x%04x", - rx->src, rx->dst); + BT_WARN("SeqAuth 0x%llx vs. 0x%llx", rx->seq_auth, *seq_auth); return -EINVAL; } @@ -1678,6 +1784,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, if (rx->block == BLOCK_COMPLETE(rx->seg_n)) { BT_INFO("Got segment for already complete SDU"); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); @@ -1715,10 +1822,11 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, net_rx->ctx.addr, net_rx->ctx.recv_dst, seq_auth, *seg_count)) { - BT_ERR("No space in Friend Queue for %u segments", *seg_count); - send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, - net_rx->ctx.send_ttl, seq_auth, 0, - net_rx->friend_match); + BT_WARN("NoSpaceInFrndQueue, SegCount %u", *seg_count); + + send_ack(net_rx->sub, net_rx->ctx.recv_dst, + net_rx->ctx.addr, net_rx->ctx.send_ttl, + seq_auth, 0, net_rx->friend_match); return -ENOBUFS; } @@ -1729,7 +1837,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, * eventually be freed up and we'll be able to process * this one. */ - BT_WARN("No free slots for new incoming segmented messages, src: %04x", net_rx->ctx.addr); + BT_WARN("SegRxFull, Src %04x", net_rx->ctx.addr); return -ENOMEM; } @@ -1756,16 +1864,21 @@ found_rx: /* Set the expected final buffer length */ rx->buf.len = seg_n * seg_len(&si) + buf->len; + BT_DBG("Target len %u * %u + %u = %u", + seg_n, seg_len(&si), buf->len, rx->buf.len); + if ((!rx->ext && rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) #if CONFIG_BLE_MESH_LONG_PACKET || (rx->ext && rx->buf.len > BLE_MESH_EXT_RX_SDU_MAX) #endif ) { - BT_ERR("Too large SDU len"); + BT_ERR("Too large SDU len %u", rx->buf.len); send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, 0, rx->obo); + seg_rx_reset(rx, true); + return -EMSGSIZE; } } else { @@ -1793,6 +1906,7 @@ found_rx: rx->block |= BIT(seg_o); if (rx->block != BLOCK_COMPLETE(seg_n)) { + BT_DBG("FrndPDUPartial"); *pdu_type = BLE_MESH_FRIEND_PDU_PARTIAL; return 0; } @@ -1813,8 +1927,8 @@ found_rx: if (net_rx->ctl) { err = ctl_recv(net_rx, *hdr, &rx->buf, seq_auth); } else { - err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), *hdr, - ASZMIC(hdr), &rx->buf); + err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), + *hdr, ASZMIC(hdr), &rx->buf); } seg_rx_reset(rx, false); @@ -1824,12 +1938,14 @@ found_rx: int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) { - uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; enum bt_mesh_friend_pdu_type pdu_type = BLE_MESH_FRIEND_PDU_SINGLE; struct net_buf_simple_state state = {0}; + uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; uint8_t seg_count = 0U; int err = 0; + BT_DBG("TransRecv"); + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { rx->friend_match = bt_mesh_friend_match(rx->sub->net_idx, rx->ctx.recv_dst); @@ -1837,20 +1953,21 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) rx->friend_match = false; } - BT_DBG("src 0x%04x dst 0x%04x seq 0x%08x friend_match %u", + BT_DBG("Src 0x%04x Dst 0x%04x Seq 0x%06x FrndMatch %u", rx->ctx.addr, rx->ctx.recv_dst, rx->seq, rx->friend_match); /* Remove network headers */ net_buf_simple_pull(buf, BLE_MESH_NET_HDR_LEN); - BT_DBG("Payload %s", bt_hex(buf->data, buf->len)); + BT_DBG("PDU %u %s", buf->len, bt_hex(buf->data, buf->len)); /* If LPN mode is enabled messages are only accepted when we've * requested the Friend to send them. The messages must also * be encrypted using the Friend Credentials. */ if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && - bt_mesh_lpn_established() && rx->net_if == BLE_MESH_NET_IF_ADV && + bt_mesh_lpn_established() && + rx->net_if == BLE_MESH_NET_IF_ADV && (!bt_mesh_lpn_waiting_update() || rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED)) { BT_WARN("Ignoring unexpected message in Low Power mode"); @@ -1867,12 +1984,14 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) * LPN of this Friend. */ if (!rx->local_match && !rx->friend_match) { + BT_DBG("LocalAndFrndNotMatch"); return 0; } err = trans_seg(buf, rx, &pdu_type, &seq_auth, &seg_count); } else { seg_count = 1U; + err = trans_unseg(buf, rx, &seq_auth); } @@ -1912,6 +2031,8 @@ void bt_mesh_rx_reset(void) { int i; + BT_DBG("RxReset"); + for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { seg_rx_reset(&seg_rx[i], true); } @@ -1921,6 +2042,8 @@ void bt_mesh_tx_reset(void) { int i; + BT_DBG("TxReset"); + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { seg_tx_reset(&seg_tx[i]); } @@ -1930,6 +2053,8 @@ void bt_mesh_rx_reset_single(uint16_t src) { int i; + BT_DBG("RxResetSingle, Src 0x%04x", src); + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { return; } @@ -1946,6 +2071,8 @@ void bt_mesh_tx_reset_single(uint16_t dst) { int i; + BT_DBG("TxResetSingle, Dst 0x%04x", dst); + if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { return; } diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c index 583f83e6a3..5721d6635a 100644 --- a/components/bt/esp_ble_mesh/core/transport.enh.c +++ b/components/bt/esp_ble_mesh/core/transport.enh.c @@ -160,53 +160,93 @@ static inline void bt_mesh_seg_rx_unlock(void) uint8_t bt_mesh_seg_send_interval(void) { - return (bt_mesh_get_sar_sis() + 1) * 10; + uint8_t interval = (bt_mesh_get_sar_sis() + 1) * 10; + + BT_DBG("SegSendInterval %u", interval); + + return interval; } uint8_t bt_mesh_get_seg_rtx_num(void) { - return bt_mesh_get_sar_urc(); + uint8_t num = bt_mesh_get_sar_urc(); + + BT_DBG("SegRTXNum %u", num); + + return num; } int32_t bt_mesh_seg_rtx_interval(uint16_t dst, uint8_t ttl) { + int32_t interval = 0; + if (BLE_MESH_ADDR_IS_UNICAST(dst)) { if (ttl == 0) { - return (bt_mesh_get_sar_uris() + 1) * 25; + interval = (bt_mesh_get_sar_uris() + 1) * 25; + } else { + interval = ((bt_mesh_get_sar_uris() + 1) * 25 + + (bt_mesh_get_sar_urii() + 1) * 25 * (ttl - 1)); } - - return ((bt_mesh_get_sar_uris() + 1) * 25 + - (bt_mesh_get_sar_urii() + 1) * 25 * (ttl - 1)); + } else { + interval = (bt_mesh_get_sar_mris() + 1) * 25; } - return (bt_mesh_get_sar_mris() + 1) * 25; + BT_DBG("SegRTXInterval %ld, Dst 0x%04x TTL %u", interval, dst, ttl); + + return interval; } int32_t bt_mesh_get_seg_rtx_timeout(uint16_t dst, uint8_t ttl) { - return bt_mesh_seg_rtx_interval(dst, ttl); + int32_t timeout = bt_mesh_seg_rtx_interval(dst, ttl); + + BT_DBG("SegRTXTimeout %ld, Dst 0x%04x TTL %u", timeout, dst, ttl); + + return timeout; } uint32_t bt_mesh_seg_discard_timeout(void) { - return K_SECONDS((bt_mesh_get_sar_dt() + 1) * 5); + uint32_t timeout = K_SECONDS((bt_mesh_get_sar_dt() + 1) * 5); + + BT_DBG("SegDiscardTimeout %lu", timeout); + + return timeout; } uint32_t bt_mesh_seg_rx_interval(void) { - return (bt_mesh_get_sar_rsis() + 1) * 10; + uint32_t interval = (bt_mesh_get_sar_rsis() + 1) * 10; + + BT_DBG("SegRxInterval %lu", interval); + + return interval; } uint32_t bt_mesh_seg_ack_timeout(uint8_t seg_n) { - float min = MIN((float)seg_n + 0.5, (float)bt_mesh_get_sar_adi() + 1.5); - return (uint32_t)(min * bt_mesh_seg_rx_interval()); + uint32_t timeout = 0U; + float min = 0.0; + + min = MIN((float)seg_n + 0.5, (float)bt_mesh_get_sar_adi() + 1.5); + timeout = (uint32_t)(min * bt_mesh_seg_rx_interval()); + + BT_DBG("SegAckTimeout %lu, Min %f", timeout, min); + + return timeout; } uint32_t bt_mesh_seg_ack_period(void) { - float val = (float)bt_mesh_get_sar_adi() + 1.5; - return (uint32_t)(val * bt_mesh_seg_rx_interval()); + uint32_t period = 0U; + float val = 0.0; + + val = (float)bt_mesh_get_sar_adi() + 1.5; + period = (uint32_t)(val * bt_mesh_seg_rx_interval()); + + BT_DBG("SegAckPeriod %lu, Val %f", period, val); + + return period; } static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, @@ -216,8 +256,10 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, struct net_buf *buf = NULL; enum bt_mesh_adv_type adv_type = BLE_MESH_ADV_DATA; - BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x sdu_len %u", - tx->src, tx->ctx->addr, tx->ctx->app_idx, sdu->len); + BT_DBG("SendUnseg"); + BT_DBG("Src 0x%04x Dst 0x%04x AppIdx 0x%04x CtlOp 0x%02x SduLen %u", + tx->src, tx->ctx->addr, tx->ctx->app_idx, + ctl_op ? *ctl_op : 0xFF, sdu->len); #if CONFIG_BLE_MESH_EXT_ADV #if CONFIG_BLE_MESH_LONG_PACKET @@ -272,13 +314,14 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, if (!bt_mesh_friend_queue_has_space(tx->sub->net_idx, tx->src, tx->ctx->addr, NULL, 1)) { + BT_WARN("NoSpaceInFrndQueue, SegCount 1"); + if (BLE_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - BT_ERR("Not enough space in Friend Queue"); + BT_ERR("NotSentToUnicast"); net_buf_unref(buf); return -ENOBUFS; } - BT_WARN("No space in Friend Queue"); goto send; } @@ -288,6 +331,8 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu, /* PDUs for a specific Friend should only go * out through the Friend Queue. */ + BT_DBG("FrndTxEnqueued, SegCount 1"); + net_buf_unref(buf); send_cb_finalize(cb, cb_data); return 0; @@ -300,19 +345,25 @@ send: static inline uint8_t seg_len(struct seg_info *si) { + uint8_t len = 0; + if (si->ctl) { - return + len = #if CONFIG_BLE_MESH_LONG_PACKET si->long_pkt ? BLE_MESH_EXT_CTL_SEG_SDU_MAX : #endif BLE_MESH_CTL_SEG_SDU_MAX; + } else { + len = +#if CONFIG_BLE_MESH_LONG_PACKET + si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : +#endif + BLE_MESH_APP_SEG_SDU_MAX; } - return -#if CONFIG_BLE_MESH_LONG_PACKET - si->long_pkt ? BLE_MESH_EXT_APP_SEG_SDU_MAX : -#endif - BLE_MESH_APP_SEG_SDU_MAX; + BT_DBG("SegLen %u", len); + + return len; } bool bt_mesh_tx_in_progress(void) @@ -321,20 +372,28 @@ bool bt_mesh_tx_in_progress(void) for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { if (seg_tx[i].nack_count) { + BT_DBG("SegTxInProgress"); return true; } } + BT_DBG("SegTxNotInProgress"); return false; } static bool seg_tx_blocks(struct seg_tx *tx, uint16_t src, uint16_t dst) { + BT_DBG("SegTxBlocks"); + BT_DBG("Src 0x%04x vs. 0x%04x", tx->src, src); + BT_DBG("Dst 0x%04x vs. 0x%04x", tx->dst, dst); + return (tx->src == src) && (tx->dst == dst); } static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) { + BT_DBG("SegTxDone, SegIdx %u", seg_idx); + /* If the segments are sent from local network interface, buf->ref * should be smaller than 4. * For other network interfaces, buf->ref should be smaller than 3. @@ -344,12 +403,16 @@ static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(tx->seg[seg_idx]), 0); net_buf_unref(tx->seg[seg_idx]); + BT_DBG("NackCountDec %u", tx->nack_count); + tx->seg[seg_idx] = NULL; tx->nack_count--; } static void seg_tx_reset(struct seg_tx *tx) { + BT_DBG("SegTxReset"); + bt_mesh_seg_tx_lock(); k_delayed_work_free(&tx->seg_timer); @@ -381,6 +444,7 @@ static void seg_tx_reset(struct seg_tx *tx) if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_IVU_PENDING)) { BT_DBG("Proceeding with pending IV Update"); + /* bt_mesh_net_iv_update() will re-enable the flag if this * wasn't the only transfer. */ @@ -395,6 +459,8 @@ static void seg_tx_complete(struct seg_tx *tx, int err) const struct bt_mesh_send_cb *cb = tx->cb; void *cb_data = tx->cb_data; + BT_DBG("SegTxComplete, Err %d", err); + seg_tx_reset(tx); /* TODO: notify the completion of sending segmented message */ @@ -411,10 +477,15 @@ static bool all_seg_acked(struct seg_tx *tx, uint8_t *seg_n) if (seg_n) { *seg_n = i; } + + BT_DBG("NotAllSegAcked, SegN %u", i); + return false; } } + BT_DBG("AllSegAcked"); + return true; } @@ -438,6 +509,10 @@ static bool send_next_segment(struct seg_tx *tx, int *result) struct net_buf *seg = NULL; int err = 0; + BT_DBG("SendNextSeg"); + BT_DBG("Src 0x%04x Dst 0x%04x LastSegN %u SegN %u LSNUpdated %u", + tx->src, tx->dst, tx->last_seg_n, tx->seg_n, tx->lsn_updated); + /* Check if all the segments are acknowledged. This could happen * when the complete Segment ACK (i.e. with all ack bits set) is * received before sending the next segment, which will cause the @@ -469,6 +544,8 @@ static bool send_next_segment(struct seg_tx *tx, int *result) * not been acknowledged. */ if (tx->seg[i]) { + BT_DBG("SegFound %u", i); + tx->last_seg_n = i; seg = tx->seg[i]; break; @@ -490,16 +567,19 @@ static bool send_next_segment(struct seg_tx *tx, int *result) * Segment Retransmission timer is expired earlier. */ if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(seg))) { + BT_DBG("SegSentBusy"); return false; } - BT_INFO("Send next seg %u, cred %u", tx->last_seg_n, tx->cred); + BT_INFO("LastSegN %u Cred %u", tx->last_seg_n, tx->cred); if (tx->resend) { err = bt_mesh_net_resend(tx->sub, seg, tx->new_key, &tx->cred, tx->tag, &seg_sent_cb, tx); if (err) { - BT_ERR("Resend seg %u failed (err %d)", tx->last_seg_n, err); + BT_ERR("ResendSegFailed, LastSegN %u Err %d", + tx->last_seg_n, err); + *result = -EIO; return true; } @@ -508,15 +588,16 @@ static bool send_next_segment(struct seg_tx *tx, int *result) net_tx.ctx->net_idx = tx->sub->net_idx; - /** - * Add one to the ref count only if the segment can be further + /* Add one to the ref count only if the segment can be further * processed by the network. */ seg = net_buf_ref(seg); err = bt_mesh_net_send(&net_tx, seg, &seg_sent_cb, tx); if (err) { - BT_ERR("Send seg %u failed (err %d)", tx->last_seg_n, err); + BT_ERR("SendSegFailed, LastSegN %u Err %d", + tx->last_seg_n, err); + *result = -EIO; return true; } @@ -526,7 +607,9 @@ static bool send_next_segment(struct seg_tx *tx, int *result) * which will be used for retransmission later. */ if (tx->cred != net_tx.ctx->send_cred) { - BT_ERR("Mismatch seg cred %u/%u", tx->cred, net_tx.ctx->send_cred); + BT_ERR("MismatchSegCred %u vs. %u", + tx->cred, net_tx.ctx->send_cred); + *result = -EIO; return true; } @@ -544,6 +627,8 @@ static void send_next_seg(struct k_work *work) tx_complete = send_next_segment(tx, &result); bt_mesh_seg_tx_unlock(); + BT_DBG("SendNextSeg, TxComplete %u", tx_complete); + if (tx_complete) { seg_tx_complete(tx, result); } @@ -555,6 +640,8 @@ static void prepare_next_seg(struct seg_tx *tx) uint8_t seg_n = 0; uint8_t xmit = 0; + BT_DBG("PrepareNextSeg"); + /* Check if all the segments are acknowledged. This could happen * when the complete Segment ACK (i.e. with all ack bits set) is * received before the completion of sending last segment, which @@ -565,6 +652,8 @@ static void prepare_next_seg(struct seg_tx *tx) return; } + BT_DBG("LastSegN %u SegN %u SegNGet %u", tx->last_seg_n, tx->seg_n, seg_n); + /* The last_seg_n must not be larger than the seg_n */ assert(tx->last_seg_n <= tx->seg_n && "Too large last_seg_n"); @@ -598,7 +687,7 @@ static void prepare_next_seg(struct seg_tx *tx) interval = bt_mesh_seg_send_interval(); - BT_INFO("Send next segment %u after %dms", i, interval); + BT_INFO("SendNextSeg %u, Interval %ld", i, interval); k_delayed_work_submit(&tx->seg_timer, interval); return; @@ -610,6 +699,7 @@ static void prepare_next_seg(struct seg_tx *tx) * we need to decrypt it firstly. */ if (tx->resend == 0) { + BT_DBG("TxResendMarked"); tx->resend = 1; } @@ -620,7 +710,7 @@ static void prepare_next_seg(struct seg_tx *tx) /* Start the SAR retransmission timer */ interval = bt_mesh_seg_rtx_interval(tx->dst, tx->ttl); - BT_INFO("All segments sent, resend after %dms", interval); + BT_INFO("AllSegsSent, SegN %u Interval %ld", seg_n, interval); k_delayed_work_submit(&tx->rtx_timer, interval); } @@ -629,6 +719,8 @@ static void seg_send_start(uint16_t duration, int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegSendStart, Err %d", err); + /* If there's an error in transmitting the 'sent' callback will never * be called. Make sure that we kick the retransmit timer also in this * case since otherwise we risk the transmission of becoming stale. @@ -638,6 +730,8 @@ static void seg_send_start(uint16_t duration, int err, void *user_data) return; } + BT_DBG("TxResend %u LastSegN %u", tx->resend, tx->last_seg_n); + if (tx->resend == 0 && tx->last_seg_n == 0) { /* Start sending the multi-segment message */ if (tx->cb && tx->cb->start) { @@ -654,6 +748,8 @@ static void seg_send_end(int err, void *user_data) { struct seg_tx *tx = user_data; + BT_DBG("SegSendEnd, Err %d", err); + if (err) { seg_tx_complete(tx, -EIO); } @@ -669,6 +765,10 @@ static bool resend_unacked_seg(struct seg_tx *tx, int *result) struct net_buf *seg = NULL; int err = 0; + BT_DBG("ResendUnackedSeg"); + BT_DBG("Dst 0x%04x Surc %u Surwpc %u Smrc %u", + tx->dst, tx->surc, tx->surwpc, tx->smrc); + /* Check if all the segments are acknowledged. This could happen * when the complete Segment ACK(i.e. with all ack bits set) is * received before the completion of sending last segment, which @@ -738,6 +838,8 @@ static bool resend_unacked_seg(struct seg_tx *tx, int *result) */ for (size_t i = tx->last_seg_n; i <= tx->seg_n; i++) { if (tx->seg[i]) { + BT_DBG("SegFound %u", i); + tx->last_seg_n = i; seg = tx->seg[i]; break; @@ -760,10 +862,11 @@ static bool resend_unacked_seg(struct seg_tx *tx, int *result) * find that the "busy" flag of Segment A is 1. */ if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(seg))) { + BT_DBG("SegSentBusy"); return false; } - BT_INFO("Resend seg %u, cred %u", tx->last_seg_n, tx->cred); + BT_INFO("LastSegN %u Cred %u", tx->last_seg_n, tx->cred); /* TODO: * The "tx->new_key" should be replaced with sub->kr_flag, @@ -774,7 +877,9 @@ static bool resend_unacked_seg(struct seg_tx *tx, int *result) &tx->cred, tx->tag, &seg_sent_cb, tx); if (err) { - BT_ERR("Resend seg %u failed (err %d)", tx->last_seg_n, err); + BT_ERR("ResendSegFailed, LastSegN %u Err %d", + tx->last_seg_n, err); + *result = -EIO; return true; } @@ -794,6 +899,8 @@ static void seg_retransmit(struct k_work *work) tx_complete = resend_unacked_seg(tx, &err); bt_mesh_seg_tx_unlock(); + BT_DBG("SendRetransmit, TxComplete %u", tx_complete); + if (tx_complete) { seg_tx_complete(tx, err); } @@ -811,11 +918,14 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, int err = 0; size_t i; - BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x aszmic %u sdu_len %u", + BT_DBG("SendSeg"); + BT_DBG("Src 0x%04x Dst 0x%04x AppIdx 0x%04x Aszmic %u SduLen %u", net_tx->src, net_tx->ctx->addr, net_tx->ctx->app_idx, net_tx->aszmic, sdu->len); for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { + BT_DBG("Seg%u: NackCount %u", i, seg_tx[i].nack_count); + if (seg_tx[i].nack_count) { /* The lower transport layer shall not transmit segmented messages * for more than one Upper Transport PDU to the same destination @@ -830,6 +940,8 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, for (tx = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) { if (!seg_tx[i].nack_count) { + BT_DBG("SegTxFound %u", i); + tx = &seg_tx[i]; break; } @@ -922,15 +1034,18 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, seq_zero = tx->seq_auth & TRANS_SEQ_ZERO_MASK; - BT_DBG("SeqZero 0x%04x (segs: %u)", seq_zero, tx->nack_count); + BT_DBG("SegHdr 0x%02x SegN %u NackCount %u NewKey %u TTL %u", + tx->hdr, tx->seg_n, tx->nack_count, tx->new_key, tx->ttl); + BT_DBG("SeqZero 0x%04x Surc %u Surwpc %u Smrc %u", + seq_zero, tx->surc, tx->surwpc, tx->smrc); if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_friend_queue_has_space(tx->sub->net_idx, net_tx->src, tx->dst, &tx->seq_auth, tx->seg_n + 1) && BLE_MESH_ADDR_IS_UNICAST(tx->dst)) { - BT_ERR("Not enough space in Friend Queue for %u segments", - tx->seg_n + 1); + BT_WARN("NoSpaceInFrndQueue, SegCount %u", tx->seg_n + 1); + seg_tx_reset(tx); return -ENOBUFS; } @@ -997,6 +1112,8 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, type = BLE_MESH_FRIEND_PDU_PARTIAL; } + BT_DBG("FrndPDUType %u", type); + if (bt_mesh_friend_enqueue_tx(net_tx, type, &tx->seq_auth, tx->seg_n + 1, @@ -1005,39 +1122,40 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, /* PDUs for a specific Friend should only go * out through the Friend Queue. */ + BT_DBG("FrndTxEnqueued, SegCount %u", tx->seg_n + 1); + net_buf_unref(seg); continue; } } - /** - * If the net buffer allocation of the subsequent - * segments of this segment message fails, it will - * cause the ref count of the previously allocated - * successful segments to not be unref, which will - * cause the net buffer leakage to occur, so it is - * necessary to wait until all the segments have been - * allocated, and then when the segment is confirmed - * that it will be network layer for further processing, - * then ref of the net buffer should be plus one. + /* If the net buffer allocation of the subsequent segments of + * this segment message fails, it will cause the ref count of + * the previously allocated successful segments to not be unref, + * which will cause the net buffer leakage to occur, so it is + * necessary to wait until all the segments have been allocated, + * and then when the segment is confirmed that it will be network + * layer for further processing, then ref of the net buffer should + * be plus one. */ tx->seg[seg_o] = seg; - BT_DBG("Seg %u/%u prepared", seg_o, tx->seg_n); + BT_DBG("SegPrepared %u/%u", seg_o, tx->seg_n); } /* If all the segments are enqueued in the friend queue, then the * tx->seg[0] will be NULL here. */ if (tx->seg[0]) { - /** - * Add one to the ref count only if the segment can be further + /* Add one to the ref count only if the segment can be further * processed by the network. */ tx->seg[0] = net_buf_ref(tx->seg[0]); + err = bt_mesh_net_send(net_tx, tx->seg[0], &seg_sent_cb, tx); if (err) { - BT_ERR("Send 1st seg failed (err %d)", err); + BT_ERR("SendFirstSegFailed, Err %d", err); + seg_tx_reset(tx); return err; } @@ -1047,13 +1165,17 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu, * which will be used for retransmission later. */ if (tx->cred != net_tx->ctx->send_cred) { + BT_INFO("OldCred %u NewCred %u", tx->cred, net_tx->ctx->send_cred); tx->cred = net_tx->ctx->send_cred; } } /* This can happen if segments only went into the Friend Queue */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !tx->seg[0]) { + BT_DBG("OnlyToFrndQueue"); + seg_tx_reset(tx); + /* If there was a callback notify sending immediately since * there's no other way to track this (at least currently) * with the Friend Queue. @@ -1077,6 +1199,8 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, uint8_t aid = 0U; int err = 0; + BT_DBG("TransSend"); + if (msg->len < 1) { BT_ERR("Zero-length SDU not allowed"); return -EINVAL; @@ -1102,9 +1226,9 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, } #endif - BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->sub->net_idx, - tx->ctx->app_idx, tx->ctx->addr); - BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len)); + BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Dst 0x%04x", + tx->sub->net_idx, tx->ctx->app_idx, tx->ctx->addr); + BT_DBG("Len %u: %s", msg->len, bt_hex(msg->data, msg->len)); err = bt_mesh_upper_key_get(tx->sub, tx->ctx->app_idx, &key, &aid, tx->ctx->addr); @@ -1122,7 +1246,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, tx->aszmic = 1U; } - BT_INFO("%s, send_tag 0x%02x, send_szmic %d, aszmic %d", + BT_INFO("%s, Tag 0x%02x Szmic %u Aszmic %u", bt_mesh_tag_send_segmented(tx->ctx->send_tag) ? "Seg" : "Unseg", tx->ctx->send_tag, tx->ctx->send_szmic, tx->aszmic); @@ -1137,7 +1261,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, tx->ctx->addr, bt_mesh.seq, BLE_MESH_NET_IVI_TX); if (err) { - BT_ERR("Encrypt failed (err %d)", err); + BT_ERR("AppEncryptFailed, Err %d", err); return err; } @@ -1151,7 +1275,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, static void revoke_dev_key(const uint8_t *dev_key) { if (!memcmp(dev_key, bt_mesh.dev_key_ca, 16)) { - BT_INFO("Revoke Device Key"); + BT_INFO("RevokeDevKey"); memcpy(bt_mesh.dev_key, bt_mesh.dev_key_ca, 16); memset(bt_mesh.dev_key_ca, 0, 16); @@ -1172,8 +1296,9 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, size_t i = 0U; int err = 0; - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); - BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len)); + BT_DBG("SduRecv"); + BT_DBG("Aszmic %u AKF %u AID 0x%02x", aszmic, AKF(&hdr), AID(&hdr)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->len < 1 + APP_MIC_LEN(aszmic)) { BT_ERR("Too short SDU + MIC (len %u)", buf->len); @@ -1212,7 +1337,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, dev_key = bt_mesh_rx_devkey_get(i, rx->ctx.addr); if (!dev_key) { - BT_DBG("DevKey not found"); + BT_DBG("DevKeyNotFound"); continue; } @@ -1223,6 +1348,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, rx->ctx.recv_dst, seq, BLE_MESH_NET_IVI_RX(rx)); if (err) { + BT_DBG("DevKeyNotDecrypt"); continue; } @@ -1248,6 +1374,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } BT_WARN("Unable to decrypt with DevKey"); + bt_mesh_free_buf(sdu); return -ENODEV; } @@ -1260,7 +1387,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, key = bt_mesh_rx_appkey_get(i); if (!key) { - BT_DBG("AppKey not found"); + BT_DBG("AppKeyNotFound"); continue; } @@ -1294,8 +1421,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, bt_hex(sdu->data, sdu->len)); if (err) { - BT_DBG("Unable to decrypt with AppKey 0x%03x", - key->app_idx); + BT_DBG("AppKeyNotDecrypt, AppIdx 0x%04x", key->app_idx); continue; } @@ -1307,10 +1433,10 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint32_t seq, uint8_t hdr, } if (rx->local_match) { - BT_WARN("No matching AppKey"); + BT_WARN("NoMatchAppKey"); } - bt_mesh_free_buf(sdu); + bt_mesh_free_buf(sdu); return 0; } @@ -1320,6 +1446,8 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, struct seg_tx *tx = NULL; int i; + BT_DBG("SegTxLookup, SeqZero 0x%04x OBO %u Addr 0x%04x", seq_zero, obo, addr); + for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { tx = &seg_tx[i]; @@ -1335,6 +1463,7 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, } if (tx->dst == addr) { + BT_DBG("SegTxFound, Dst 0x%04x", addr); return tx; } @@ -1344,6 +1473,7 @@ static struct seg_tx *seg_tx_lookup(uint16_t seq_zero, uint8_t obo, * responding and therefore accept the message. */ if (obo && tx->nack_count == tx->seg_n + 1) { + BT_DBG("SegTxOboFound, Dst 0x%04x", addr); tx->dst = addr; return tx; } @@ -1370,6 +1500,8 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, *tx_complete = false; *result = 0; + BT_DBG("RecvSegAck"); + if (buf->len != 6) { BT_ERR("Malformed Segment Ack (len %u)", buf->len); return -EINVAL; @@ -1388,7 +1520,7 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, ack = net_buf_simple_pull_be32(buf); - BT_DBG("OBO %u seq_zero 0x%04x ack 0x%08x", obo, seq_zero, ack); + BT_DBG("OBO %u SeqZero 0x%04x Ack 0x%08lx", obo, seq_zero, ack); tx = seg_tx_lookup(seq_zero, obo, rx->ctx.addr, rx->ctx.net_idx); if (!tx) { @@ -1446,6 +1578,8 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, return 0; } + BT_DBG("NewlyMarked"); + /* If at least one segment is newly marked as acknowledged as * a result of receiving the Segment Acknowledgment message, * the lower transport layer shall set the remaining number of @@ -1455,9 +1589,12 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, tx->surwpc = bt_mesh_get_sar_urwpc(); } + BT_DBG("Surc %u Surwpc %u", tx->surc, tx->surwpc); + if (tx->surc == 0 || tx->surwpc == 0) { BT_WARN("Ran out of retransmission to 0x%04x (%u/%u)", tx->dst, tx->surc, tx->surwpc); + *tx_complete = true; *result = -ETIMEDOUT; return 0; @@ -1465,6 +1602,8 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, assert(all_seg_acked(tx, &seg_n) == false && "All segments acked"); + BT_DBG("SegN %u TxResend %u", seg_n, tx->resend); + if (tx->resend == 1) { /* Only update the last_seg_n to the first unacked SegN while * the first round transmission is finished, because we need @@ -1493,7 +1632,7 @@ static int recv_seg_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, /* Restart the SAR Unicast Retransmission timer */ interval = bt_mesh_seg_rtx_interval(tx->dst, tx->ttl); - BT_INFO("Resend segments after %dms", interval); + BT_INFO("ResendSeg, Interval %ld", interval); k_delayed_work_submit(&tx->rtx_timer, interval); @@ -1512,6 +1651,8 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, err = recv_seg_ack(rx, hdr, buf, seq_auth, &tx, &tx_complete, &result); bt_mesh_seg_tx_unlock(); + BT_DBG("TransAck, TxComplete %u", tx_complete); + if (tx_complete) { seg_tx_complete(tx, result); } @@ -1525,6 +1666,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, uint8_t init_ttl = 0U, hops = 0U; uint16_t feat = 0U; + BT_DBG("TransHeartbeat"); + if (buf->len != 3) { BT_ERR("Malformed heartbeat message (len %u)", buf->len); return -EINVAL; @@ -1541,9 +1684,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx, hops = (init_ttl - rx->ctx.recv_ttl + 1); - BT_INFO("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x", - rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, - (hops == 1U) ? "" : "s", feat); + BT_INFO("Src 0x%04x TTL %u InitTTL %u Hops %u Feat 0x%04x", + rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops, feat); if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned()) { bt_mesh_heartbeat_recv(rx->ctx.addr, rx->ctx.recv_dst, hops, feat); @@ -1561,7 +1703,7 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, { uint8_t ctl_op = TRANS_CTL_OP(&hdr); - BT_DBG("OpCode 0x%02x len %u", ctl_op, buf->len); + BT_DBG("CTLRecv, OpCode 0x%02x Len %u", ctl_op, buf->len); BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_TNPT, @@ -1578,21 +1720,22 @@ static int ctl_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, /* Only acks and heartbeats may need processing without local_match */ if (!rx->local_match) { + BT_DBG("LocalNotMatch"); return 0; } - if (IS_ENABLED(CONFIG_BLE_MESH_DF_SRV)) { - switch (ctl_op) { - case TRANS_CTL_OP_PATH_REQ: - case TRANS_CTL_OP_PATH_REPLY: - case TRANS_CTL_OP_PATH_CFM: - case TRANS_CTL_OP_PATH_ECHO_REQ: - case TRANS_CTL_OP_PATH_ECHO_REPLY: - case TRANS_CTL_OP_DEP_NODE_UPDATE: - case TRANS_CTL_OP_PATH_REQ_SOLIC: - return bt_mesh_directed_forwarding_ctl_recv(ctl_op, rx, buf); - } +#if CONFIG_BLE_MESH_DF_SRV + switch (ctl_op) { + case TRANS_CTL_OP_PATH_REQ: + case TRANS_CTL_OP_PATH_REPLY: + case TRANS_CTL_OP_PATH_CFM: + case TRANS_CTL_OP_PATH_ECHO_REQ: + case TRANS_CTL_OP_PATH_ECHO_REPLY: + case TRANS_CTL_OP_DEP_NODE_UPDATE: + case TRANS_CTL_OP_PATH_REQ_SOLIC: + return bt_mesh_directed_forwarding_ctl_recv(ctl_op, rx, buf); } +#endif /* CONFIG_BLE_MESH_DF_SRV */ if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !bt_mesh_lpn_established()) { switch (ctl_op) { @@ -1645,7 +1788,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, { uint8_t hdr = 0U; - BT_DBG("AFK %u AID 0x%02x", AKF(buf->data), AID(buf->data)); + BT_DBG("TransUnseg, AKF %u AID 0x%02x", AKF(buf->data), AID(buf->data)); if (buf->len < 1) { BT_ERR("Too small unsegmented PDU"); @@ -1653,7 +1796,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, } if (bt_mesh_rpl_check(rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", rx->ctx.addr, rx->ctx.recv_dst, rx->seq); return -EINVAL; } @@ -1666,6 +1809,7 @@ static int trans_unseg(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx, /* SDUs must match a local element or an LPN of this Friend. */ if (!rx->local_match && !rx->friend_match) { + BT_DBG("LocalAndFrndNotMatch"); return 0; } @@ -1678,6 +1822,8 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, { struct net_buf_simple buf = {0}; + BT_DBG("CtlSend"); + net_buf_simple_init_with_data(&buf, data, data_len); if (data_len > BLE_MESH_SDU_UNSEG_MAX) { @@ -1687,9 +1833,9 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, /* Set app_idx to unused here since CTL is only encrypted with NetKey */ tx->ctx->app_idx = BLE_MESH_KEY_UNUSED; - BT_DBG("src 0x%04x dst 0x%04x ttl 0x%02x ctl 0x%02x", tx->src, - tx->ctx->addr, tx->ctx->send_ttl, ctl_op); - BT_DBG("len %zu: %s", data_len, bt_hex(data, data_len)); + BT_DBG("Src 0x%04x Dst 0x%04x TTL 0x%02x CTL 0x%02x", + tx->src, tx->ctx->addr, tx->ctx->send_ttl, ctl_op); + BT_DBG("Len %u: %s", data_len, bt_hex(data, data_len)); if (bt_mesh_tag_send_segmented(tx->ctx->send_tag)) { return send_seg(tx, &buf, cb, cb_data, &ctl_op); @@ -1702,18 +1848,21 @@ static void seg_ack_send_start(uint16_t duration, int err, void *user_data) { struct seg_rx *rx = user_data; - BT_INFO("Send segment ack start (err %d)", err); + BT_INFO("SegAckSendStart, Err %d", err); if (err) { rx->last_ack = k_uptime_get_32(); + + BT_DBG("LastAck %lu", rx->last_ack); } } static void seg_ack_send_end(int err, void *user_data) { struct seg_rx *rx = user_data; + uint32_t interval = 0U; - BT_INFO("Send segment ack end"); + BT_INFO("SegAckSendEnd, InUse %u Err %d", rx->in_use, err); /* This could happen when during the Segment ACK transaction, * the seg_rx is been reset. @@ -1724,6 +1873,9 @@ static void seg_ack_send_end(int err, void *user_data) rx->last_ack = k_uptime_get_32(); + BT_DBG("LastAck %lu SegN %u Sarc %u NewSeg %u", + rx->last_ack, rx->seg_n, rx->sarc, rx->new_seg); + /* If the seg_rx is in use, we will restart the SAR ACK timer if * the SegN is greater than the SAR Segments Threshold. * Note: @@ -1741,10 +1893,12 @@ static void seg_ack_send_end(int err, void *user_data) /* Decrement the SAR ACK Retransmissions Count */ rx->sarc -= 1; - BT_INFO("Resend segment ack after %dms", bt_mesh_seg_rx_interval()); + interval = bt_mesh_seg_rx_interval(); + + BT_INFO("ResendSeg, Interval %lu", interval); /* Introduce a delay for the Segment ACK retransmission */ - k_delayed_work_submit(&rx->ack_timer, bt_mesh_seg_rx_interval()); + k_delayed_work_submit(&rx->ack_timer, interval); } } @@ -1782,7 +1936,7 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, uint16_t seq_zero = *seq_auth & TRANS_SEQ_ZERO_MASK; uint8_t buf[6] = {0}; - BT_DBG("SeqZero 0x%04x Block 0x%08x OBO %u", seq_zero, block, obo); + BT_DBG("SendAck, SeqZero 0x%04x Block 0x%08lx OBO %u", seq_zero, block, obo); if (bt_mesh_lpn_established()) { BT_WARN("Not sending ack when LPN is enabled"); @@ -1806,6 +1960,8 @@ static int send_ack(struct bt_mesh_subnet *sub, uint16_t src, uint16_t dst, static void seg_rx_reset(struct seg_rx *rx, bool full_reset) { + BT_DBG("SegRxReset, FullReset %u", full_reset); + bt_mesh_seg_rx_lock(); k_delayed_work_free(&rx->dis_timer); @@ -1846,6 +2002,8 @@ static void send_seg_ack(struct k_work *work) { struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack_timer); + BT_DBG("SendSegAck, Sub %p", rx->sub); + bt_mesh_seg_rx_lock(); /* This could happen when the SAR ACK timer expired, and a BTC @@ -1872,6 +2030,9 @@ end: static void discard_msg(struct k_work *work) { struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, dis_timer); + uint32_t timeout = 0U; + + BT_DBG("DiscardMsg, InUse %u Dst 0x%04x", rx->in_use, rx->dst); /* This could happen when the SAR Discard timer expired, and a * BTC event is posted to the BTC queue. @@ -1889,16 +2050,20 @@ static void discard_msg(struct k_work *work) k_delayed_work_cancel(&rx->ack_timer); } - BT_WARN("Discard timer expired (%dms)", bt_mesh_seg_discard_timeout()); + timeout = bt_mesh_seg_discard_timeout(); - /* Not fully reset the seg_rx, in case any segment of this - * message is received later. + BT_WARN("DiscardTimerExpired, timeout %lu", timeout); + + /* Not fully reset the seg_rx, in case any segment of + * this message is received later. */ seg_rx_reset(rx, false); } static inline uint16_t sdu_len_max(uint8_t seg_n,uint16_t seg_len) { + BT_DBG("IsSduLenOK,Len:%u,SegN:%u", seg_len, seg_n); + return ((seg_n + 1) * seg_len); } @@ -1907,6 +2072,9 @@ static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n, uint16_t buf_len) struct seg_info si = { .ctl = ctl, }; + + BT_DBG("IsSduLenOK, CTL %u SegN %u", ctl, seg_n); + #if CONFIG_BLE_MESH_LONG_PACKET if ((sdu_len_max(seg_n, buf_len) > CONFIG_BLE_MESH_RX_SDU_MAX)) { si.long_pkt = 1; @@ -1919,6 +2087,8 @@ static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n, uint16_t buf_len) static void seg_rx_reset_pending(struct bt_mesh_net_rx *net_rx, const uint64_t *seq_auth) { + BT_DBG("SegRxResetPending, SeqAuth 0x%llx", *seq_auth); + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { struct seg_rx *rx = &seg_rx[i]; @@ -1940,9 +2110,13 @@ static struct seg_rx *seg_rx_find_with_buf(struct bt_mesh_net_rx *net_rx, struct seg_rx *rx_buf, uint16_t rx_buf_size ) { + BT_DBG("SegRxFind, SeqAuth 0x%llx", *seq_auth); for (size_t i = 0; i < rx_buf_size; i++) { struct seg_rx *rx = &rx_buf[i]; + BT_DBG("Seg%u/%u: Src 0x%04x Dst 0x%04x SeqAuth 0x%llx", + i,rx->seg_n, rx->src, rx->dst, rx->seq_auth); + if (rx->src == net_rx->ctx.addr && rx->dst == net_rx->ctx.recv_dst) { if (rx->seq_auth >= *seq_auth) { @@ -2025,6 +2199,8 @@ static struct seg_rx *seg_rx_find(struct bt_mesh_net_rx *net_rx, static bool seg_rx_is_valid(struct seg_rx *rx, struct bt_mesh_net_rx *net_rx, const uint8_t *hdr, uint8_t seg_n) { + BT_DBG("IsSegRxValid"); + if (rx->hdr != *hdr || rx->seg_n != seg_n) { BT_ERR("Invalid segment for ongoing session"); return false; @@ -2044,6 +2220,7 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, { int err = 0; +<<<<<<< HEAD /* By default, traditional seg_rx is used for allocation. * If the first segment received is the last segment of * the long packet, and its length is the length of the traditional packet, @@ -2063,6 +2240,12 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, for (size_t i = 0; i < rx_buf_size; i++) { struct seg_rx *rx = &seg_rx_buf[i]; +======= + BT_DBG("SegRxAlloc, SegN %u", seg_n); + + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { + struct seg_rx *rx = &seg_rx[i]; +>>>>>>> 7652269a401 (feat(ble_mesh): Miscellaneous log enhancement for BLE Mesh) if (rx->in_use) { continue; @@ -2078,7 +2261,7 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, err = k_delayed_work_init(&rx->ack_timer, send_seg_ack); if (err) { BT_ERR("No free ack_timer for new incoming segmented message"); - k_delayed_work_free(&rx->dis_timer); /* Must do */ + k_delayed_work_free(&rx->dis_timer); return NULL; } } @@ -2106,7 +2289,6 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, return rx; } - BT_WARN("No free slots for new incoming segmented messages"); return NULL; } @@ -2122,18 +2304,20 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, uint8_t seg_o = 0U; int err = 0; + BT_DBG("TransSeg"); + if (buf->len < 5) { BT_ERR("Too short segmented message (len %u)", buf->len); return -EINVAL; } if (bt_mesh_rpl_check(net_rx, &rpl)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + BT_WARN("Replay, Src 0x%04x Dst 0x%04x Seq 0x%06x", net_rx->ctx.addr, net_rx->ctx.recv_dst, net_rx->seq); return -EINVAL; } - BT_DBG("ASZMIC %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); + BT_DBG("Aszmic %u AKF %u AID 0x%02x", ASZMIC(hdr), AKF(hdr), AID(hdr)); net_buf_simple_pull(buf, 1); @@ -2160,6 +2344,9 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, *seg_count = seg_n + 1; + BT_DBG("Src 0x%04x Dst 0x%04x SeqAuth 0x%llx SegCount %u", + net_rx->ctx.addr, net_rx->ctx.recv_dst, *seq_auth, *seg_count); + /* If this is the first segment, check if any pending reassembly * exists. If yes, we need to discard the pending reassembly. * Note: @@ -2173,8 +2360,7 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, if (rx) { /* Processing result is SeqAuth Error, ignore the segment */ if (rx->seq_auth > *seq_auth) { - BT_WARN("Ignoring old SeqAuth, src 0x%04x, dst 0x%04x", - rx->src, rx->dst); + BT_WARN("SeqAuth 0x%llx vs. 0x%llx", rx->seq_auth, *seq_auth); return -EINVAL; } @@ -2239,7 +2425,8 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, net_rx->ctx.addr, net_rx->ctx.recv_dst, seq_auth, *seg_count)) { - BT_ERR("No space in Friend Queue for %u segments", *seg_count); + BT_ERR("NoSpaceInFrndQueue, SegCount %u", *seg_count); + send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, 0, net_rx->friend_match, NULL); @@ -2249,6 +2436,8 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, /* Look for free slot for a new RX session */ rx = seg_rx_alloc(net_rx, hdr, seq_auth, seg_n); if (!rx) { + BT_WARN("SegRxFull, Src %04x", net_rx->ctx.addr); + /* Processing result is Message Rejected, respond with a Segment * ACK with the AckedSegments field set to 0x00000000. */ @@ -2285,14 +2474,20 @@ found_rx: /* Set the expected final buffer length */ rx->buf.len = seg_n * seg_len(&si) + buf->len; +<<<<<<< HEAD BT_DBG("Target len %u * %u + %u = %u", seg_n, seg_len(&si), buf->len, rx->buf.len); +======= + BT_DBG("Target len %u * %u + %u = %u", + seg_n, seg_len(rx->ctl), buf->len, rx->buf.len); +>>>>>>> 7652269a401 (feat(ble_mesh): Miscellaneous log enhancement for BLE Mesh) /* This should not happen, since we have made sure the whole * SDU could be received while handling the first segment. * But if the peer device sends the segments of a segmented * message with different CTL, then the following could happen. */ +<<<<<<< HEAD if ((!rx->ext && rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) #if CONFIG_BLE_MESH_LONG_PACKET || (rx->ext && rx->buf.len > BLE_MESH_EXT_RX_SDU_MAX) @@ -2300,10 +2495,16 @@ found_rx: ) { BT_ERR("Too large SDU len %u/%u", rx->buf.len, CONFIG_BLE_MESH_RX_SDU_MAX); +======= + if (rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) { + BT_ERR("Too large SDU len %u/%u", + rx->buf.len, CONFIG_BLE_MESH_RX_SDU_MAX); +>>>>>>> 7652269a401 (feat(ble_mesh): Miscellaneous log enhancement for BLE Mesh) send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, 0, rx->obo, NULL); + seg_rx_reset(rx, true); return -EMSGSIZE; @@ -2351,6 +2552,7 @@ found_rx: rx->block |= BIT(seg_o); if (rx->block != BLOCK_COMPLETE(seg_n)) { + BT_DBG("FrndPDUPartial"); *pdu_type = BLE_MESH_FRIEND_PDU_PARTIAL; return 0; } @@ -2374,8 +2576,8 @@ found_rx: if (net_rx->ctl) { err = ctl_recv(net_rx, *hdr, &rx->buf, seq_auth); } else { - err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), *hdr, - ASZMIC(hdr), &rx->buf); + err = sdu_recv(net_rx, (rx->seq_auth & 0xffffff), + *hdr, ASZMIC(hdr), &rx->buf); } seg_rx_reset(rx, false); @@ -2385,12 +2587,14 @@ found_rx: int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) { - uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; enum bt_mesh_friend_pdu_type pdu_type = BLE_MESH_FRIEND_PDU_SINGLE; struct net_buf_simple_state state = {0}; + uint64_t seq_auth = TRANS_SEQ_AUTH_NVAL; uint8_t seg_count = 0U; int err = 0; + BT_DBG("TransRecv"); + if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) { rx->friend_match = bt_mesh_friend_match(rx->sub->net_idx, rx->ctx.recv_dst); @@ -2398,20 +2602,21 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) rx->friend_match = false; } - BT_DBG("src 0x%04x dst 0x%04x seq 0x%08x friend_match %u", + BT_DBG("Src 0x%04x Dst 0x%04x Seq 0x%06x FrndMatch %u", rx->ctx.addr, rx->ctx.recv_dst, rx->seq, rx->friend_match); /* Remove network headers */ net_buf_simple_pull(buf, BLE_MESH_NET_HDR_LEN); - BT_DBG("Payload %s", bt_hex(buf->data, buf->len)); + BT_DBG("PDU %s", bt_hex(buf->data, buf->len)); /* If LPN mode is enabled messages are only accepted when we've * requested the Friend to send them. The messages must also * be encrypted using the Friend Credentials. */ if (IS_ENABLED(CONFIG_BLE_MESH_LOW_POWER) && - bt_mesh_lpn_established() && rx->net_if == BLE_MESH_NET_IF_ADV && + bt_mesh_lpn_established() && + rx->net_if == BLE_MESH_NET_IF_ADV && (!bt_mesh_lpn_waiting_update() || rx->ctx.recv_cred != BLE_MESH_FRIENDSHIP_CRED)) { BT_WARN("Ignoring unexpected message in Low Power mode"); @@ -2428,12 +2633,14 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) * LPN of this Friend. */ if (!rx->local_match && !rx->friend_match) { + BT_DBG("LocalAndFrndNotMatch"); return 0; } err = trans_seg(buf, rx, &pdu_type, &seq_auth, &seg_count); } else { seg_count = 1U; + err = trans_unseg(buf, rx, &seq_auth); } @@ -2471,6 +2678,8 @@ int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx) void bt_mesh_rx_reset(void) { + BT_DBG("RxReset"); + for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { seg_rx_reset(&seg_rx[i], true); } @@ -2478,6 +2687,8 @@ void bt_mesh_rx_reset(void) void bt_mesh_tx_reset(void) { + BT_DBG("TxReset"); + for (size_t i = 0; i < ARRAY_SIZE(seg_tx); i++) { seg_tx_reset(&seg_tx[i]); } @@ -2485,6 +2696,8 @@ void bt_mesh_tx_reset(void) void bt_mesh_rx_reset_single(uint16_t src) { + BT_DBG("RxResetSingle, Src 0x%04x", src); + if (!BLE_MESH_ADDR_IS_UNICAST(src)) { return; } @@ -2499,6 +2712,8 @@ void bt_mesh_rx_reset_single(uint16_t src) void bt_mesh_tx_reset_single(uint16_t dst) { + BT_DBG("TxResetSingle, Dst 0x%04x", dst); + if (!BLE_MESH_ADDR_IS_UNICAST(dst)) { return; } diff --git a/components/bt/esp_ble_mesh/models/client/client_common.c b/components/bt/esp_ble_mesh/models/client/client_common.c index 8c8afdd563..e87c68f62c 100644 --- a/components/bt/esp_ble_mesh/models/client/client_common.c +++ b/components/bt/esp_ble_mesh/models/client/client_common.c @@ -16,7 +16,7 @@ #if CONFIG_BLE_MESH_V11_SUPPORT #include "mesh_v1.1/utils.h" -#endif +#endif /* CONFIG_BLE_MESH_V11_SUPPORT */ #define HCI_TIME_FOR_START_ADV K_MSEC(5) /* Three adv related hci commands may take 4 ~ 5ms */ @@ -25,9 +25,13 @@ static bt_mesh_client_node_t *client_pick_node(sys_slist_t *list, uint16_t tx_ds bt_mesh_client_node_t *node = NULL; sys_snode_t *cur = NULL; + BT_DBG("ClientPickNode, Dst 0x%04x", tx_dst); + bt_mesh_list_lock(); + if (sys_slist_is_empty(list)) { bt_mesh_list_unlock(); + BT_DBG("ListEmpty"); return NULL; } @@ -36,22 +40,28 @@ static bt_mesh_client_node_t *client_pick_node(sys_slist_t *list, uint16_t tx_ds node = (bt_mesh_client_node_t *)cur; if (node->ctx.addr == tx_dst) { bt_mesh_list_unlock(); + BT_DBG("ListNodeFound"); return node; } } bt_mesh_list_unlock(); + + BT_DBG("ListNodeNotFound"); return NULL; } bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf, bool need_pub) + struct net_buf_simple *buf, + bool need_pub) { bt_mesh_client_internal_data_t *data = NULL; bt_mesh_client_user_data_t *cli = NULL; bt_mesh_client_node_t *node = NULL; + BT_DBG("ClientRecvPublishMsg"); + if (!model || !ctx || !buf) { BT_ERR("%s, Invalid parameter", __func__); return NULL; @@ -63,22 +73,25 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * return NULL; } - /** If the received message address is not a unicast address, - * the address may be a group/virtual address, and we push - * this message to the application layer. + BT_DBG("Src 0x%04x Dst 0x%04x RecvOp 0x%08lx", + ctx->addr, ctx->recv_dst, ctx->recv_op); + + /* If the received message address is not a unicast address, + * the address may be a group/virtual address, and we push + * this message to the application layer. */ if (!BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) { - BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + BT_DBG("MsgToNonUnicastDst"); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); } return NULL; } - /** If the source address of the received status message is - * different with the destination address of the sending - * message, then the message is from another element and - * push it to application layer. + /* If the source address of the received status message is + * different with the destination address of the sending + * message, then the message is from another element and + * push it to application layer. */ data = (bt_mesh_client_internal_data_t *)cli->internal_data; if (!data) { @@ -87,7 +100,7 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * } if ((node = client_pick_node(&data->queue, ctx->addr)) == NULL) { - BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + BT_DBG("MsgFromUnknownSrc"); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); } @@ -95,7 +108,7 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * } if (node->op_pending != ctx->recv_op) { - BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + BT_DBG("MsgWithUnknownOp"); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); } @@ -103,7 +116,7 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * } if (k_delayed_work_remaining_get(&node->timer) == 0) { - BT_DBG("Unexpected status message 0x%08x", ctx->recv_op); + BT_DBG("MsgWithTimerExpired"); if (cli->publish_status && need_pub) { cli->publish_status(ctx->recv_op, model, ctx, buf); } @@ -116,6 +129,9 @@ bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * static uint32_t client_get_status_op(const bt_mesh_client_op_pair_t *op_pair, int size, uint32_t opcode) { + BT_DBG("ClientGetStatusOp"); + BT_DBG("OpPair %p Size %u OpCode 0x%08lx", op_pair, size, opcode); + if (!op_pair || size == 0) { return 0; } @@ -123,11 +139,14 @@ static uint32_t client_get_status_op(const bt_mesh_client_op_pair_t *op_pair, const bt_mesh_client_op_pair_t *op = op_pair; for (int i = 0; i < size; i++) { if (op->cli_op == opcode) { + BT_DBG("OpCodeFound"); return op->status_op; } + op++; } + BT_DBG("OpCodeNotFound"); return 0; } @@ -139,17 +158,22 @@ static int32_t client_get_adv_duration(struct bt_mesh_msg_ctx *ctx) /* Initialize with network transmission */ xmit = bt_mesh_net_transmit_get(); + BT_DBG("ClientGetAdvDuration, Xmit 0x%02x", xmit); + if (bt_mesh_tag_immutable_cred(ctx->send_tag)) { #if CONFIG_BLE_MESH_DF_SRV if (ctx->send_cred == BLE_MESH_DIRECTED_CRED) { xmit = bt_mesh_direct_net_transmit_get(); /* Directed network transmission */ + BT_DBG("UseDFXmit 0x%02x", xmit); } -#endif +#endif /* CONFIG_BLE_MESH_DF_SRV */ } adv_int = BLE_MESH_TRANSMIT_INT(xmit); duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10); + BT_DBG("Duration %ld", (int32_t)duration); + return (int32_t)duration; } @@ -187,6 +211,8 @@ static int32_t client_calc_timeout(struct bt_mesh_msg_ctx *ctx, net_buf_simple_tailroom(msg) >= BLE_MESH_MIC_LONG) ? BLE_MESH_MIC_LONG : BLE_MESH_MIC_SHORT; + BT_DBG("NeedSeg %u MicSize %u", need_seg, mic_size); + if (need_seg) { /* Based on the message length, calculate how many segments are needed. * All the messages sent from here are access messages. @@ -243,7 +269,7 @@ static void msg_send_start(uint16_t duration, int err, void *cb_data) { bt_mesh_client_node_t *node = cb_data; - BT_DBG("%s, duration %ums", __func__, duration); + BT_DBG("MsgSendStart, Duration %u Err %d", duration, err); if (err) { if (!k_delayed_work_free(&node->timer)) { @@ -269,6 +295,8 @@ int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param, bt_mesh_client_node_t *node = NULL; int err = 0; + BT_DBG("ClientSendMsg, NeedAck %u", need_ack); + if (!param || !param->model || !msg) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -376,6 +404,8 @@ int bt_mesh_client_init(struct bt_mesh_model *model) bt_mesh_client_internal_data_t *internal = NULL; bt_mesh_client_user_data_t *client = NULL; + BT_DBG("ClientInit"); + if (!model || !model->op) { BT_ERR("Invalid vendor client model"); return -EINVAL; @@ -413,6 +443,8 @@ int bt_mesh_client_deinit(struct bt_mesh_model *model) { bt_mesh_client_user_data_t *client = NULL; + BT_DBG("ClientDeinit"); + if (!model) { BT_ERR("Invalid vendor client model"); return -EINVAL; @@ -444,6 +476,8 @@ int bt_mesh_client_free_node(bt_mesh_client_node_t *node) bt_mesh_client_internal_data_t *internal = NULL; bt_mesh_client_user_data_t *client = NULL; + BT_DBG("ClientFreeNode"); + if (!node || !node->model) { BT_ERR("Invalid client list item"); return -EINVAL; @@ -461,12 +495,10 @@ int bt_mesh_client_free_node(bt_mesh_client_node_t *node) return -EINVAL; } - // Release the client node from the queue bt_mesh_list_lock(); sys_slist_find_and_remove(&internal->queue, &node->client_node); bt_mesh_list_unlock(); - // Free the node bt_mesh_free(node); return 0; @@ -477,6 +509,8 @@ int bt_mesh_client_clear_list(void *data) bt_mesh_client_internal_data_t *internal = NULL; bt_mesh_client_node_t *node = NULL; + BT_DBG("ClientClearList"); + if (!data) { BT_ERR("%s, Invalid parameter", __func__); return -EINVAL; @@ -485,11 +519,13 @@ int bt_mesh_client_clear_list(void *data) internal = (bt_mesh_client_internal_data_t *)data; bt_mesh_list_lock(); + while (!sys_slist_is_empty(&internal->queue)) { node = (void *)sys_slist_get_not_empty(&internal->queue); k_delayed_work_free(&node->timer); bt_mesh_free(node); } + bt_mesh_list_unlock(); return 0; From 0eaf2f3cc9c3e32a0539b449b38e867703afda93 Mon Sep 17 00:00:00 2001 From: luoxu Date: Mon, 1 Sep 2025 20:47:15 +0800 Subject: [PATCH 143/156] feat(ble_mesh): Miscellaneous log enhancement for Provisioning --- components/bt/esp_ble_mesh/core/prov_common.c | 34 +++++++++---- components/bt/esp_ble_mesh/core/prov_node.c | 34 +++++++++---- components/bt/esp_ble_mesh/core/prov_pvnr.c | 48 +++++++++++++++---- 3 files changed, 89 insertions(+), 27 deletions(-) diff --git a/components/bt/esp_ble_mesh/core/prov_common.c b/components/bt/esp_ble_mesh/core/prov_common.c index a29ba8fb4f..bf5657852b 100644 --- a/components/bt/esp_ble_mesh/core/prov_common.c +++ b/components/bt/esp_ble_mesh/core/prov_common.c @@ -48,6 +48,7 @@ void bt_mesh_prov_buf_init(struct net_buf_simple *buf, uint8_t type) bt_mesh_output_action_t bt_mesh_prov_output_action(uint8_t action) { + BT_DBG("ProvOutputAction:%d", action); switch (action) { case OUTPUT_OOB_BLINK: return BLE_MESH_BLINK; @@ -66,6 +67,7 @@ bt_mesh_output_action_t bt_mesh_prov_output_action(uint8_t action) bt_mesh_input_action_t bt_mesh_prov_input_action(uint8_t action) { + BT_DBG("ProvInputAction:%d", action); switch (action) { case INPUT_OOB_PUSH: return BLE_MESH_PUSH; @@ -151,20 +153,27 @@ static uint8_t bt_mesh_prov_buf_type_get(struct net_buf_simple *buf) uint8_t node_next_xact_id(struct bt_mesh_prov_link *link) { + uint8_t nxt_xact_id = 0; if (link->tx.id != 0 && link->tx.id != 0xFF) { - return ++link->tx.id; + nxt_xact_id = ++link->tx.id; + } else { + link->tx.id = 0x80; + nxt_xact_id = 0x80; } - link->tx.id = 0x80; - return link->tx.id; + BT_DBG("NodeNextXActId:%d", nxt_xact_id); + return nxt_xact_id; } uint8_t pvnr_next_xact_id(struct bt_mesh_prov_link *link) { + uint8_t nxt_xact_id = 0; if (link->tx.id > 0x7F) { link->tx.id = 0; } - return link->tx.id++; + nxt_xact_id = link->tx.id++; + BT_DBG("PvnrNextXActId:%d", nxt_xact_id); + return nxt_xact_id; } bool bt_mesh_gen_prov_start(struct bt_mesh_prov_link *link, @@ -186,7 +195,7 @@ bool bt_mesh_gen_prov_start(struct bt_mesh_prov_link *link, link->rx.id = rx->xact_id; link->rx.fcs = net_buf_simple_pull_u8(buf); - BT_DBG("len %u last_seg %u total_len %u fcs 0x%02x", buf->len, + BT_DBG("LinkId:%08x,len %u last_seg %u total_len %u fcs 0x%02x", link->link_id, buf->len, START_LAST_SEG(rx->gpc), link->rx.buf->len, link->rx.fcs); /* At least one-octet pdu type is needed */ @@ -227,9 +236,10 @@ bool bt_mesh_gen_prov_start(struct bt_mesh_prov_link *link, link->rx.last_seg = START_LAST_SEG(rx->gpc); memcpy(link->rx.buf->data, buf->data, buf->len); XACT_SEG_RECV(link, 0); - + BT_DBG("Seg: %04x, lastSeg: %04x, Data: %s", link->rx.seg, link->rx.last_seg, bt_hex(buf->data, buf->len)); /* Still have some segments to receive */ if (link->rx.seg) { + BT_DBG("Still have some segments to receive: %02x", link->rx.seg); return false; } @@ -242,7 +252,7 @@ bool bt_mesh_gen_prov_cont(struct bt_mesh_prov_link *link, { uint8_t seg = CONT_SEG_INDEX(rx->gpc); - BT_DBG("len %u, seg_index %u", buf->len, seg); + BT_DBG("LinkId:%08x,len %u,seg_index %u", link->link_id, buf->len, seg); if (link->rx.seg == 0 && link->rx.prev_id == rx->xact_id) { BT_INFO("Resending ack"); @@ -287,6 +297,7 @@ bool bt_mesh_gen_prov_cont(struct bt_mesh_prov_link *link, /* Still have some segments to receive */ if (link->rx.seg) { + BT_DBG("Still have some segments to receive: %02x", link->rx.seg); return false; } @@ -346,12 +357,14 @@ void bt_mesh_gen_prov_ack_send(struct bt_mesh_prov_link *link, uint8_t xact_id) net_buf_add_u8(buf, xact_id); net_buf_add_u8(buf, GPC_ACK); + BT_DBG("GenericProvAckSend,LinkId:%08x,XActId:%02x", link->link_id, xact_id); bt_mesh_adv_send(buf, PROV_XMIT, complete, link); net_buf_unref(buf); } static void free_segments(struct bt_mesh_prov_link *link) { + BT_DBG("FreeSegments:%08x", link->link_id); for (size_t i = 0; i < ARRAY_SIZE(link->tx.buf); i++) { struct net_buf *buf = link->tx.buf[i]; @@ -386,6 +399,7 @@ static void buf_sent(int err, void *user_data) int32_t timeout = RETRANSMIT_TIMEOUT; if (!link->tx.buf[0]) { + BT_DBG("LinkId:%08x,NoTxBuf", link->link_id); return; } @@ -412,6 +426,8 @@ static void prov_retransmit(struct k_work *work) struct bt_mesh_prov_link *link = work->user_data; int64_t timeout = TRANSACTION_TIMEOUT; + BT_DBG("LinkRetransmit:%08x,flag:%s", link->link_id, bt_hex(link->flags, sizeof(link->flags))); + if (!bt_mesh_atomic_test_bit(link->flags, LINK_ACTIVE) && !bt_mesh_atomic_test_bit(link->flags, LINK_CLOSING)) { BT_WARN("Link not active"); @@ -493,7 +509,7 @@ static void prov_retransmit(struct k_work *work) BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); - if (i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1]) { + if (likely(i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1])) { bt_mesh_adv_send(buf, PROV_XMIT, NULL, NULL); } else { bt_mesh_adv_send(buf, PROV_XMIT, &buf_sent_cb, link); @@ -521,7 +537,7 @@ static void send_reliable(struct bt_mesh_prov_link *link, uint8_t xmit) break; } - if (i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1]) { + if (likely(i + 1 < ARRAY_SIZE(link->tx.buf) && link->tx.buf[i + 1])) { bt_mesh_adv_send(buf, xmit, NULL, NULL); } else { bt_mesh_adv_send(buf, xmit, &buf_sent_cb, link); diff --git a/components/bt/esp_ble_mesh/core/prov_node.c b/components/bt/esp_ble_mesh/core/prov_node.c index cf78947071..973239097d 100644 --- a/components/bt/esp_ble_mesh/core/prov_node.c +++ b/components/bt/esp_ble_mesh/core/prov_node.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -52,6 +52,7 @@ struct bt_mesh_prov_link *bt_mesh_prov_node_get_link(void) static void close_link(uint8_t reason) { + BT_DBG("LinkClose(Rpr:%d),Reason:%d", bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE), reason); if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { if (prov_link.pb_remote_close) { prov_link.pb_remote_close(&prov_link, reason); @@ -69,6 +70,7 @@ void bt_mesh_prov_node_close_link(uint8_t reason) static void reset_state(void) { + BT_INFO("ProvLinkStateReset"); k_delayed_work_cancel(&prov_link.prot_timer); /* Disable Attention Timer if it was set */ @@ -122,6 +124,7 @@ static void reset_adv_link(struct bt_mesh_prov_link *link, uint8_t reason) { ARG_UNUSED(link); + BT_INFO("ResetAdvLink:%08x", link->link_id); bt_mesh_prov_clear_tx(&prov_link, true); if (bt_mesh_prov_get()->link_close) { @@ -267,6 +270,7 @@ static int prov_auth(uint8_t method, uint8_t action, uint8_t size) auth_size = PROV_AUTH_SIZE(&prov_link); + BT_INFO("ProvAuth:method:%d,action:%d,size:%d", method, action, size); switch (method) { case AUTH_METHOD_NO_OOB: if (action || size) { @@ -411,6 +415,7 @@ static void prov_start(const uint8_t *data) if ((bt_mesh_prov_get()->oob_type & BIT(PROV_ONLY_OOB_AUTH_SUPPORT)) && ((data[0] == PROV_ALG_P256_HMAC_SHA256 && data[2] == AUTH_METHOD_NO_OOB) || data[0] == PROV_ALG_P256_CMAC_AES128)) { + BT_WARN("InvalidCapabilities,Alg:%d,Method:%d", data[0], data[2]); close_link(PROV_ERR_NVAL_FMT); return; } @@ -561,9 +566,10 @@ int bt_mesh_input_number(uint32_t num) auth_size = PROV_AUTH_SIZE(&prov_link); - BT_INFO("%u", num); + BT_INFO("ProvInputNumber:%u", num); if (!bt_mesh_atomic_test_and_clear_bit(prov_link.flags, WAIT_NUMBER)) { + BT_WARN("InvalidFlag:WAIT_NUMBER"); return -EINVAL; } @@ -572,6 +578,7 @@ int bt_mesh_input_number(uint32_t num) send_input_complete(); if (!bt_mesh_atomic_test_bit(prov_link.flags, HAVE_DHKEY)) { + BT_INFO("DHKeyExists"); return 0; } @@ -587,6 +594,7 @@ int bt_mesh_input_string(const char *str) BT_INFO("%s", str); if (!bt_mesh_atomic_test_and_clear_bit(prov_link.flags, WAIT_STRING)) { + BT_WARN("InvalidFlag:WAIT_STRING"); return -EINVAL; } @@ -595,6 +603,7 @@ int bt_mesh_input_string(const char *str) send_input_complete(); if (!bt_mesh_atomic_test_bit(prov_link.flags, HAVE_DHKEY)) { + BT_INFO("DHKeyExists"); return 0; } @@ -712,6 +721,7 @@ int bt_mesh_set_oob_pub_key(const uint8_t pub_key_x[32], /* If remote public key is not got, just return */ if (!bt_mesh_atomic_test_bit(prov_link.flags, REMOTE_PUB_KEY)) { + BT_WARN("RemotePubKeyNotSet"); return 0; } @@ -902,6 +912,7 @@ static void prov_data(const uint8_t *data) uint8_t reason = 0; if (bt_mesh_rpr_srv_nppi_check(prov_link.pb_remote_nppi, pdu, net_idx, iv_index, addr, &reason) == false) { + BT_WARN("RprNppiCheckFail:%d", reason); close_link(reason); return; } @@ -924,6 +935,7 @@ static void prov_data(const uint8_t *data) pdu, net_idx, flags, iv_index, addr, dev_key); if (err) { + BT_WARN("RprNppiStoreFail:%d", err); close_link(PROV_ERR_UNEXP_ERR); return; } @@ -964,6 +976,7 @@ static void prov_data(const uint8_t *data) * using Node Identity. */ if (IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && identity_enable) { + BT_DBG("EnableProxyIdentity"); bt_mesh_proxy_identity_enable(); } } @@ -973,7 +986,7 @@ static void prov_complete(const uint8_t *data) static void prov_failed(const uint8_t *data) { - BT_WARN("Error: 0x%02x", data[0]); + BT_WARN("ProvError: 0x%02x", data[0]); #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { @@ -1011,7 +1024,7 @@ static const struct { #if CONFIG_BLE_MESH_PB_ADV static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) { - BT_DBG("len %u", buf->len); + BT_DBG("LinkOpenLen:%u", buf->len); if (buf->len < 16) { BT_ERR("Too short bearer open message (len %u)", buf->len); @@ -1065,7 +1078,7 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf) static void link_ack(struct prov_rx *rx, struct net_buf_simple *buf) { - BT_DBG("len %u", buf->len); + BT_DBG("LinkAckLen:%u",buf->len); #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { @@ -1094,7 +1107,7 @@ static void link_close(struct prov_rx *rx, struct net_buf_simple *buf) { uint8_t reason = 0; - BT_DBG("len %u", buf->len); + BT_DBG("LinkCloseLen %u", buf->len); if (buf->len != 1) { BT_ERR("Invalid Link Close length %d", buf->len); @@ -1258,12 +1271,14 @@ static void gen_prov_ack(struct prov_rx *rx, struct net_buf_simple *buf) BT_DBG("len %u", buf->len); if (!prov_link.tx.buf[0]) { + BT_DBG("AlreadyReceived"); return; } #if CONFIG_BLE_MESH_RPR_SRV if (bt_mesh_atomic_test_bit(prov_link.flags, PB_REMOTE)) { if (prov_link.tx.id == 0) { + BT_DBG("ZeroTxId"); return; } @@ -1278,6 +1293,7 @@ static void gen_prov_ack(struct prov_rx *rx, struct net_buf_simple *buf) #endif /* CONFIG_BLE_MESH_RPR_SRV */ if (rx->xact_id == prov_link.tx.id) { + BT_DBG("XActId:%04x,ReceivedAck", rx->xact_id); bt_mesh_prov_clear_tx(&prov_link, true); } } @@ -1342,7 +1358,7 @@ void bt_mesh_pb_adv_recv(struct net_buf_simple *buf) rx.xact_id = net_buf_simple_pull_u8(buf); rx.gpc = net_buf_simple_pull_u8(buf); - BT_DBG("link_id 0x%08x xact_id %u", rx.link_id, rx.xact_id); + BT_DBG("link_id 0x%08x xact_id %u gpc %u", rx.link_id, rx.xact_id, rx.gpc); if (bt_mesh_atomic_test_bit(prov_link.flags, LINK_ACTIVE) && prov_link.link_id != rx.link_id) { @@ -1441,7 +1457,7 @@ int bt_mesh_pb_gatt_recv(struct bt_mesh_conn *conn, struct net_buf_simple *buf) int bt_mesh_pb_gatt_open(struct bt_mesh_conn *conn) { - BT_DBG("conn %p", conn); + BT_DBG("ProvConnOpen %p", conn); /** * It's necessary to determine if it is PB_REMOTE because when the @@ -1482,7 +1498,7 @@ int bt_mesh_pb_gatt_open(struct bt_mesh_conn *conn) int bt_mesh_pb_gatt_close(struct bt_mesh_conn *conn, uint8_t reason) { - BT_DBG("conn %p", conn); + BT_DBG("ProvConnClose %p", conn); if (prov_link.conn != conn) { BT_ERR("Not connected"); diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index 091e3e8607..e51c7a8d1d 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2017-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -202,6 +202,7 @@ static inline void bt_mesh_pb_gatt_unlock(void) void bt_mesh_provisioner_pbg_count_dec(void) { + BT_DBG("PbgCntDec:%d", prov_ctx.pbg_count); if (prov_ctx.pbg_count) { prov_ctx.pbg_count--; } @@ -210,6 +211,7 @@ void bt_mesh_provisioner_pbg_count_dec(void) static inline void provisioner_pbg_count_inc(void) { prov_ctx.pbg_count++; + BT_DBG("PbgCntInc:%d", prov_ctx.pbg_count); } void bt_mesh_provisioner_clear_link_info(const uint8_t addr[6]) @@ -436,8 +438,8 @@ static int provisioner_start_prov_pb_gatt(const uint8_t uuid[16], const bt_mesh_ */ if (assign_addr == BLE_MESH_ADDR_UNASSIGNED && prov_ctx.alloc_addr == BLE_MESH_ADDR_UNASSIGNED) { - BT_ERR("No available unicast address to assign"); bt_mesh_pb_gatt_unlock(); + BT_ERR("No available unicast address to assign"); return -EIO; } @@ -451,6 +453,7 @@ static int provisioner_start_prov_pb_gatt(const uint8_t uuid[16], const bt_mesh_ !bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE)) { if (bt_mesh_gattc_conn_create(addr, BLE_MESH_UUID_MESH_PROV_VAL)) { bt_mesh_pb_gatt_unlock(); + BT_ERR("ProvGattCreateFailed:%s", bt_hex(addr->val, 6)); return -EIO; } @@ -598,6 +601,7 @@ int bt_mesh_provisioner_add_unprov_dev(struct bt_mesh_unprov_dev_add *add_dev, u start: /* If not provisioning immediately, directly return here */ if (!(flags & START_PROV_NOW)) { + BT_DBG("StartProvNotSet"); return 0; } @@ -617,6 +621,9 @@ start: } if ((err = provisioner_check_unprov_dev_info(add_dev->uuid, add_dev->bearer))) { + if (err == -EALREADY) { + BT_INFO("The device is being provisioning"); + } return err; } @@ -710,6 +717,9 @@ int bt_mesh_provisioner_prov_device_with_addr(const uint8_t uuid[16], const uint } if ((err = provisioner_check_unprov_dev_info(uuid, bearer))) { + if (err == -EALREADY) { + BT_INFO("The device is being provisioning"); + } return err; } @@ -749,10 +759,12 @@ int bt_mesh_provisioner_delete_device(struct bt_mesh_device_delete *del_dev) return -EINVAL; } + BT_INFO("ProvisionerDeleteDevice:%s", bt_hex(del_dev->uuid, 16)); /* Find if the device is in the device queue */ for (i = 0; i < ARRAY_SIZE(unprov_dev); i++) { if (!memcmp(unprov_dev[i].uuid, del_dev->uuid, 16)) { memset(&unprov_dev[i], 0, sizeof(struct unprov_dev_queue)); + BT_INFO("Device is in the queue"); break; } } @@ -761,6 +773,7 @@ int bt_mesh_provisioner_delete_device(struct bt_mesh_device_delete *del_dev) for (i = 0; i < ARRAY_SIZE(prov_links); i++) { if (!memcmp(prov_links[i].uuid, del_dev->uuid, 16)) { close_link(&prov_links[i], CLOSE_REASON_FAILED); + BT_INFO("Device is being provisioned"); break; } } @@ -776,6 +789,7 @@ int bt_mesh_provisioner_set_dev_uuid_match(uint8_t offset, uint8_t length, return -EINVAL; } + BT_INFO("SetUUIDMatch,offset:%d,value:%s,flag:%d", offset, bt_hex(match, length), prov_flag); (void)memset(prov_ctx.match_value, 0, 16); prov_ctx.match_offset = offset; @@ -795,6 +809,7 @@ int bt_mesh_provisioner_adv_pkt_cb_register(unprov_adv_pkt_cb_t cb) return -EINVAL; } + BT_INFO("RegisterAdvCB:%p", notify_unprov_adv_pkt_cb); notify_unprov_adv_pkt_cb = cb; return 0; } @@ -815,6 +830,7 @@ int bt_mesh_provisioner_set_prov_data_info(struct bt_mesh_prov_data_info *info) } prov_ctx.net_idx = info->net_idx; + BT_INFO("SetProvCtx,NetIndex:%d", info->net_idx); } return 0; @@ -881,6 +897,7 @@ void bt_mesh_provisioner_set_prov_bearer(bt_mesh_prov_bearer_t bearers, bool cle } else { prov_ctx.bearers &= ~bearers; } + BT_INFO("ProvCtxBearer:%04x,clear:%d", prov_ctx.bearers, clear); } bt_mesh_prov_bearer_t bt_mesh_provisioner_get_prov_bearer(void) @@ -909,7 +926,7 @@ int bt_mesh_provisioner_set_static_oob_value(const uint8_t *value, uint8_t lengt prov_ctx.static_oob_len = MIN(BLE_MESH_PROV_STATIC_OOB_MAX_LEN, length); memcpy(prov_ctx.static_oob_val, value, prov_ctx.static_oob_len); - + BT_INFO("SetStaticOob:%s", bt_hex(value, prov_ctx.static_oob_len)); return 0; } @@ -984,11 +1001,13 @@ int bt_mesh_test_provisioner_update_alloc_addr(uint16_t unicast_addr, uint16_t e void bt_mesh_provisioner_fast_prov_enable(bool enable) { prov_ctx.fast_prov.enable = enable; + BT_INFO("FastProvEnable:%d", enable); } void bt_mesh_provisioner_set_fast_prov_net_idx(uint16_t net_idx) { prov_ctx.fast_prov.net_idx = net_idx; + BT_INFO("FastProvNetIdx:%d", net_idx); } uint16_t bt_mesh_provisioner_get_fast_prov_net_idx(void) @@ -1017,7 +1036,7 @@ uint8_t bt_mesh_set_fast_prov_unicast_addr_range(uint16_t min, uint16_t max) prov_ctx.fast_prov.unicast_addr_max = max; prov_ctx.alloc_addr = prov_ctx.fast_prov.unicast_addr_min; - + BT_INFO("FastProv,AddrMin:%04x,Max:%04x,allocAddr:%04x", min, max, prov_ctx.alloc_addr); return 0x0; /* status: success */ } @@ -1038,6 +1057,7 @@ static struct net_buf_simple *get_rx_buf(const uint8_t idx) static void reset_adv_link(struct bt_mesh_prov_link *link, uint8_t reason) { + BT_INFO("ResetAdvLink:%08x", link->link_id); bt_mesh_prov_clear_tx(link, true); if (bt_mesh_prov_get()->prov_link_close) { @@ -1106,6 +1126,7 @@ static void send_link_open(struct bt_mesh_prov_link *link) if (bt_mesh_atomic_test_bit(prov_links[i].flags, LINK_ACTIVE) && prov_links[i].link_id == link->link_id) { bt_mesh_rand(&link->link_id, sizeof(link->link_id)); + BT_DBG("ProvLinkIdx:%d,LinkId:%08x", i, link->link_id); break; } } @@ -1280,6 +1301,7 @@ static void prov_capabilities(struct bt_mesh_prov_link *link, if ((algorithms & BIT(PROV_ALG_P256_CMAC_AES128)) || (!((oob_type & BIT(PROV_STATIC_OOB_AVAILABLE)) == 0x00 || output_size == 0x00 || input_size == 0x00))) { + BT_INFO("InvalidOobTypeSet:%02x,Alg:%02x", oob_type, algorithms); goto fail; } } @@ -1358,6 +1380,7 @@ static void prov_capabilities(struct bt_mesh_prov_link *link, * send Remote Provisioning PDU Send with Public Key. */ if (bt_mesh_atomic_test_bit(link->flags, PB_REMOTE)) { + BT_DBG("WaitForRprClientCmd"); return; } @@ -1387,6 +1410,7 @@ static int prov_auth(struct bt_mesh_prov_link *link, bt_mesh_input_action_t input = 0U; uint8_t auth_size = PROV_AUTH_SIZE(link); + BT_INFO("ProvAuth:method:%d,action:%d,size:%d", method, action, size); switch (method) { case AUTH_METHOD_NO_OOB: if (action || size) { @@ -1778,6 +1802,7 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) */ if (link->auth_method == AUTH_METHOD_OUTPUT || link->auth_method == AUTH_METHOD_INPUT) { + BT_INFO("WaitForNextAction:%d", link->auth_method); return; } @@ -1814,6 +1839,7 @@ static void prov_gen_dh_key(struct bt_mesh_prov_link *link) * Input Complete, because if the authentication method is * Output OOB or Input OOB, it will directly return above. */ + BT_DBG("LinkExpect:%d", link->expect); if (link->expect != PROV_INPUT_COMPLETE) { send_confirm(link); } @@ -2094,6 +2120,7 @@ static void send_prov_data(struct bt_mesh_prov_link *link) link->unicast_addr = alloc_addr; } + BT_DBG("ProvAllocAddr:%04x", link->unicast_addr); bt_mesh_prov_buf_init(&buf, PROV_DATA); err = bt_mesh_prov_encrypt(session_key, nonce, pdu, net_buf_simple_add(&buf, 33)); @@ -2310,7 +2337,7 @@ static void prov_complete(struct bt_mesh_prov_link *link, static void prov_failed(struct bt_mesh_prov_link *link, struct net_buf_simple *buf) { - BT_WARN("Error 0x%02x", buf->data[0]); + BT_WARN("ProvError 0x%02x", buf->data[0]); close_link(link, CLOSE_REASON_FAILED); } @@ -2360,7 +2387,7 @@ static void close_link(struct bt_mesh_prov_link *link, uint8_t reason) #if CONFIG_BLE_MESH_PB_ADV static void link_ack(struct bt_mesh_prov_link *link, struct prov_rx *rx, struct net_buf_simple *buf) { - BT_DBG("len %u", buf->len); + BT_DBG("LinkAckLen %u", buf->len); if (buf->len) { BT_ERR("Invalid Link ACK length %d", buf->len); @@ -2388,7 +2415,7 @@ static void link_ack(struct bt_mesh_prov_link *link, struct prov_rx *rx, struct static void link_close(struct bt_mesh_prov_link *link, struct prov_rx *rx, struct net_buf_simple *buf) { - BT_DBG("len %u", buf->len); + BT_DBG("LinkCloseLen %u", buf->len); if (buf->len != 1) { BT_ERR("Invalid Link Close length %d", buf->len); @@ -2511,10 +2538,12 @@ static void gen_prov_ack(struct bt_mesh_prov_link *link, BT_DBG("len %u", buf->len); if (!link->tx.buf[0]) { + BT_DBG("NullTxbuf"); return; } if (!link->tx.id) { + BT_DBG("ZeroTxId"); return; } @@ -2620,7 +2649,7 @@ void bt_mesh_provisioner_pb_adv_recv(struct net_buf_simple *buf) rx.xact_id = net_buf_simple_pull_u8(buf); rx.gpc = net_buf_simple_pull_u8(buf); - BT_DBG("link_id 0x%08x xact_id %u", rx.link_id, rx.xact_id); + BT_DBG("link_id 0x%08x xact_id %u gpc %u", rx.link_id, rx.xact_id, rx.gpc); link = find_pba_link(rx.link_id); if (link == NULL) { @@ -2783,7 +2812,7 @@ static void protocol_timeout(struct k_work *work) { struct bt_mesh_prov_link *link = work->user_data; - BT_WARN("Protocol timeout"); + BT_WARN("Protocol timeout,LinkId:%08x", link->link_id); close_link(link, CLOSE_REASON_TIMEOUT); } @@ -3112,6 +3141,7 @@ int bt_mesh_rpr_cli_pdu_recv(struct bt_mesh_prov_link *link, uint8_t type, return -EINVAL; } + BT_INFO("RprCliProvType:%d", type); prov_handlers[type].func(link, buf); return 0; } From 556eeb934d11d0fd6df8ba6d4c3b467e1cbc45d7 Mon Sep 17 00:00:00 2001 From: Rainer Date: Wed, 3 Sep 2025 18:11:41 +0800 Subject: [PATCH 144/156] fix(ble_mesh): fixed issues with incorrect logs format and position --- components/bt/esp_ble_mesh/core/cfg_cli.c | 36 ++++++++++---------- components/bt/esp_ble_mesh/core/cfg_srv.c | 34 +++++++++--------- components/bt/esp_ble_mesh/core/friend.c | 6 ++-- components/bt/esp_ble_mesh/core/health_cli.c | 8 ++--- components/bt/esp_ble_mesh/core/net.c | 3 ++ 5 files changed, 45 insertions(+), 42 deletions(-) diff --git a/components/bt/esp_ble_mesh/core/cfg_cli.c b/components/bt/esp_ble_mesh/core/cfg_cli.c index e04588fab7..211f80e9ed 100644 --- a/components/bt/esp_ble_mesh/core/cfg_cli.c +++ b/components/bt/esp_ble_mesh/core/cfg_cli.c @@ -237,7 +237,7 @@ static void comp_data_status(struct bt_mesh_model *model, BT_DBG("CompDataStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.page = net_buf_simple_pull_u8(buf); status.comp_data = bt_mesh_alloc_buf(buf->len); @@ -260,7 +260,7 @@ static void state_status_u8(struct bt_mesh_model *model, BT_DBG("StateStatusU8"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); @@ -312,7 +312,7 @@ static void relay_status(struct bt_mesh_model *model, BT_DBG("RelayStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.relay = net_buf_simple_pull_u8(buf); status.retransmit = net_buf_simple_pull_u8(buf); @@ -329,7 +329,7 @@ static void net_key_status(struct bt_mesh_model *model, BT_DBG("NetKeyStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.net_idx = net_buf_simple_pull_le16(buf) & 0xfff; @@ -346,7 +346,7 @@ static void app_key_status(struct bt_mesh_model *model, BT_DBG("AppKeyStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); key_idx_unpack(buf, &status.net_idx, &status.app_idx); @@ -363,7 +363,7 @@ static void mod_app_status(struct bt_mesh_model *model, BT_DBG("ModAppStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.elem_addr = net_buf_simple_pull_le16(buf); @@ -387,7 +387,7 @@ static void mod_pub_status(struct bt_mesh_model *model, BT_DBG("ModPubStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.elem_addr = net_buf_simple_pull_le16(buf); @@ -417,7 +417,7 @@ static void mod_sub_status(struct bt_mesh_model *model, BT_DBG("ModSubStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.elem_addr = net_buf_simple_pull_le16(buf); @@ -441,7 +441,7 @@ static void hb_sub_status(struct bt_mesh_model *model, BT_DBG("HbSubStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.src = net_buf_simple_pull_le16(buf); @@ -463,7 +463,7 @@ static void hb_pub_status(struct bt_mesh_model *model, BT_DBG("HbPubStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.dst = net_buf_simple_pull_le16(buf); @@ -483,7 +483,7 @@ static void node_reset_status(struct bt_mesh_model *model, BT_DBG("NodeResetStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); cfg_client_recv_status(model, ctx, NULL, 0); } @@ -497,7 +497,7 @@ static void mod_sub_list(struct bt_mesh_model *model, BT_DBG("ModSubList"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); list.status = net_buf_simple_pull_u8(buf); list.elem_addr = net_buf_simple_pull_le16(buf); @@ -527,7 +527,7 @@ static void net_key_list(struct bt_mesh_model *model, BT_DBG("NetKeyList"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); list.net_idx = bt_mesh_alloc_buf(buf->len); if (!list.net_idx) { @@ -548,7 +548,7 @@ static void app_key_list(struct bt_mesh_model *model, BT_DBG("AppKeyList"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); list.status = net_buf_simple_pull_u8(buf); list.net_idx = net_buf_simple_pull_le16(buf); @@ -571,7 +571,7 @@ static void node_id_status(struct bt_mesh_model *model, BT_DBG("NodeIDStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.net_idx = net_buf_simple_pull_le16(buf); @@ -589,7 +589,7 @@ static void mod_app_list(struct bt_mesh_model *model, BT_DBG("ModAppList"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); list.status = net_buf_simple_pull_u8(buf); list.elem_addr = net_buf_simple_pull_le16(buf); @@ -619,7 +619,7 @@ static void kr_phase_status(struct bt_mesh_model *model, BT_DBG("KrPhaseStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.status = net_buf_simple_pull_u8(buf); status.net_idx = net_buf_simple_pull_le16(buf); @@ -637,7 +637,7 @@ static void lpn_pollto_status(struct bt_mesh_model *model, BT_DBG("LPNPollToStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.lpn_addr = net_buf_simple_pull_le16(buf); status.timeout = net_buf_simple_pull_u8(buf); diff --git a/components/bt/esp_ble_mesh/core/cfg_srv.c b/components/bt/esp_ble_mesh/core/cfg_srv.c index 84cdb59b3a..12448eec81 100644 --- a/components/bt/esp_ble_mesh/core/cfg_srv.c +++ b/components/bt/esp_ble_mesh/core/cfg_srv.c @@ -144,7 +144,7 @@ static void get_comp_data(struct net_buf_simple *buf, } } - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); } static int fetch_comp_data(struct net_buf_simple *buf, @@ -213,7 +213,7 @@ static void comp_data_get(struct bt_mesh_model *model, BT_DBG("CompDataGet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); /* TODO: * @@ -817,7 +817,7 @@ static void beacon_get(struct bt_mesh_model *model, BT_DBG("BeaconGet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_BEACON_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_secure_beacon_get()); @@ -837,7 +837,7 @@ static void beacon_set(struct bt_mesh_model *model, BT_DBG("BeaconSet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (!cfg) { BT_WARN("No Configuration Server context available"); @@ -877,7 +877,7 @@ static void default_ttl_get(struct bt_mesh_model *model, BT_DBG("DefaultTTLGet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_DEFAULT_TTL_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_default_ttl_get()); @@ -897,7 +897,7 @@ static void default_ttl_set(struct bt_mesh_model *model, BT_DBG("DefaultTTLSet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (!cfg) { BT_WARN("No Configuration Server context available"); @@ -944,7 +944,7 @@ static void gatt_proxy_get(struct bt_mesh_model *model, BT_DBG("GattProxyGet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); send_gatt_proxy_status(model, ctx); } @@ -958,7 +958,7 @@ static void gatt_proxy_set(struct bt_mesh_model *model, BT_DBG("GattProxySet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->data[0] != 0x00 && buf->data[0] != 0x01) { BT_WARN("Invalid GATT Proxy value 0x%02x", buf->data[0]); @@ -1021,7 +1021,7 @@ static void net_transmit_get(struct bt_mesh_model *model, BT_DBG("NetTransmitGet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_NET_TRANSMIT_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_net_transmit_get()); @@ -1041,7 +1041,7 @@ static void net_transmit_set(struct bt_mesh_model *model, BT_DBG("NetTransmitSet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); BT_DBG("Transmit 0x%02x Count %u Interval %u", buf->data[0], @@ -1075,7 +1075,7 @@ static void relay_get(struct bt_mesh_model *model, BT_DBG("RelayGet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_RELAY_STATUS); net_buf_simple_add_u8(&msg, bt_mesh_relay_get()); @@ -1096,7 +1096,7 @@ static void relay_set(struct bt_mesh_model *model, BT_DBG("RelaySet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (!cfg) { BT_WARN("No Configuration Server context available"); @@ -2777,7 +2777,7 @@ static void node_identity_get(struct bt_mesh_model *model, BT_DBG("NodeIdentityGet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -2817,7 +2817,7 @@ static void node_identity_set(struct bt_mesh_model *model, BT_DBG("NodeIdentitySet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { @@ -3098,7 +3098,7 @@ static void node_reset(struct bt_mesh_model *model, BT_DBG("NodeReset"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); bt_mesh_model_msg_init(&msg, OP_NODE_RESET_STATUS); @@ -3137,7 +3137,7 @@ static void friend_get(struct bt_mesh_model *model, BT_DBG("FrndGet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); send_friend_status(model, ctx); } @@ -3151,7 +3151,7 @@ static void friend_set(struct bt_mesh_model *model, BT_DBG("FrndSet"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); if (buf->data[0] != 0x00 && buf->data[0] != 0x01) { BT_WARN("Invalid Friend value 0x%02x", buf->data[0]); diff --git a/components/bt/esp_ble_mesh/core/friend.c b/components/bt/esp_ble_mesh/core/friend.c index 07de4b7d3c..0f602f1d35 100644 --- a/components/bt/esp_ble_mesh/core/friend.c +++ b/components/bt/esp_ble_mesh/core/friend.c @@ -332,7 +332,7 @@ static bool friend_sub_exist(struct bt_mesh_friend *frnd, uint16_t addr) { int i; - BT_DBG("IsFrndSubExist, Addr 0x%04x"); + BT_DBG("IsFrndSubExist, Addr 0x%04x", addr); for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == addr) { @@ -347,7 +347,7 @@ static void friend_sub_add(struct bt_mesh_friend *frnd, uint16_t addr) { int i; - BT_DBG("FrndSubAdd, Addr 0x%04x"); + BT_DBG("FrndSubAdd, Addr 0x%04x", addr); for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == BLE_MESH_ADDR_UNASSIGNED) { @@ -363,7 +363,7 @@ static void friend_sub_rem(struct bt_mesh_friend *frnd, uint16_t addr) { int i; - BT_DBG("FrndSubRem, Addr 0x%04x"); + BT_DBG("FrndSubRem, Addr 0x%04x", addr); for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) { if (frnd->sub_list[i] == addr) { diff --git a/components/bt/esp_ble_mesh/core/health_cli.c b/components/bt/esp_ble_mesh/core/health_cli.c index 829ae33693..c458710db1 100644 --- a/components/bt/esp_ble_mesh/core/health_cli.c +++ b/components/bt/esp_ble_mesh/core/health_cli.c @@ -138,7 +138,7 @@ static void health_fault_status(struct bt_mesh_model *model, BT_DBG("HealthFaultStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.test_id = net_buf_simple_pull_u8(buf); status.cid = net_buf_simple_pull_le16(buf); @@ -162,7 +162,7 @@ static void health_current_status(struct bt_mesh_model *model, BT_DBG("HealthCurrentStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status.test_id = net_buf_simple_pull_u8(buf); status.cid = net_buf_simple_pull_le16(buf); @@ -186,7 +186,7 @@ static void health_period_status(struct bt_mesh_model *model, BT_DBG("HealthPeriodStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); @@ -202,7 +202,7 @@ static void health_attention_status(struct bt_mesh_model *model, BT_DBG("HealthAttentionStatus"); BT_DBG("NetIdx 0x%04x AppIdx 0x%04x Src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - BT_DBG("Len %u: %s", bt_hex(buf->data, buf->len)); + BT_DBG("Len %u: %s", buf->len, bt_hex(buf->data, buf->len)); status = net_buf_simple_pull_u8(buf); diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index 5ddbb46ca0..3282120de8 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.c @@ -2094,6 +2094,9 @@ void bt_mesh_generic_net_recv(struct net_buf_simple *data, /* Save the state so the buffer can later be relayed */ net_buf_simple_save(buf, &state); + BT_DBG("NetRecv, Src 0x%04x Dst 0x%04x Rssi %d NetIf %u", + rx->ctx.addr, rx->ctx.recv_dst, rx->ctx.recv_rssi, net_if); + BT_BQB(BLE_MESH_BQB_TEST_LOG_LEVEL_PRIMARY_ID_NODE | \ BLE_MESH_BQB_TEST_LOG_LEVEL_SUB_ID_NET, "\nNetRecv: ctl: %d, src: %d, dst: %d, ttl: %d, data: 0x%s", From dfde4492d701d1c343f755b866b96837fba16e8e Mon Sep 17 00:00:00 2001 From: luoxu Date: Tue, 9 Sep 2025 15:31:01 +0800 Subject: [PATCH 145/156] fix(ble_mesh): resolve miscellaneous logging issues --- components/bt/esp_ble_mesh/core/adv.c | 4 +- components/bt/esp_ble_mesh/core/adv_common.c | 55 ++++--------------- components/bt/esp_ble_mesh/core/adv_common.h | 42 ++++++++++++++ components/bt/esp_ble_mesh/core/cfg_srv.c | 2 +- components/bt/esp_ble_mesh/core/ext_adv.c | 3 +- components/bt/esp_ble_mesh/core/friend.c | 4 +- components/bt/esp_ble_mesh/core/net.c | 2 +- components/bt/esp_ble_mesh/core/prov_pvnr.c | 2 +- .../bt/esp_ble_mesh/core/proxy_server.c | 8 +-- components/bt/esp_ble_mesh/core/transport.c | 2 +- .../bt/esp_ble_mesh/core/transport.enh.c | 20 +------ 11 files changed, 67 insertions(+), 77 deletions(-) diff --git a/components/bt/esp_ble_mesh/core/adv.c b/components/bt/esp_ble_mesh/core/adv.c index bb7b9771ca..9a12e8c125 100644 --- a/components/bt/esp_ble_mesh/core/adv.c +++ b/components/bt/esp_ble_mesh/core/adv.c @@ -29,10 +29,8 @@ static struct bt_mesh_adv_queue *adv_queue; #if CONFIG_BLE_MESH_RELAY_ADV_BUF -#define BLE_MESH_RELAY_QUEUE_SIZE CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT - static QueueSetHandle_t mesh_queue_set; -#define BLE_MESH_QUEUE_SET_SIZE (BLE_MESH_ADV_QUEUE_SIZE + BLE_MESH_RELAY_QUEUE_SIZE) +#define BLE_MESH_QUEUE_SET_SIZE (bt_mesh_adv_buf_count_get() + bt_mesh_relay_adv_buf_count_get()) #endif /* CONFIG_BLE_MESH_RELAY_ADV_BUF */ static int adv_send(struct net_buf *buf) diff --git a/components/bt/esp_ble_mesh/core/adv_common.c b/components/bt/esp_ble_mesh/core/adv_common.c index 193dcf4c43..ff4e50ac1c 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.c +++ b/components/bt/esp_ble_mesh/core/adv_common.c @@ -158,7 +158,7 @@ int bt_mesh_adv_inst_init(enum bt_mesh_adv_inst_type inst_type, uint8_t inst_id) return -EINVAL; } - if (inst_id == BLE_MESH_ADV_INS_UNUSED) { + if (inst_id == BLE_MESH_ADV_INST_UNUSED) { BT_ERR("UnusedAdvInstID"); return -EINVAL; } @@ -181,7 +181,7 @@ int bt_mesh_adv_inst_deinit(enum bt_mesh_adv_inst_type inst_type) bt_le_ext_adv_stop(adv_insts[inst_type].id); - adv_insts[inst_type].id = BLE_MESH_ADV_INS_UNUSED; + adv_insts[inst_type].id = BLE_MESH_ADV_INST_UNUSED; #if CONFIG_BLE_MESH_SUPPORT_MULTI_ADV adv_insts[inst_type].spt_mask = 0; #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ @@ -243,7 +243,7 @@ struct bt_mesh_adv *ext_long_relay_adv_alloc(int id, enum bt_mesh_adv_type type) #endif /* CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT */ #endif /* CONFIG_BLE_MESH_LONG_PACKET */ -struct bt_mesh_adv_type_manager *bt_mesh_adv_types_mgnt_get(enum bt_mesh_adv_type adv_type) +struct bt_mesh_adv_type_manager *bt_mesh_adv_types_mgmt_get(enum bt_mesh_adv_type adv_type) { BT_DBG("AdvTypeMgmtGet, AdvType %u", adv_type); @@ -668,21 +668,6 @@ uint16_t bt_mesh_get_stored_relay_count(void) return count; } -static ALWAYS_INLINE -uint16_t bt_mesh_relay_adv_buf_count_get(void) -{ - uint16_t relay_adv_count = 2 + CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT; - -#if CONFIG_BLE_MESH_EXT_ADV && CONFIG_BLE_MESH_RELAY - relay_adv_count += CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT; -#endif - -#if CONFIG_BLE_MESH_LONG_PACKET && CONFIG_BLE_MESH_RELAY - relay_adv_count += CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT; -#endif - return relay_adv_count; -} - void bt_mesh_relay_adv_init(void) { BT_DBG("RelayAdvInit"); @@ -806,33 +791,6 @@ void bt_mesh_frnd_adv_deinit(void) } #endif /* CONFIG_BLE_MESH_FRIEND */ -static ALWAYS_INLINE -uint16_t bt_mesh_adv_buf_count_get(void) -{ - uint16_t adv_count = 2 + CONFIG_BLE_MESH_ADV_BUF_COUNT; - -#if CONFIG_BLE_MESH_EXT_ADV - adv_count += CONFIG_BLE_MESH_EXT_ADV_BUF_COUNT; -#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY - adv_count += CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT; -#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY */ -#endif /* CONFIG_BLE_MESH_EXT_ADV */ - -#if CONFIG_BLE_MESH_LONG_PACKET - adv_count += CONFIG_BLE_MESH_LONG_PACKET_ADV_BUF_COUNT; -#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY - adv_count += CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT; -#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY */ -#endif /* CONFIG_BLE_MESH_LONG_PACKET */ - -#if (CONFIG_BLE_MESH_SUPPORT_BLE_ADV && \ - !(CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE)) - adv_count += CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT; -#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ - - return adv_count; -} - void bt_mesh_adv_task_init(void adv_thread(void *p)) { BT_DBG("AdvTaskInit"); @@ -861,7 +819,14 @@ void bt_mesh_adv_task_init(void adv_thread(void *p)) #else /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */ int ret = xTaskCreatePinnedToCore(adv_thread, BLE_MESH_ADV_TASK_NAME, BLE_MESH_ADV_TASK_STACK_SIZE, NULL, BLE_MESH_ADV_TASK_PRIO, &adv_task.handle, BLE_MESH_ADV_TASK_CORE); +#if CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE + if (ret != pdTRUE) { + BT_ERR("xTaskCreatePinnedToCore failed, ret %d", ret); + return; + } +#else assert(ret == pdTRUE); +#endif /* CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE */ #endif /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */ } diff --git a/components/bt/esp_ble_mesh/core/adv_common.h b/components/bt/esp_ble_mesh/core/adv_common.h index f77079a648..54267ee522 100644 --- a/components/bt/esp_ble_mesh/core/adv_common.h +++ b/components/bt/esp_ble_mesh/core/adv_common.h @@ -298,6 +298,21 @@ void bt_mesh_adv_inst_type_clear(enum bt_mesh_adv_inst_type inst_type, #endif /* CONFIG_BLE_MESH_SUPPORT_MULTI_ADV */ #if CONFIG_BLE_MESH_RELAY_ADV_BUF +static ALWAYS_INLINE +uint16_t bt_mesh_relay_adv_buf_count_get(void) +{ + uint16_t relay_adv_count = 2 + CONFIG_BLE_MESH_RELAY_ADV_BUF_COUNT; + +#if CONFIG_BLE_MESH_EXT_ADV && CONFIG_BLE_MESH_RELAY + relay_adv_count += CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT; +#endif + +#if CONFIG_BLE_MESH_LONG_PACKET && CONFIG_BLE_MESH_RELAY + relay_adv_count += CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT; +#endif + return relay_adv_count; +} + void bt_mesh_relay_adv_init(void); bool bt_mesh_ignore_relay_packet(uint32_t timestamp); @@ -325,6 +340,33 @@ void bt_mesh_frnd_adv_deinit(void); #endif /* CONFIG_BLE_MESH_DEINIT */ #endif /* CONFIG_BLE_MESH_FRIEND */ +static ALWAYS_INLINE +uint16_t bt_mesh_adv_buf_count_get(void) +{ + uint16_t adv_count = 2 + CONFIG_BLE_MESH_ADV_BUF_COUNT; + +#if CONFIG_BLE_MESH_EXT_ADV + adv_count += CONFIG_BLE_MESH_EXT_ADV_BUF_COUNT; +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY + adv_count += CONFIG_BLE_MESH_EXT_RELAY_ADV_BUF_COUNT; +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY */ +#endif /* CONFIG_BLE_MESH_EXT_ADV */ + +#if CONFIG_BLE_MESH_LONG_PACKET + adv_count += CONFIG_BLE_MESH_LONG_PACKET_ADV_BUF_COUNT; +#if !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY + adv_count += CONFIG_BLE_MESH_LONG_PACKET_RELAY_ADV_BUF_COUNT; +#endif /* !CONFIG_BLE_MESH_RELAY_ADV_BUF && CONFIG_BLE_MESH_RELAY */ +#endif /* CONFIG_BLE_MESH_LONG_PACKET */ + +#if (CONFIG_BLE_MESH_SUPPORT_BLE_ADV && \ + !(CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BLE_MESH_SEPARATE_BLE_ADV_INSTANCE)) + adv_count += CONFIG_BLE_MESH_BLE_ADV_BUF_COUNT; +#endif /* CONFIG_BLE_MESH_SUPPORT_BLE_ADV */ + + return adv_count; +} + void bt_mesh_adv_task_init(void adv_thread(void *p)); void bt_mesh_adv_common_init(void); diff --git a/components/bt/esp_ble_mesh/core/cfg_srv.c b/components/bt/esp_ble_mesh/core/cfg_srv.c index 12448eec81..9be3e51983 100644 --- a/components/bt/esp_ble_mesh/core/cfg_srv.c +++ b/components/bt/esp_ble_mesh/core/cfg_srv.c @@ -3356,7 +3356,7 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, static uint8_t hb_log(uint16_t val) { BT_DBG("HbLog, Val 0x%04x", val); - + switch (val) { case 0x0000: return 0x00; diff --git a/components/bt/esp_ble_mesh/core/ext_adv.c b/components/bt/esp_ble_mesh/core/ext_adv.c index 37000ce73e..8b85076aed 100644 --- a/components/bt/esp_ble_mesh/core/ext_adv.c +++ b/components/bt/esp_ble_mesh/core/ext_adv.c @@ -142,7 +142,8 @@ static int adv_send(struct bt_mesh_adv_inst *inst, uint16_t *adv_duration) err = bt_le_ext_adv_start(inst->id, ¶m, &ad, 1, NULL, 0); } - break; + } + break; #if CONFIG_BLE_MESH_SUPPORT_BLE_ADV case BLE_MESH_ADV_BLE: diff --git a/components/bt/esp_ble_mesh/core/friend.c b/components/bt/esp_ble_mesh/core/friend.c index 0f602f1d35..46060d3b0f 100644 --- a/components/bt/esp_ble_mesh/core/friend.c +++ b/components/bt/esp_ble_mesh/core/friend.c @@ -792,7 +792,7 @@ int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx, static void enqueue_buf(struct bt_mesh_friend *frnd, struct net_buf *buf) { - BT_DBG("EnqueueBuf, Buf %p QueueSize %u", __func__, buf, frnd->queue_size); + BT_DBG("EnqueueBuf, Buf %p QueueSize %u", buf, frnd->queue_size); net_buf_slist_put(&frnd->queue, buf); frnd->queue_size++; @@ -802,7 +802,7 @@ static void enqueue_update(struct bt_mesh_friend *frnd, uint8_t md) { struct net_buf *buf = NULL; - BT_DBG("EnqueueUpdate, LPN 0x%04x MD %u", __func__, frnd->lpn, md); + BT_DBG("EnqueueUpdate, LPN 0x%04x MD %u", frnd->lpn, md); buf = encode_update(frnd, md); if (!buf) { diff --git a/components/bt/esp_ble_mesh/core/net.c b/components/bt/esp_ble_mesh/core/net.c index 3282120de8..fde5b5cdda 100644 --- a/components/bt/esp_ble_mesh/core/net.c +++ b/components/bt/esp_ble_mesh/core/net.c @@ -104,7 +104,7 @@ static bool check_dup(struct net_buf_simple *data) } } - BT_DBG("DupCacheAdd, CacheNext %ld", val, dup_cache_next); + BT_DBG("DupCacheAdd, CacheNext %ld %d", val, dup_cache_next); dup_cache[dup_cache_next++] = val; dup_cache_next %= ARRAY_SIZE(dup_cache); diff --git a/components/bt/esp_ble_mesh/core/prov_pvnr.c b/components/bt/esp_ble_mesh/core/prov_pvnr.c index e51c7a8d1d..d1df4a69e1 100644 --- a/components/bt/esp_ble_mesh/core/prov_pvnr.c +++ b/components/bt/esp_ble_mesh/core/prov_pvnr.c @@ -2812,7 +2812,7 @@ static void protocol_timeout(struct k_work *work) { struct bt_mesh_prov_link *link = work->user_data; - BT_WARN("Protocol timeout,LinkId:%08x", link->link_id); + BT_WARN("Protocol timeout,RmtAddr:%s", bt_hex(link->addr.val, 6)); close_link(link, CLOSE_REASON_TIMEOUT); } diff --git a/components/bt/esp_ble_mesh/core/proxy_server.c b/components/bt/esp_ble_mesh/core/proxy_server.c index 6a498f7508..6021ca7f8f 100644 --- a/components/bt/esp_ble_mesh/core/proxy_server.c +++ b/components/bt/esp_ble_mesh/core/proxy_server.c @@ -36,7 +36,7 @@ _Static_assert(!(IS_ENABLED(CONFIG_BLE_MESH_GATT_PROXY_SERVER) && IS_ENABLED(CON #endif #if CONFIG_BLE_MESH_USE_BLE_50 -static uint8_t proxy_adv_inst = BLE_MESH_ADV_INS_UNUSED; +static uint8_t proxy_adv_inst = BLE_MESH_ADV_INST_UNUSED; #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ #define ADV_OPT (BLE_MESH_ADV_OPT_CONNECTABLE | BLE_MESH_ADV_OPT_ONE_TIME) @@ -2028,7 +2028,7 @@ int32_t bt_mesh_proxy_server_adv_start(void) } #if CONFIG_BLE_MESH_USE_BLE_50 - if (proxy_adv_inst == BLE_MESH_ADV_INS_UNUSED) { + if (proxy_adv_inst == BLE_MESH_ADV_INST_UNUSED) { BT_DBG("ProxyAdvInstUnused"); return K_FOREVER; } @@ -2108,7 +2108,7 @@ int bt_mesh_proxy_server_adv_stop(void) } #if CONFIG_BLE_MESH_USE_BLE_50 - if (proxy_adv_inst == BLE_MESH_ADV_INS_UNUSED) { + if (proxy_adv_inst == BLE_MESH_ADV_INST_UNUSED) { BT_ERR("Proxy adv inst is not initialized!"); return -EINVAL; } @@ -2189,7 +2189,7 @@ int bt_mesh_proxy_server_deinit(void) BT_DBG("ProxyServerDeinit"); #if CONFIG_BLE_MESH_USE_BLE_50 - proxy_adv_inst = BLE_MESH_ADV_INS_UNUSED; + proxy_adv_inst = BLE_MESH_ADV_INST_UNUSED; #endif /* CONFIG_BLE_MESH_USE_BLE_50 */ bt_mesh_proxy_server_adv_flag_set(false); diff --git a/components/bt/esp_ble_mesh/core/transport.c b/components/bt/esp_ble_mesh/core/transport.c index 62704ccfa8..204854e241 100644 --- a/components/bt/esp_ble_mesh/core/transport.c +++ b/components/bt/esp_ble_mesh/core/transport.c @@ -788,7 +788,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, uint8_t aid = 0U; int err = 0; - BT_DBG("TransSend"); + BT_DBG("transcend"); if (msg->len < 1) { BT_ERR("Zero-length SDU not allowed"); diff --git a/components/bt/esp_ble_mesh/core/transport.enh.c b/components/bt/esp_ble_mesh/core/transport.enh.c index 5721d6635a..967b523379 100644 --- a/components/bt/esp_ble_mesh/core/transport.enh.c +++ b/components/bt/esp_ble_mesh/core/transport.enh.c @@ -1199,7 +1199,7 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg, uint8_t aid = 0U; int err = 0; - BT_DBG("TransSend"); + BT_DBG("transcend"); if (msg->len < 1) { BT_ERR("Zero-length SDU not allowed"); @@ -2220,7 +2220,6 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, { int err = 0; -<<<<<<< HEAD /* By default, traditional seg_rx is used for allocation. * If the first segment received is the last segment of * the long packet, and its length is the length of the traditional packet, @@ -2240,12 +2239,8 @@ static struct seg_rx *seg_rx_alloc(struct bt_mesh_net_rx *net_rx, for (size_t i = 0; i < rx_buf_size; i++) { struct seg_rx *rx = &seg_rx_buf[i]; -======= - BT_DBG("SegRxAlloc, SegN %u", seg_n); - for (size_t i = 0; i < ARRAY_SIZE(seg_rx); i++) { - struct seg_rx *rx = &seg_rx[i]; ->>>>>>> 7652269a401 (feat(ble_mesh): Miscellaneous log enhancement for BLE Mesh) + BT_DBG("SegRxAlloc, SegN %u", seg_n); if (rx->in_use) { continue; @@ -2474,20 +2469,14 @@ found_rx: /* Set the expected final buffer length */ rx->buf.len = seg_n * seg_len(&si) + buf->len; -<<<<<<< HEAD BT_DBG("Target len %u * %u + %u = %u", seg_n, seg_len(&si), buf->len, rx->buf.len); -======= - BT_DBG("Target len %u * %u + %u = %u", - seg_n, seg_len(rx->ctl), buf->len, rx->buf.len); ->>>>>>> 7652269a401 (feat(ble_mesh): Miscellaneous log enhancement for BLE Mesh) /* This should not happen, since we have made sure the whole * SDU could be received while handling the first segment. * But if the peer device sends the segments of a segmented * message with different CTL, then the following could happen. */ -<<<<<<< HEAD if ((!rx->ext && rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) #if CONFIG_BLE_MESH_LONG_PACKET || (rx->ext && rx->buf.len > BLE_MESH_EXT_RX_SDU_MAX) @@ -2495,11 +2484,6 @@ found_rx: ) { BT_ERR("Too large SDU len %u/%u", rx->buf.len, CONFIG_BLE_MESH_RX_SDU_MAX); -======= - if (rx->buf.len > CONFIG_BLE_MESH_RX_SDU_MAX) { - BT_ERR("Too large SDU len %u/%u", - rx->buf.len, CONFIG_BLE_MESH_RX_SDU_MAX); ->>>>>>> 7652269a401 (feat(ble_mesh): Miscellaneous log enhancement for BLE Mesh) send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, From 3dc98549f8844bb417b67aebd4d50891afee95bd Mon Sep 17 00:00:00 2001 From: Luo Xu Date: Fri, 28 Nov 2025 17:43:50 +0800 Subject: [PATCH 146/156] fix(ble_mesh): add proper memory cleanup in composition data parsing (cherry picked from commit a45bb6c5dae5680c3c2865de43462aa217c973c0) Co-authored-by: luoxu --- .../rpr_client/main/main.c | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c index 6b816d6d84..dcfdab25ae 100644 --- a/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c +++ b/examples/bluetooth/esp_ble_mesh/remote_provisioning/rpr_client/main/main.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -353,26 +353,22 @@ static void example_ble_mesh_parse_node_comp_data(esp_ble_mesh_node_info_t* node node->sig_model_num = (uint8_t *)calloc(node->elem_num, sizeof(uint8_t)); if (!node->sig_model_num) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto calloc_fail; } node->vnd_model_num = (uint8_t *)calloc(node->elem_num, sizeof(uint8_t)); if (!node->vnd_model_num) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto vnd_model_num_fail; } node->sig_models = (uint16_t **)calloc(node->elem_num, sizeof(uint16_t*)); if (!node->sig_models) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto sig_models_fail; } node->vnd_models = (uint32_t **)calloc(node->elem_num, sizeof(uint32_t*)); - if (!node->sig_models) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + if (!node->vnd_models) { + goto vnd_models_fail; } ESP_LOGI(TAG, "********************** Composition Data Start **********************"); @@ -387,8 +383,7 @@ static void example_ble_mesh_parse_node_comp_data(esp_ble_mesh_node_info_t* node if (nums) { node->sig_models[seq] = (uint16_t *)calloc(nums, sizeof(uint16_t)); if (!(node->sig_models[seq])) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto sig_mode_seq_fail; } } else { node->sig_models[seq] = NULL; @@ -397,8 +392,7 @@ static void example_ble_mesh_parse_node_comp_data(esp_ble_mesh_node_info_t* node if (numv) { node->vnd_models[seq] = (uint32_t *)calloc(numv, sizeof(uint32_t)); if (!(node->vnd_models[seq])) { - ESP_LOGW(TAG, "No Free memory to store composition data"); - return; + goto vnd_model_seq_fail; } } else { node->vnd_models[seq] = NULL; @@ -422,6 +416,32 @@ static void example_ble_mesh_parse_node_comp_data(esp_ble_mesh_node_info_t* node seq++; } ESP_LOGI(TAG, "*********************** Composition Data End ***********************"); + return; + +vnd_model_seq_fail: + free(node->sig_models[seq]); + node->sig_models[seq] = NULL; +sig_mode_seq_fail: + for (int j = 0; j < seq; j++) { + free(node->sig_models[j]); + free(node->vnd_models[j]); + node->sig_models[j] = NULL; + node->vnd_models[j] = NULL; + } + free(node->vnd_models); + node->vnd_models = NULL; +vnd_models_fail: + free(node->sig_models); + node->sig_models = NULL; +sig_models_fail: + free(node->vnd_model_num); + node->vnd_model_num = NULL; +vnd_model_num_fail: + free(node->sig_model_num); + node->sig_model_num = NULL; +calloc_fail: + ESP_LOGW(TAG, "No Free memory to store composition data"); + return; } static bool example_ble_mesh_query_element_have_model(uint16_t elem_addr, uint16_t model_id, uint16_t company_id) @@ -435,6 +455,10 @@ static bool example_ble_mesh_query_element_have_model(uint16_t elem_addr, uint16 elem_idx = elem_addr - node->unicast; + if (node->sig_model_num == NULL) { + return false; + } + if (company_id == CID_NVAL) { model_num = node->sig_model_num[elem_idx]; for (i = 0; i < model_num; i++) { From ef87f313479041e7659d31370114174ebe84057d Mon Sep 17 00:00:00 2001 From: Luo Xu Date: Mon, 15 Dec 2025 17:43:26 +0800 Subject: [PATCH 147/156] fix(ble_mesh): fix memory issue in nimble gap event forwarding (cherry picked from commit aeab65c1a749c123add978cdf51ace4151ec67ed) Co-authored-by: luoxu --- .../bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h | 3 +++ components/bt/esp_ble_mesh/btc/btc_ble_mesh_ble.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h index 83d7e62760..cdada119b4 100644 --- a/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h +++ b/components/bt/esp_ble_mesh/api/core/include/esp_ble_mesh_ble_api.h @@ -97,6 +97,9 @@ typedef union { #if CONFIG_BLE_MESH_USE_BLE_50 && CONFIG_BT_NIMBLE_ENABLED /** * @brief Event parameters of ESP_BLE_MESH_NIMBLE_GAP_EVENT_EVT + * @note The execution environment of this event is different + * from other BLE Mesh events, as it runs in the NimBLE Host's + * execution environment. */ struct ble_mesh_nimble_gap_event_evt_param { struct ble_gap_event event; /*!< GAP event parameters for NimBLE Host */ diff --git a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_ble.c b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_ble.c index 2769960029..ac397aeb18 100644 --- a/components/bt/esp_ble_mesh/btc/btc_ble_mesh_ble.c +++ b/components/bt/esp_ble_mesh/btc/btc_ble_mesh_ble.c @@ -14,6 +14,8 @@ #include "esp_ble_mesh_ble_api.h" #if (CONFIG_BLE_MESH_BLE_COEX_SUPPORT || CONFIG_BLE_MESH_USE_BLE_50) +static inline void btc_ble_mesh_ble_cb_to_app(esp_ble_mesh_ble_cb_event_t event, + esp_ble_mesh_ble_cb_param_t *param); static void btc_ble_mesh_ble_copy_req_data(btc_msg_t *msg, void *p_dst, void *p_src) { #if CONFIG_BLE_MESH_SUPPORT_BLE_SCAN @@ -99,7 +101,7 @@ void bt_mesh_ble_nimble_evt_to_btc(struct ble_gap_event *event, void *arg) memcpy(¶m.nimble_gap_evt.event, event, sizeof(struct ble_gap_event)); param.nimble_gap_evt.arg = arg; - btc_ble_mesh_ble_callback(¶m, ESP_BLE_MESH_NIMBLE_GAP_EVENT_EVT); + btc_ble_mesh_ble_cb_to_app(ESP_BLE_MESH_NIMBLE_GAP_EVENT_EVT, ¶m); } #endif /* CONFIG_BT_NIMBLE_ENABLED && CONFIG_BLE_MESH_USE_BLE_50 */ From a1265f300c70340a6cc3bf6ecc8d11fb6cc966c9 Mon Sep 17 00:00:00 2001 From: suda-morris <362953310@qq.com> Date: Sat, 20 Dec 2025 11:27:34 +0800 Subject: [PATCH 148/156] feat(dsi_lcd): pixel clock frequency can be a float number --- components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c | 7 +- components/esp_lcd/dsi/esp_lcd_panel_dpi.c | 5 +- .../esp_lcd/dsi/include/esp_lcd_mipi_dsi.h | 4 +- components/hal/include/hal/mipi_dsi_hal.h | 13 +-- components/hal/mipi_dsi_hal.c | 80 ++++++++++++------- 5 files changed, 66 insertions(+), 43 deletions(-) diff --git a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c index 2979a1365a..cc887628f2 100644 --- a/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c +++ b/components/esp_lcd/dsi/esp_lcd_mipi_dsi_bus.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include #include "esp_lcd_mipi_dsi.h" #include "esp_clk_tree.h" #include "mipi_dsi_priv.h" @@ -19,7 +20,7 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc ESP_ERR_INVALID_ARG, TAG, "invalid number of data lanes %d", bus_config->num_data_lanes); ESP_RETURN_ON_FALSE(bus_config->lane_bit_rate_mbps >= MIPI_DSI_LL_MIN_PHY_MBPS && bus_config->lane_bit_rate_mbps <= MIPI_DSI_LL_MAX_PHY_MBPS, ESP_ERR_INVALID_ARG, TAG, - "invalid lane bit rate %"PRIu32, bus_config->lane_bit_rate_mbps); + "invalid lane bit rate %.2f", bus_config->lane_bit_rate_mbps); // we don't use an bus allocator here, because different DSI bus uses different PHY. // And each PHY has its own associated PINs, which is not changeable. @@ -114,9 +115,9 @@ esp_err_t esp_lcd_new_dsi_bus(const esp_lcd_dsi_bus_config_t *bus_config, esp_lc mipi_dsi_host_ll_enable_tx_eotp(hal->host, true, false); // Set the divider to get the Time Out clock, clock source is the high-speed byte clock - mipi_dsi_host_ll_set_timeout_clock_division(hal->host, bus_config->lane_bit_rate_mbps / 8 / MIPI_DSI_DEFAULT_TIMEOUT_CLOCK_FREQ_MHZ); + mipi_dsi_host_ll_set_timeout_clock_division(hal->host, (uint32_t)roundf(bus_config->lane_bit_rate_mbps / 8.0f / MIPI_DSI_DEFAULT_TIMEOUT_CLOCK_FREQ_MHZ)); // Set the divider to get the TX Escape clock, clock source is the high-speed byte clock - mipi_dsi_host_ll_set_escape_clock_division(hal->host, bus_config->lane_bit_rate_mbps / 8 / MIPI_DSI_DEFAULT_ESCAPE_CLOCK_FREQ_MHZ); + mipi_dsi_host_ll_set_escape_clock_division(hal->host, (uint32_t)roundf(bus_config->lane_bit_rate_mbps / 8.0f / MIPI_DSI_DEFAULT_ESCAPE_CLOCK_FREQ_MHZ)); // set the timeout intervals to zero, means to disable the timeout mechanism mipi_dsi_host_ll_set_timeout_count(hal->host, 0, 0, 0, 0, 0, 0, 0); // DSI host will wait indefinitely for a read response from the DSI device diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index 7430d646b8..74c95b4a71 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -169,7 +169,7 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ esp_async_fbcpy_handle_t fbcpy_ctx = NULL; ESP_RETURN_ON_FALSE(bus && panel_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE(panel_config->virtual_channel < 4, ESP_ERR_INVALID_ARG, TAG, "invalid virtual channel %d", panel_config->virtual_channel); - ESP_RETURN_ON_FALSE(panel_config->dpi_clock_freq_mhz, ESP_ERR_INVALID_ARG, TAG, "invalid DPI clock frequency %"PRIu32, panel_config->dpi_clock_freq_mhz); + ESP_RETURN_ON_FALSE(panel_config->dpi_clock_freq_mhz > 0, ESP_ERR_INVALID_ARG, TAG, "invalid DPI clock frequency %.2f", panel_config->dpi_clock_freq_mhz); #if !SOC_DMA2D_SUPPORTED ESP_RETURN_ON_FALSE(!panel_config->flags.use_dma2d, ESP_ERR_NOT_SUPPORTED, TAG, "DMA2D is not supported"); #endif // !SOC_DMA2D_SUPPORTED @@ -265,7 +265,8 @@ esp_err_t esp_lcd_new_panel_dpi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_dpi_ ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(dpi_clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &dpi_clk_src_freq_hz), err, TAG, "get clock source frequency failed"); // divide the source clock to get the final DPI clock - uint32_t dpi_div = mipi_dsi_hal_host_dpi_calculate_divider(hal, dpi_clk_src_freq_hz / 1000 / 1000, panel_config->dpi_clock_freq_mhz); + float dpi_clk_src_freq_mhz = (float)dpi_clk_src_freq_hz / 1000.0f / 1000.0f; + uint32_t dpi_div = mipi_dsi_hal_host_dpi_calculate_divider(hal, dpi_clk_src_freq_mhz, panel_config->dpi_clock_freq_mhz); ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src((soc_module_clk_t)dpi_clk_src, true), err, TAG, "clock source enable failed"); // set the clock source, set the divider, and enable the dpi clock PERIPH_RCC_ATOMIC() { diff --git a/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h b/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h index 99917c7742..d0c1594f20 100644 --- a/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h +++ b/components/esp_lcd/dsi/include/esp_lcd_mipi_dsi.h @@ -23,7 +23,7 @@ typedef struct { int bus_id; /*!< Select which DSI controller, index from 0 */ uint8_t num_data_lanes; /*!< Number of data lanes, if set to 0, the driver will fallback to use maximum number of lanes */ mipi_dsi_phy_pllref_clock_source_t phy_clk_src; /*!< The clock source for the PHY PLL */ - uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ + float lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ } esp_lcd_dsi_bus_config_t; /** @@ -82,7 +82,7 @@ esp_err_t esp_lcd_new_panel_io_dbi(esp_lcd_dsi_bus_handle_t bus, const esp_lcd_d typedef struct { uint8_t virtual_channel; /*!< Virtual channel ID, index from 0 */ mipi_dsi_dpi_clock_source_t dpi_clk_src; /*!< MIPI DSI DPI clock source */ - uint32_t dpi_clock_freq_mhz; /*!< DPI clock frequency in MHz */ + float dpi_clock_freq_mhz; /*!< Pixel clock frequency in MHz */ lcd_color_rgb_pixel_format_t pixel_format; /*!< Pixel format that used by the MIPI LCD device */ lcd_color_format_t in_color_format; /*!< Format of the input data (color space and pixel format), which is the format stored in the frame buffer */ diff --git a/components/hal/include/hal/mipi_dsi_hal.h b/components/hal/include/hal/mipi_dsi_hal.h index d7f3737f52..3c1692383b 100644 --- a/components/hal/include/hal/mipi_dsi_hal.h +++ b/components/hal/include/hal/mipi_dsi_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -30,8 +30,9 @@ typedef struct dsi_brg_dev_t *mipi_dsi_bridge_soc_handle_t; typedef struct { mipi_dsi_host_soc_handle_t host; /*!< Pointer to the host controller registers */ mipi_dsi_bridge_soc_handle_t bridge; /*!< Pointer to the bridge controller registers */ - uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ - uint32_t dpi_clock_freq_mhz; /*!< DPI clock frequency in MHz */ + float lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ + float expect_dpi_clock_freq_mhz; /*!< Expected DPI clock frequency in MHz */ + float real_dpi_clock_freq_mhz; /*!< Real DPI clock frequency in MHz */ } mipi_dsi_hal_context_t; /** @@ -39,7 +40,7 @@ typedef struct { */ typedef struct { int bus_id; /*!< MIPI DSI bus ID, index from 0 */ - uint32_t lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ + float lane_bit_rate_mbps; /*!< Lane bit rate in Mbps */ uint8_t num_data_lanes; /*!< Number of data lanes */ } mipi_dsi_hal_config_t; @@ -67,7 +68,7 @@ void mipi_dsi_hal_deinit(mipi_dsi_hal_context_t *hal); * @param phy_clk_src_freq_hz PHY clock source frequency in Hz * @param lane_bit_rate_mbps Lane bit rate in Mbps */ -void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, uint32_t lane_bit_rate_mbps); +void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, float lane_bit_rate_mbps); /** * @brief Write a value to a PHY register via internal bus (so-called test interface) @@ -175,7 +176,7 @@ void mipi_dsi_hal_host_dpi_set_vertical_timing(mipi_dsi_hal_context_t *hal, uint * @param expect_dpi_clk_mhz Expected DPI clock frequency in MHz * @return Divider value */ -uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, uint32_t clk_src_mhz, uint32_t expect_dpi_clk_mhz); +uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, float clk_src_mhz, float expect_dpi_clk_mhz); #ifdef __cplusplus diff --git a/components/hal/mipi_dsi_hal.c b/components/hal/mipi_dsi_hal.c index 8e57fab191..5bd2f6964d 100644 --- a/components/hal/mipi_dsi_hal.c +++ b/components/hal/mipi_dsi_hal.c @@ -1,11 +1,13 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include +#include #include "hal/mipi_dsi_hal.h" #include "hal/mipi_dsi_ll.h" #include "hal/assert.h" @@ -38,28 +40,28 @@ void mipi_dsi_hal_deinit(mipi_dsi_hal_context_t *hal) hal->bridge = NULL; } -void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, uint32_t lane_bit_rate_mbps) +void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_clk_src_freq_hz, float lane_bit_rate_mbps) { // Formula: f_vco = M/N * f_ref // where the M is Feedback Multiplication Ratio, N is Input Frequency Division Ratio - uint32_t ref_freq_mhz = phy_clk_src_freq_hz / 1000 / 1000; - uint32_t vco_freq_mhz = lane_bit_rate_mbps; + float ref_freq_mhz = (float)phy_clk_src_freq_hz / 1000.0f / 1000.0f; + float vco_freq_mhz = lane_bit_rate_mbps; uint8_t pll_N = 1; uint16_t pll_M = 0; // 5MHz <= f_ref/N <= 40MHz - uint8_t min_N = MAX(1, ref_freq_mhz / 40); - uint8_t max_N = ref_freq_mhz / 5; - uint16_t min_delta = UINT16_MAX; + uint8_t min_N = MAX(1, (uint8_t)(ref_freq_mhz / 40.0f)); + uint8_t max_N = (uint8_t)(ref_freq_mhz / 5.0f); + float min_delta = INFINITY; for (uint8_t n = min_N; n <= max_N; n++) { - uint16_t m = vco_freq_mhz * n / ref_freq_mhz; + uint16_t m = (uint16_t)(vco_freq_mhz * n / ref_freq_mhz); // M must be even number if ((m & 0x01) == 0) { - uint16_t delta = vco_freq_mhz - ref_freq_mhz * m / n; + float delta = fabsf(vco_freq_mhz - ref_freq_mhz * m / n); if (delta < min_delta) { min_delta = delta; pll_M = m; pll_N = n; - if (min_delta == 0) { + if (min_delta < 0.01f) { break; } } @@ -84,8 +86,8 @@ void mipi_dsi_hal_configure_phy_pll(mipi_dsi_hal_context_t *hal, uint32_t phy_cl mipi_dsi_hal_phy_write_register(hal, 0x18, ((pll_M - 1) & 0x1F)); mipi_dsi_hal_phy_write_register(hal, 0x18, 0x80 | (((pll_M - 1) >> 5) & 0x0F)); // update the real lane bit rate - hal->lane_bit_rate_mbps = ref_freq_mhz * pll_M / pll_N; - HAL_LOGD("dsi_hal", "phy pll: ref=%" PRIu32 "Hz, lane_bit_rate=%" PRIu32 "Mbps, M=%" PRId16 ", N=%" PRId8 ", hsfreqrange=%" PRId8, + hal->lane_bit_rate_mbps = ref_freq_mhz * (float)pll_M / (float)pll_N; + HAL_LOGD("dsi_hal", "phy pll: ref=%" PRIu32 "Hz, lane_bit_rate=%.2f Mbps, M=%" PRId16 ", N=%" PRId8 ", hsfreqrange=%" PRId8, phy_clk_src_freq_hz, hal->lane_bit_rate_mbps, pll_M, pll_N, hs_freq_sel); } @@ -116,7 +118,7 @@ void mipi_dsi_hal_host_gen_write_dcs_command(mipi_dsi_hal_context_t *hal, uint8_ uint32_t payload_size = command_bytes + param_size; // merge the command and some bytes of parameters into one 32-bit word - uint32_t temp = command & ((1 << (8 * command_bytes)) - 1); + uint32_t temp = command & ((1U << (8 * command_bytes)) - 1); uint16_t merged_size = MIN(4 - command_bytes, param_size); for (int i = 0; i < merged_size; i++) { temp |= payload[i] << (8 * (i + command_bytes)); @@ -131,15 +133,17 @@ void mipi_dsi_hal_host_gen_write_dcs_command(mipi_dsi_hal_context_t *hal, uint8_ payload += merged_size; uint32_t remain_size = param_size - merged_size; while (remain_size >= 4) { - temp = *(uint32_t *)payload; + // use memcpy to avoid unaligned memory access + memcpy(&temp, payload, sizeof(uint32_t)); while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); payload += 4; remain_size -= 4; } if (remain_size) { - temp = *(uint32_t *)payload; - temp &= (1 << (8 * remain_size)) - 1; + temp = 0; + // use memcpy to avoid unaligned memory access and buffer over-read + memcpy(&temp, payload, remain_size); while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); } @@ -176,15 +180,17 @@ void mipi_dsi_hal_host_gen_write_long_packet(mipi_dsi_hal_context_t *hal, uint8_ uint32_t remain_size = buffer_size; uint32_t temp = 0; while (remain_size >= 4) { - temp = *(uint32_t *)payload; + // use memcpy to avoid unaligned memory access + memcpy(&temp, payload, sizeof(uint32_t)); while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); payload += 4; remain_size -= 4; } if (remain_size) { - temp = *(uint32_t *)payload; - temp &= (1 << (8 * remain_size)) - 1; + temp = 0; + // use memcpy to avoid unaligned memory access and buffer over-read + memcpy(&temp, payload, remain_size); while (mipi_dsi_host_ll_gen_is_write_fifo_full(hal->host)); mipi_dsi_host_ll_gen_write_payload_fifo(hal->host, temp); } @@ -225,19 +231,30 @@ void mipi_dsi_hal_host_gen_read_short_packet(mipi_dsi_hal_context_t *hal, uint8_ void mipi_dsi_hal_host_gen_read_dcs_command(mipi_dsi_hal_context_t *hal, uint8_t vc, uint32_t command, uint32_t command_bytes, void *ret_param, uint16_t param_buf_size) { - uint16_t header_data = command & ((1 << (8 * command_bytes)) - 1); + uint16_t header_data = command & ((1U << (8 * command_bytes)) - 1); mipi_dsi_hal_host_gen_read_short_packet(hal, vc, MIPI_DSI_DT_DCS_READ_0, header_data, ret_param, param_buf_size); } void mipi_dsi_hal_host_dpi_set_horizontal_timing(mipi_dsi_hal_context_t *hal, uint32_t hsw, uint32_t hbp, uint32_t active_width, uint32_t hfp) { - float dpi2lane_clk_ratio = (float)hal->lane_bit_rate_mbps / hal->dpi_clock_freq_mhz / 8; - mipi_dsi_host_ll_dpi_set_horizontal_timing(hal->host, - hsw * dpi2lane_clk_ratio, - hbp * dpi2lane_clk_ratio, - active_width * dpi2lane_clk_ratio, - hfp * dpi2lane_clk_ratio); - mipi_dsi_brg_ll_set_horizontal_timing(hal->bridge, hsw, hbp, active_width, hfp); + // set the horizontal timing based on user's expectation + uint32_t htotal = hsw + hbp + active_width + hfp; + float dpi2lane_clk_ratio = hal->lane_bit_rate_mbps / hal->expect_dpi_clock_freq_mhz / 8.0f; + uint32_t host_hsw = (uint32_t)roundf(hsw * dpi2lane_clk_ratio); + uint32_t host_hbp = (uint32_t)roundf(hbp * dpi2lane_clk_ratio); + uint32_t host_act = (uint32_t)roundf(active_width * dpi2lane_clk_ratio); + uint32_t host_hfp = (uint32_t)roundf(hfp * dpi2lane_clk_ratio); + uint32_t host_htotal = (uint32_t)roundf(htotal * dpi2lane_clk_ratio); + int compensation = (int)host_htotal - (int)(host_hsw + host_hbp + host_act + host_hfp); + mipi_dsi_host_ll_dpi_set_horizontal_timing(hal->host, host_hsw, host_hbp, host_act + compensation, host_hfp); + HAL_LOGD("dsi_hal", "host video timing: hsw=%" PRIu32 ", hbp=%" PRIu32 ", act=%" PRIu32 ", hfp=%" PRIu32, + host_hsw, host_hbp, host_act + compensation, host_hfp); + + // compensate the video timing to achieve the same refresh rate as expected + compensation = (int)roundf(hal->real_dpi_clock_freq_mhz / hal->expect_dpi_clock_freq_mhz * htotal) - (int)htotal; + mipi_dsi_brg_ll_set_horizontal_timing(hal->bridge, hsw, hbp, active_width, hfp + compensation); + HAL_LOGD("dsi_hal", "brg video timing: hsw=%" PRIu32 ", hbp=%" PRIu32 ", act=%" PRIu32 ", hfp=%" PRIu32, + hsw, hbp, active_width, hfp + compensation); } void mipi_dsi_hal_host_dpi_set_vertical_timing(mipi_dsi_hal_context_t *hal, uint32_t vsw, uint32_t vbp, uint32_t active_height, uint32_t vfp) @@ -246,9 +263,12 @@ void mipi_dsi_hal_host_dpi_set_vertical_timing(mipi_dsi_hal_context_t *hal, uint mipi_dsi_brg_ll_set_vertical_timing(hal->bridge, vsw, vbp, active_height, vfp); } -uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, uint32_t clk_src_mhz, uint32_t expect_dpi_clk_mhz) +uint32_t mipi_dsi_hal_host_dpi_calculate_divider(mipi_dsi_hal_context_t *hal, float clk_src_mhz, float expect_dpi_clk_mhz) { - uint32_t div = clk_src_mhz / expect_dpi_clk_mhz; - hal->dpi_clock_freq_mhz = clk_src_mhz / div; + uint32_t div = (uint32_t)roundf(clk_src_mhz / expect_dpi_clk_mhz); + hal->expect_dpi_clock_freq_mhz = expect_dpi_clk_mhz; + hal->real_dpi_clock_freq_mhz = clk_src_mhz / (float)div; + HAL_LOGD("dsi_hal", "dpi clk: src=%.2f MHz, expect=%.2f MHz, div=%" PRIu32 ", real=%.2f MHz", + clk_src_mhz, expect_dpi_clk_mhz, div, hal->real_dpi_clock_freq_mhz); return div; } From 9dbbdc9359e3e5ee634d63f0a9b96fe9c8270f92 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Thu, 18 Dec 2025 19:54:55 +0800 Subject: [PATCH 149/156] feat(802.15.4): remove tx pending feature --- .../ieee802154/driver/esp_ieee802154_dev.c | 44 +++++-------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index a6d7bdec93..b33b32a89e 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -77,14 +77,6 @@ static esp_err_t ieee802154_sleep_deinit(void); #define NEEDS_NEXT_OPT(a) do {s_needs_next_operation = a;} while(0) static esp_err_t ieee802154_transmit_internal(const uint8_t *frame, bool cca); -#if !CONFIG_IEEE802154_TEST -typedef struct { - const uint8_t *frame; - bool cca; -} pending_tx_t; -static pending_tx_t s_pending_tx = { 0 }; -#endif - static void ieee802154_receive_done(uint8_t *data, esp_ieee802154_frame_info_t *frame_info) { // If the RX done packet is written in the stub buffer, drop it silently. @@ -382,26 +374,13 @@ static void enable_rx(void) static IRAM_ATTR void next_operation(void) { + if (ieee802154_pib_get_rx_when_idle()) { + enable_rx(); + } else { + ieee802154_set_state(IEEE802154_STATE_IDLE); #if !CONFIG_IEEE802154_TEST - if (s_pending_tx.frame) { - // Here the driver needs to recover the setting of rx aborts, see function `ieee802154_transmit`. - ieee802154_ll_disable_rx_abort_events(IEEE802154_RX_ABORT_ALL); - ieee802154_ll_enable_rx_abort_events(BIT(IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT - 1) | BIT(IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK - 1)); - // Clear the RX abort event again for avoiding the risk if there are still some rx abort events created after last isr process. - ieee802154_ll_clear_events(IEEE802154_EVENT_RX_ABORT); - ieee802154_transmit_internal(s_pending_tx.frame, s_pending_tx.cca); - s_pending_tx.frame = NULL; - } else + ieee802154_sleep(); #endif - { - if (ieee802154_pib_get_rx_when_idle()) { - enable_rx(); - } else { - ieee802154_set_state(IEEE802154_STATE_IDLE); -#if !CONFIG_IEEE802154_TEST - ieee802154_sleep(); -#endif - } } } @@ -901,15 +880,12 @@ esp_err_t ieee802154_transmit(const uint8_t *frame, bool cca) ieee802154_enter_critical(); if ((s_ieee802154_state == IEEE802154_STATE_RX && ieee802154_ll_is_current_rx_frame()) || s_ieee802154_state == IEEE802154_STATE_TX_ACK || s_ieee802154_state == IEEE802154_STATE_TX_ENH_ACK) { - // If the current radio is processing an RX frame or sending an ACK, do not shut down the ongoing process. - // Instead, defer the transmission of the pending TX frame. - // Once the current process is completed, the pending transmit frame will be initiated. - s_pending_tx.frame = frame; - s_pending_tx.cca = cca; + if (cca) { + ieee802154_inner_transmit_failed(frame, ESP_IEEE802154_TX_ERR_CCA_BUSY); + } else { + ieee802154_inner_transmit_failed(frame, ESP_IEEE802154_TX_ERR_ABORT); + } IEEE802154_TX_DEFERRED_NUMS_UPDATE(); - // Here we enable all rx interrupts due to the driver needs to know when the current RX has finished. - // Will recover the setting of rx abort in function `next_operation`. - ieee802154_ll_enable_rx_abort_events(IEEE802154_RX_ABORT_ALL); ieee802154_exit_critical(); return ESP_OK; } From a2be6b90df9937b0c898710377bfd6265c0d8ebb Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 16 Dec 2025 20:08:07 +0800 Subject: [PATCH 150/156] fix(esp_driver_cam): fix MIPI-CSI RX data broken --- components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c | 7 +++++++ components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c | 3 +++ .../esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c index 1937ecbee9..c05ca87dec 100644 --- a/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c +++ b/components/esp_driver_cam/csi/src/esp_cam_ctlr_csi.c @@ -352,6 +352,10 @@ IRAM_ATTR static bool csi_dma_trans_done_callback(dw_gdma_channel_handle_t chan, } } + esp_err_t ret = esp_cache_msync((void *)(new_trans.buffer), new_trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + assert(ret == ESP_OK); + (void)ret; + ESP_EARLY_LOGD(TAG, "new_trans.buffer: %p, new_trans.buflen: %d", new_trans.buffer, new_trans.buflen); dw_gdma_channel_config_transfer(chan, &csi_dma_transfer_config); dw_gdma_channel_enable_ctrl(chan, true); @@ -448,6 +452,9 @@ esp_err_t s_ctlr_csi_start(esp_cam_ctlr_handle_t handle) } } + ESP_RETURN_ON_ERROR(esp_cache_msync((void *)(trans.buffer), trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C), + TAG, "failed to sync(M2C) trans buffer"); + ESP_LOGD(TAG, "trans.buffer: %p, trans.buflen: %d", trans.buffer, trans.buflen); ctlr->trans = trans; diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c index 8a9df05c56..b92404fae6 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_cam.c @@ -177,6 +177,9 @@ static IRAM_ATTR esp_err_t esp_cam_ctlr_dvp_start_trans(esp_cam_ctlr_dvp_cam_t * assert(false && "no new buffer, and no driver internal buffer"); } + ESP_RETURN_ON_ERROR(esp_cache_msync((void *)(trans.buffer), trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C), + TAG, "failed to sync(M2C) trans buffer"); + ESP_RETURN_ON_ERROR_ISR(esp_cam_ctlr_dvp_dma_reset(&ctlr->dma), TAG, "failed to reset DMA"); ESP_RETURN_ON_ERROR_ISR(esp_cam_ctlr_dvp_dma_start(&ctlr->dma, trans.buffer, ctlr->fb_size_in_bytes), TAG, "failed to start DMA"); diff --git a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c index ef607849d3..085a569577 100644 --- a/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c +++ b/components/esp_driver_cam/isp_dvp/src/esp_cam_ctlr_isp_dvp.c @@ -346,6 +346,9 @@ static esp_err_t s_isp_dvp_start(esp_cam_ctlr_handle_t handle) } } + ESP_RETURN_ON_ERROR(esp_cache_msync((void *)(trans.buffer), trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C), + TAG, "failed to sync(M2C) trans buffer"); + ESP_LOGD(TAG, "trans.buffer: %p, trans.buflen: %d", trans.buffer, trans.buflen); dvp_ctlr->trans = trans; @@ -469,6 +472,10 @@ IRAM_ATTR static bool s_dvp_dma_trans_done_callback(dw_gdma_channel_handle_t cha } } + esp_err_t ret = esp_cache_msync((void *)(new_trans.buffer), new_trans.buflen, ESP_CACHE_MSYNC_FLAG_DIR_M2C); + assert(ret == ESP_OK); + (void)ret; + ESP_EARLY_LOGD(TAG, "new_trans.buffer: %p, new_trans.buflen: %d", new_trans.buffer, new_trans.buflen); dw_gdma_channel_config_transfer(chan, &dvp_dma_transfer_config); dw_gdma_channel_enable_ctrl(chan, true); From 2ff54ff5c53375bdd4566c9aeba3dc17de9f8ffa Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Tue, 16 Dec 2025 12:10:19 +0800 Subject: [PATCH 151/156] fix(soc): update breakpoint nums on c5 and h4 --- components/soc/esp32c5/include/soc/Kconfig.soc_caps.in | 4 ++-- components/soc/esp32c5/include/soc/soc_caps.h | 4 ++-- components/soc/esp32h4/include/soc/Kconfig.soc_caps.in | 4 ++-- components/soc/esp32h4/include/soc/soc_caps.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index d14aa56e4a..ccf75e989d 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -453,11 +453,11 @@ config SOC_BRANCH_PREDICTOR_SUPPORTED config SOC_CPU_BREAKPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE hex diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 1c8d837396..bb696ebb35 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -165,8 +165,8 @@ #define SOC_INT_HW_NESTED_SUPPORTED 1 // Support for hardware interrupts nesting #define SOC_BRANCH_PREDICTOR_SUPPORTED 1 -#define SOC_CPU_BREAKPOINTS_NUM 4 -#define SOC_CPU_WATCHPOINTS_NUM 4 +#define SOC_CPU_BREAKPOINTS_NUM 3 +#define SOC_CPU_WATCHPOINTS_NUM 3 #define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x100 // bytes #define SOC_CPU_HAS_PMA 1 diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 8e15f46312..5155d3e4ea 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -125,11 +125,11 @@ config SOC_CPU_COPROC_NUM config SOC_CPU_BREAKPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINTS_NUM int - default 4 + default 3 config SOC_CPU_WATCHPOINT_MAX_REGION_SIZE hex diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 868180cf23..7539f159ec 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -156,8 +156,8 @@ #define SOC_CPU_HAS_FPU_EXT_ILL_BUG 0 // EXT_ILL CSR doesn't support FLW/FSW #define SOC_CPU_COPROC_NUM 2 -#define SOC_CPU_BREAKPOINTS_NUM 4 -#define SOC_CPU_WATCHPOINTS_NUM 4 +#define SOC_CPU_BREAKPOINTS_NUM 3 +#define SOC_CPU_WATCHPOINTS_NUM 3 #define SOC_CPU_WATCHPOINT_MAX_REGION_SIZE 0x80000000 // bytes #define SOC_CPU_HAS_PMA 1 From dbac2285eccbdd655e4c52109cc9a9a65ed30ab9 Mon Sep 17 00:00:00 2001 From: Adorjan White Date: Fri, 28 Nov 2025 17:48:28 +0000 Subject: [PATCH 152/156] fix(usb_serial_jtag): tx_ring_buf not checked for successful allocation, Closes https://github.com/espressif/esp-idf/pull/17945 --- components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c index 631829de9e..e6abe60e8b 100644 --- a/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c +++ b/components/esp_driver_usb_serial_jtag/src/usb_serial_jtag.c @@ -183,7 +183,7 @@ esp_err_t usb_serial_jtag_driver_install(usb_serial_jtag_driver_config_t *usb_se } p_usb_serial_jtag_obj->tx_ring_buf = xRingbufferCreate(usb_serial_jtag_config->tx_buffer_size, RINGBUF_TYPE_BYTEBUF); - if (p_usb_serial_jtag_obj->rx_ring_buf == NULL) { + if (p_usb_serial_jtag_obj->tx_ring_buf == NULL) { ESP_LOGE(USB_SERIAL_JTAG_TAG, "ringbuffer create error"); err = ESP_ERR_NO_MEM; goto _exit; From be52835d21d5ae3e0ba081aae2f9df0024e87657 Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Fri, 19 Dec 2025 11:42:17 +0800 Subject: [PATCH 153/156] fix(system): removed the exe flag from psram memory for esp32 extern_ram_seg segment was marked as RWX in the linker script even though we cannot run code from PSRAM on ESP32. This is a link-time check, and actual CPU RWX permissions are controlled seperately so this has no practical implications, but it could mistakenly be remarked upon during security scans or checks by customers. --- components/esp_system/ld/esp32/memory.ld.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp_system/ld/esp32/memory.ld.in b/components/esp_system/ld/esp32/memory.ld.in index e0b2517ff8..df13722b0c 100644 --- a/components/esp_system/ld/esp32/memory.ld.in +++ b/components/esp_system/ld/esp32/memory.ld.in @@ -122,7 +122,7 @@ MEMORY rtc_slow_reserved_seg(RW) : org = 0x50000000 + 0x2000 - RESERVE_RTC_MEM, len = RESERVE_RTC_MEM /* external memory */ - extern_ram_seg(RWX) : org = 0x3F800000, + extern_ram_seg(RW) : org = 0x3F800000, len = 0x400000 } From dae2b988f4e66742b3ea41b176efa60f4ed4aed0 Mon Sep 17 00:00:00 2001 From: Chen Yudong Date: Wed, 12 Nov 2025 10:02:59 +0800 Subject: [PATCH 154/156] ci: rename wifi_two_dut to two_duts --- .../pytest_temperature_sensor.py | 4 +- .../bin_size_apsta/pytest_bin_size_apsta.py | 2 +- .../wifi_connect/pytest_wifi_connect.py | 8 +-- .../test_apps/main/test_offchannel.c | 2 +- .../test_apps/main/test_wifi_external_bss.c | 2 +- .../test_apps/pytest_wpa_supplicant_ut.py | 16 ++--- examples/bluetooth/.build-test-rules.yml | 2 + .../pytest_ble_throughput_test.py | 24 +++---- .../bluedroid/ble/pytest_ble_test.py | 62 +++++++++---------- .../bluedroid/ble_50/pytest_ble50_test.py | 36 ++++++----- .../classic_bt/pytest_classic_bt_test.py | 17 +++-- .../bluetooth/nimble/pytest_nimble_test.py | 24 +++---- .../pytest_wifi_getting_started.py | 9 +-- .../station/pytest_wifi_station.py | 3 +- tools/ci/idf_pytest/constants.py | 2 +- .../phy/phy_tsens/pytest_phy_tsens.py | 8 +-- 16 files changed, 115 insertions(+), 106 deletions(-) diff --git a/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py b/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py index 987e0db89f..236a1076ca 100644 --- a/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py +++ b/components/esp_driver_tsens/test_apps/temperature_sensor/pytest_temperature_sensor.py @@ -49,10 +49,10 @@ def test_temperature_sensor_cbs_esp32c5(dut: Dut) -> None: dut.run_all_single_board_cases() -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize('count', [2], indirect=True) @idf_parametrize('target', ['esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32c61'], indirect=['target']) def test_temperature_phy_cases(case_tester: CaseTester) -> None: # type: ignore for case in case_tester.test_menu: - if case.attributes.get('test_env', 'wifi_two_dut') == 'wifi_two_dut': + if case.attributes.get('test_env', 'two_duts') == 'two_duts': case_tester.run_all_multi_dev_cases(case=case, reset=True) diff --git a/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py b/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py index a014517091..fc4dbb7542 100644 --- a/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py +++ b/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py @@ -41,7 +41,7 @@ def _get_diff_th( return diff_threshold.get(target) or diff_threshold['default'] -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, config, skip_autoflash', [ diff --git a/components/esp_wifi/test_apps/wifi_connect/pytest_wifi_connect.py b/components/esp_wifi/test_apps/wifi_connect/pytest_wifi_connect.py index e4b87e35d3..60d6d8c358 100644 --- a/components/esp_wifi/test_apps/wifi_connect/pytest_wifi_connect.py +++ b/components/esp_wifi/test_apps/wifi_connect/pytest_wifi_connect.py @@ -5,7 +5,7 @@ from pytest_embedded_idf.unity_tester import CaseTester from pytest_embedded_idf.utils import idf_parametrize -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize('count', [2], indirect=True) @idf_parametrize( 'target', ['esp32', 'esp32c3', 'esp32s2', 'esp32s3', 'esp32c5', 'esp32c6', 'esp32c61'], indirect=['target'] @@ -14,7 +14,7 @@ def test_wifi_connect_cases(case_tester: CaseTester) -> None: # type: ignore case_tester.run_all_cases() -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, config, baud', @@ -29,7 +29,7 @@ def test_wifi_connect_cases_esp32c2_xtal26m(case_tester: CaseTester) -> None: @pytest.mark.esp32c2eco4 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, config, baud', @@ -43,7 +43,7 @@ def test_wifi_connect_cases_esp32c2eco4_xtal26m(case_tester: CaseTester) -> None case_tester.run_all_cases() -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'count, config', diff --git a/components/wpa_supplicant/test_apps/main/test_offchannel.c b/components/wpa_supplicant/test_apps/main/test_offchannel.c index 0f73079e3b..6ccb9b843a 100644 --- a/components/wpa_supplicant/test_apps/main/test_offchannel.c +++ b/components/wpa_supplicant/test_apps/main/test_offchannel.c @@ -265,4 +265,4 @@ static void test_wifi_roc(void) } } -TEST_CASE_MULTIPLE_DEVICES("test ROC and Offchannel Action Frame Tx", "[Offchan][test_env=wifi_two_dut][timeout=90]", test_wifi_roc, test_wifi_offchan_tx); +TEST_CASE_MULTIPLE_DEVICES("test ROC and Offchannel Action Frame Tx", "[Offchan][test_env=two_duts][timeout=90]", test_wifi_roc, test_wifi_offchan_tx); diff --git a/components/wpa_supplicant/test_apps/main/test_wifi_external_bss.c b/components/wpa_supplicant/test_apps/main/test_wifi_external_bss.c index df75beba46..2bc994c8fc 100644 --- a/components/wpa_supplicant/test_apps/main/test_wifi_external_bss.c +++ b/components/wpa_supplicant/test_apps/main/test_wifi_external_bss.c @@ -198,6 +198,6 @@ static void test_softap_connection(void) } /* Test that wifi starts, scans and stops normally when .bss segment is allowed to move to external memory */ -TEST_CASE_MULTIPLE_DEVICES("test wifi connection for sta and softap when ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY is enabled", "[esp_wifi][test_env=wifi_two_dut]", test_station_connection, test_softap_connection); +TEST_CASE_MULTIPLE_DEVICES("test wifi connection for sta and softap when ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY is enabled", "[esp_wifi][test_env=two_duts]", test_station_connection, test_softap_connection); #endif // CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY diff --git a/components/wpa_supplicant/test_apps/pytest_wpa_supplicant_ut.py b/components/wpa_supplicant/test_apps/pytest_wpa_supplicant_ut.py index c8633f1fda..e7ff601bfa 100644 --- a/components/wpa_supplicant/test_apps/pytest_wpa_supplicant_ut.py +++ b/components/wpa_supplicant/test_apps/pytest_wpa_supplicant_ut.py @@ -16,7 +16,7 @@ def test_wpa_supplicant_ut(dut: Dut) -> None: dut.run_all_single_board_cases() -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count', [ @@ -31,12 +31,12 @@ def test_wpa_supplicant_ut(dut: Dut) -> None: ) def test_wpa_supplicant_ut_offchan(case_tester: CaseTester) -> None: for case in case_tester.test_menu: - if case.attributes.get('test_env') == 'wifi_two_dut': + if case.attributes.get('test_env') == 'two_duts': case_tester.run_multi_dev_case(case=case, reset=True) # test when external bss segment is enabled -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, config', [ @@ -50,11 +50,11 @@ def test_wpa_supplicant_ut_offchan(case_tester: CaseTester) -> None: @idf_parametrize('target', ['esp32s3'], indirect=['target']) def test_wpa_supplicant_ut_psram(case_tester: CaseTester) -> None: for case in case_tester.test_menu: - if case.attributes.get('test_env') == 'wifi_two_dut': + if case.attributes.get('test_env') == 'two_duts': case_tester.run_multi_dev_case(case=case, reset=True) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c2eco4 @pytest.mark.xtal_26mhz @pytest.mark.parametrize( @@ -71,11 +71,11 @@ def test_wpa_supplicant_ut_psram(case_tester: CaseTester) -> None: @idf_parametrize('target', ['esp32c2'], indirect=['target']) def test_wpa_supplicant_esp32c2eco4_xtal26mhz(case_tester: CaseTester) -> None: for case in case_tester.test_menu: - if case.attributes.get('test_env') == 'wifi_two_dut': + if case.attributes.get('test_env') == 'two_duts': case_tester.run_multi_dev_case(case=case, reset=True) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'count, config', @@ -90,5 +90,5 @@ def test_wpa_supplicant_esp32c2eco4_xtal26mhz(case_tester: CaseTester) -> None: @idf_parametrize('target', ['esp32c3'], indirect=['target']) def test_wpa_supplicant_esp32c3eco7(case_tester: CaseTester) -> None: for case in case_tester.test_menu: - if case.attributes.get('test_env') == 'wifi_two_dut': + if case.attributes.get('test_env') == 'two_duts': case_tester.run_multi_dev_case(case=case, reset=True) diff --git a/examples/bluetooth/.build-test-rules.yml b/examples/bluetooth/.build-test-rules.yml index f79848069e..69caebef10 100644 --- a/examples/bluetooth/.build-test-rules.yml +++ b/examples/bluetooth/.build-test-rules.yml @@ -141,6 +141,8 @@ examples/bluetooth/esp_hid_host: - if: SOC_BT_SUPPORTED != 1 depends_components+: - esp_hid + depends_filepatterns: + - examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py examples/bluetooth/hci/ble_adv_scan_combined: <<: *bt_default_depends diff --git a/examples/bluetooth/bluedroid/ble/ble_throughput/pytest_ble_throughput_test.py b/examples/bluetooth/bluedroid/ble/ble_throughput/pytest_ble_throughput_test.py index a19cb8ed78..d2cccabc40 100644 --- a/examples/bluetooth/bluedroid/ble/ble_throughput/pytest_ble_throughput_test.py +++ b/examples/bluetooth/bluedroid/ble/ble_throughput/pytest_ble_throughput_test.py @@ -1,22 +1,24 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path import time +from pathlib import Path from typing import Tuple import pytest from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize + +CUR_DIR = Path(__file__).parent.resolve() + + # Case 1: gatt write throughput test(EXAMPLE_CI_ID = 2) - - -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "throughput_server")}|{os.path.join(os.path.dirname(__file__), "throughput_client")}', + f'{str(CUR_DIR / "throughput_server")}|{str(CUR_DIR / "throughput_client")}', 'write', 'y', ), @@ -54,7 +56,7 @@ def test_gatt_write_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> Non # Case 2: gatt write throughput test for ESP32C2 26mhz xtal(EXAMPLE_CI_ID = 2) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -63,7 +65,7 @@ def test_gatt_write_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> Non 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "throughput_server")}|{os.path.join(os.path.dirname(__file__), "throughput_client")}', + f'{str(CUR_DIR / "throughput_server")}|{str(CUR_DIR / "throughput_client")}', 'esp32c2_xtal26m_write', 'y', ), @@ -98,13 +100,13 @@ def test_c2_26mhz_xtal_write_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut # Case 3: gatt notify throughput test(EXAMPLE_CI_ID = 1) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "throughput_server")}|{os.path.join(os.path.dirname(__file__), "throughput_client")}', + f'{str(CUR_DIR / "throughput_server")}|{str(CUR_DIR / "throughput_client")}', 'notify', 'y', ), @@ -144,7 +146,7 @@ def test_gatt_notify_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> No # Case 4: gatt notify throughput test for ESP32C2 26mhz xtal(EXAMPLE_CI_ID = 1) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -153,7 +155,7 @@ def test_gatt_notify_throughput(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> No 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "throughput_server")}|{os.path.join(os.path.dirname(__file__), "throughput_client")}', + f'{str(CUR_DIR / "throughput_server")}|{str(CUR_DIR / "throughput_client")}', 'esp32c2_xtal26m_notify', 'y', ), diff --git a/examples/bluetooth/bluedroid/ble/pytest_ble_test.py b/examples/bluetooth/bluedroid/ble/pytest_ble_test.py index 7ac6ec61fc..6210ddcd48 100644 --- a/examples/bluetooth/bluedroid/ble/pytest_ble_test.py +++ b/examples/bluetooth/bluedroid/ble/pytest_ble_test.py @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path +from pathlib import Path from typing import Tuple import pexpect @@ -8,17 +8,19 @@ import pytest from pytest_embedded import Dut from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize + +CUR_DIR = Path(__file__).parent.resolve() + + # Case 1: gatt client and gatt server test # EXAMPLE_CI_ID=3 - - -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "gatt_server")}|{os.path.join(os.path.dirname(__file__), "gatt_client")}', + f'{str(CUR_DIR / "gatt_server")}|{str(CUR_DIR / "gatt_client")}', 'name', 'y', ), @@ -61,7 +63,7 @@ def test_gatt_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: gatt client and gatt server test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=3 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -70,7 +72,7 @@ def test_gatt_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "gatt_server")}|{os.path.join(os.path.dirname(__file__), "gatt_client")}', + f'{str(CUR_DIR / "gatt_server")}|{str(CUR_DIR / "gatt_client")}', 'esp32c2_xtal26m', 'y', ), @@ -110,13 +112,13 @@ def test_c2_26mhz_xtal_gatt_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> N # Case 3: gatt security server and gatt security client test # EXAMPLE_CI_ID=5 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "gatt_security_server")}|{os.path.join(os.path.dirname(__file__), "gatt_security_client")}', + f'{str(CUR_DIR / "gatt_security_server")}|{str(CUR_DIR / "gatt_security_client")}', 'name', 'y', ), @@ -126,7 +128,7 @@ def test_c2_26mhz_xtal_gatt_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> N @idf_parametrize( 'target', ['esp32', 'esp32c3', 'esp32c6', 'esp32c5', 'esp32h2', 'esp32s3', 'esp32c61'], indirect=['target'] ) -def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: Tuple) -> None: +def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: tuple) -> None: gatt_security_client = dut[1] gatt_security_server = dut[0] gatt_security_client_addr = ( @@ -143,9 +145,9 @@ def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: T gatt_security_client.expect_exact('Scanning start successfully', timeout=30) gatt_security_client.expect_exact('Device found BE', timeout=30) # can not get rpa_address, so not check server address - gatt_security_client.expect_exact(f'Connected, conn_id 0, remote ', timeout=30) + gatt_security_client.expect_exact('Connected, conn_id 0, remote ', timeout=30) if target == ('esp32', 'esp32'): - gatt_security_server.expect_exact(f'Connected, conn_id 0, remote', timeout=30) + gatt_security_server.expect_exact('Connected, conn_id 0, remote', timeout=30) else: gatt_security_server.expect_exact(f'Connected, conn_id 0, remote {gatt_security_client_addr}', timeout=30) gatt_security_client.expect_exact('Key exchanged, key_type ESP_LE_KEY_PID', timeout=30) @@ -158,12 +160,12 @@ def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: T gatt_security_server.expect_exact('Key exchanged, key_type ESP_LE_KEY_LID', timeout=30) gatt_security_server.expect_exact('Key exchanged, key_type ESP_LE_KEY_PID', timeout=30) if target == ('esp32', 'esp32'): - gatt_security_server.expect_exact(f'Authentication complete, addr_type 1, addr ', timeout=30) + gatt_security_server.expect_exact('Authentication complete, addr_type 1, addr ', timeout=30) else: gatt_security_server.expect_exact( f'Authentication complete, addr_type 0, addr {gatt_security_client_addr}', timeout=30 ) - gatt_security_client.expect_exact(f'Authentication complete, addr_type 1, addr ', timeout=30) + gatt_security_client.expect_exact('Authentication complete, addr_type 1, addr ', timeout=30) gatt_security_server.expect_exact('Pairing successfully', timeout=30) gatt_security_server.expect_exact('Bonded devices number 1', timeout=30) gatt_security_client.expect_exact('Pairing successfully', timeout=30) @@ -178,7 +180,7 @@ def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: T # Case 4: gatt security server and gatt security client test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=5 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -187,7 +189,7 @@ def test_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut], target: T 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "gatt_security_server")}|{os.path.join(os.path.dirname(__file__), "gatt_security_client")}', + f'{str(CUR_DIR / "gatt_security_server")}|{str(CUR_DIR / "gatt_security_client")}', 'esp32c2_xtal26m', 'y', ), @@ -211,7 +213,7 @@ def test_c2_26mhz_xtal_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfD gatt_security_client.expect_exact('Scanning start successfully', timeout=30) gatt_security_client.expect_exact('Device found BE', timeout=30) # can not get rpa_address, so not check server address - gatt_security_client.expect_exact(f'Connected, conn_id 0, remote ', timeout=30) + gatt_security_client.expect_exact('Connected, conn_id 0, remote ', timeout=30) gatt_security_server.expect_exact(f'Connected, conn_id 0, remote {gatt_security_client_addr}', timeout=30) gatt_security_client.expect_exact('Key exchanged, key_type ESP_LE_KEY_PID', timeout=30) gatt_security_client.expect_exact('Key exchanged, key_type ESP_LE_KEY_LENC', timeout=30) @@ -225,7 +227,7 @@ def test_c2_26mhz_xtal_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfD gatt_security_server.expect_exact( f'Authentication complete, addr_type 0, addr {gatt_security_client_addr}', timeout=30 ) - gatt_security_client.expect_exact(f'Authentication complete, addr_type 1, addr ', timeout=30) + gatt_security_client.expect_exact('Authentication complete, addr_type 1, addr ', timeout=30) gatt_security_server.expect_exact('Pairing successfully', timeout=30) gatt_security_server.expect_exact('Bonded devices number 1', timeout=30) gatt_security_client.expect_exact('Pairing successfully', timeout=30) @@ -239,13 +241,13 @@ def test_c2_26mhz_xtal_gatt_security_func(app_path: str, dut: Tuple[IdfDut, IdfD # Case 5: ble ibeacon test -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "ble_ibeacon")}|{os.path.join(os.path.dirname(__file__), "ble_ibeacon")}', + f'{str(CUR_DIR / "ble_ibeacon")}|{str(CUR_DIR / "ble_ibeacon")}', 'sender|receiver', 'y', ), @@ -277,7 +279,7 @@ def test_ble_ibeacon_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 5: ble ibeacon test for ESP32C2 26mhz xtal -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -286,7 +288,7 @@ def test_ble_ibeacon_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "ble_ibeacon")}|{os.path.join(os.path.dirname(__file__), "ble_ibeacon")}', + f'{str(CUR_DIR / "ble_ibeacon")}|{str(CUR_DIR / "ble_ibeacon")}', 'esp32c2_xtal26m_sender|esp32c2_xtal26m_receiver', 'y', ), @@ -316,13 +318,13 @@ def test_c2_26mhz_ble_ibeacon_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> # Case 6: gatt client and gatt server config test # EXAMPLE_CI_ID=4 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "gatt_server")}|{os.path.join(os.path.dirname(__file__), "gatt_client")}', + f'{str(CUR_DIR / "gatt_server")}|{str(CUR_DIR / "gatt_client")}', 'cfg_test', 'y', ), @@ -365,7 +367,7 @@ def test_gatt_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 7: gatt client and gatt server config test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=3 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -374,7 +376,7 @@ def test_gatt_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "gatt_server")}|{os.path.join(os.path.dirname(__file__), "gatt_client")}', + f'{str(CUR_DIR / "gatt_server")}|{str(CUR_DIR / "gatt_client")}', 'esp32c2_cfg_test', 'y', ), @@ -414,9 +416,7 @@ def test_c2_26mhz_xtal_gatt_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut # Case 8: BLE init deinit loop test @pytest.mark.generic -@pytest.mark.parametrize( - 'config, app_path', [('init_deinit', f'{os.path.join(os.path.dirname(__file__), "gatt_client")}')], indirect=True -) +@pytest.mark.parametrize('config, app_path', [('init_deinit', f'{str(CUR_DIR / "gatt_client")}')], indirect=True) @idf_parametrize( 'target', ['esp32c6', 'esp32h2', 'esp32c3', 'esp32s3', 'esp32c5', 'esp32c61', 'esp32'], indirect=['target'] ) @@ -431,12 +431,12 @@ def test_bluedroid_host_init_deinit(dut: Dut) -> None: # # Case 9: BLE init deinit loop test for ESP32C2 26mhz xtal -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'baud, app_path, config', [ - ('74880', f'{os.path.join(os.path.dirname(__file__), "gatt_client")}', 'esp32c2_init_deinit'), + ('74880', f'{str(CUR_DIR / "gatt_client")}', 'esp32c2_init_deinit'), ], indirect=True, ) diff --git a/examples/bluetooth/bluedroid/ble_50/pytest_ble50_test.py b/examples/bluetooth/bluedroid/ble_50/pytest_ble50_test.py index d48aef51ac..e66757e798 100644 --- a/examples/bluetooth/bluedroid/ble_50/pytest_ble50_test.py +++ b/examples/bluetooth/bluedroid/ble_50/pytest_ble50_test.py @@ -1,22 +1,24 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path +from pathlib import Path from typing import Tuple import pytest from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize + +CUR_DIR = Path(__file__).parent.resolve() + + # Case 1: ble50 security client and ble50 security server test # EXAMPLE_CI_ID=6 - - -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "ble50_security_server")}|{os.path.join(os.path.dirname(__file__), "ble50_security_client")}', + f'{str(CUR_DIR / "ble50_security_server")}|{str(CUR_DIR / "ble50_security_client")}', 'name', 'y', ), @@ -52,7 +54,7 @@ def test_ble50_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: ble50 security client and ble50 security server test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=6 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -61,7 +63,7 @@ def test_ble50_security_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "ble50_security_server")}|{os.path.join(os.path.dirname(__file__), "ble50_security_client")}', + f'{str(CUR_DIR / "ble50_security_server")}|{str(CUR_DIR / "ble50_security_client")}', 'esp32c2_xtal26m', 'y', ), @@ -96,13 +98,13 @@ def test_c2_26mhz_xtal_ble50_security_func(app_path: str, dut: Tuple[IdfDut, Idf # Case 3: period_adv and period_sync test # EXAMPLE_CI_ID=8 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "periodic_adv")}|{os.path.join(os.path.dirname(__file__), "periodic_sync")}', + f'{str(CUR_DIR / "periodic_adv")}|{str(CUR_DIR / "periodic_sync")}', 'name', 'y', ), @@ -123,14 +125,14 @@ def test_period_adv_sync_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None adv_dut.expect_exact('Periodic advertising start, status 0', timeout=30) sync_dut.expect_exact('Extended scanning params set, status 0', timeout=30) sync_dut.expect_exact('Extended scanning start, status 0', timeout=30) - sync_dut.expect_exact(f'Create sync with the peer device BE', timeout=30) + sync_dut.expect_exact('Create sync with the peer device BE', timeout=30) sync_dut.expect_exact('Periodic advertising sync establish, status 0', timeout=30) sync_dut.expect_exact('Periodic adv report, sync handle ', timeout=30) # Case 4: period_adv and period_sync test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=8 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -139,7 +141,7 @@ def test_period_adv_sync_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "periodic_adv")}|{os.path.join(os.path.dirname(__file__), "periodic_sync")}', + f'{str(CUR_DIR / "periodic_adv")}|{str(CUR_DIR / "periodic_sync")}', 'esp32c2_xtal26m', 'y', ), @@ -159,20 +161,20 @@ def test_c2_26mhz_xtal_period_adv_sync_func(app_path: str, dut: Tuple[IdfDut, Id adv_dut.expect_exact('Periodic advertising start, status 0', timeout=30) sync_dut.expect_exact('Extended scanning params set, status 0', timeout=30) sync_dut.expect_exact('Extended scanning start, status 0', timeout=30) - sync_dut.expect_exact(f'Create sync with the peer device BE', timeout=30) + sync_dut.expect_exact('Create sync with the peer device BE', timeout=30) sync_dut.expect_exact('Periodic advertising sync establish, status 0', timeout=30) sync_dut.expect_exact('Periodic adv report, sync handle ', timeout=30) # Case 5: ble50 security client and ble50 security server config test # EXAMPLE_CI_ID=7 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, config, erase_nvs', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "ble50_security_server")}|{os.path.join(os.path.dirname(__file__), "ble50_security_client")}', + f'{str(CUR_DIR / "ble50_security_server")}|{str(CUR_DIR / "ble50_security_client")}', 'cfg_test', 'y', ), @@ -210,7 +212,7 @@ def test_ble50_security_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) - # Case 6: ble50 security client and ble50 security server config test for ESP32C2 26mhz xtal # EXAMPLE_CI_ID=7 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, target, baud, app_path, config, erase_nvs', @@ -219,7 +221,7 @@ def test_ble50_security_config_func(app_path: str, dut: Tuple[IdfDut, IdfDut]) - 2, 'esp32c2|esp32c2', '74880', - f'{os.path.join(os.path.dirname(__file__), "ble50_security_server")}|{os.path.join(os.path.dirname(__file__), "ble50_security_client")}', + f'{str(CUR_DIR / "ble50_security_server")}|{str(CUR_DIR / "ble50_security_client")}', 'esp32c2_cfg_test', 'y', ), diff --git a/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py b/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py index 74a9e40c5a..3190035c38 100644 --- a/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py +++ b/examples/bluetooth/bluedroid/classic_bt/pytest_classic_bt_test.py @@ -1,16 +1,15 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path +import os from typing import Tuple import pexpect import pytest from pytest_embedded_idf.dut import IdfDut + # Case 1: SPP - - -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, erase_all, config', [ @@ -45,7 +44,7 @@ def test_bt_spp_only(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: SPP_VFS -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ @@ -74,7 +73,7 @@ def test_bt_spp_vfs(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 3: A2DP -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ @@ -101,7 +100,7 @@ def test_bt_a2dp(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 4: HFP -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ @@ -126,7 +125,7 @@ def test_bt_hfp(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # # Case 5: HID -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ @@ -155,7 +154,7 @@ def test_bt_hid(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 6: L2CAP -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path, target, config', [ diff --git a/examples/bluetooth/nimble/pytest_nimble_test.py b/examples/bluetooth/nimble/pytest_nimble_test.py index 8f9d8a1e65..d9c5c62fdf 100644 --- a/examples/bluetooth/nimble/pytest_nimble_test.py +++ b/examples/bluetooth/nimble/pytest_nimble_test.py @@ -1,22 +1,24 @@ # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 -import os.path +from pathlib import Path from typing import Tuple import pexpect import pytest from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize + +CUR_DIR = Path(__file__).parent.resolve() + + # Case 1: BLE power save test - - -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path', [ ( 2, - f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}', + f'{str(CUR_DIR / "power_save")}|{str(CUR_DIR / "blecent")}', ), ], indirect=True, @@ -39,7 +41,7 @@ def test_power_save_conn(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: BLE power save test for ESP32C2 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'config, count, app_path, baud', @@ -47,7 +49,7 @@ def test_power_save_conn(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: ( 'esp32c2_xtal26m', 2, - f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}', + f'{str(CUR_DIR / "power_save")}|{str(CUR_DIR / "blecent")}', '74880', ), ], @@ -69,7 +71,7 @@ def test_power_save_conn_esp32c2_26mhz(dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: BLE power save test for ESP32C2ECO4 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.esp32c2eco4 @pytest.mark.parametrize( @@ -78,7 +80,7 @@ def test_power_save_conn_esp32c2_26mhz(dut: Tuple[IdfDut, IdfDut]) -> None: ( 'esp32c2eco4_xtal26m', 2, - f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}', + f'{str(CUR_DIR / "power_save")}|{str(CUR_DIR / "blecent")}', '74880', ), ], @@ -100,7 +102,7 @@ def test_power_save_conn_esp32c2eco4(dut: Tuple[IdfDut, IdfDut]) -> None: # Case 2: BLE power save test for ESP32C3ECO7 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'config, count, app_path', @@ -108,7 +110,7 @@ def test_power_save_conn_esp32c2eco4(dut: Tuple[IdfDut, IdfDut]) -> None: ( 'esp32c3eco7', 2, - f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}', + f'{str(CUR_DIR / "power_save")}|{str(CUR_DIR / "blecent")}', ), ], indirect=True, diff --git a/examples/wifi/getting_started/pytest_wifi_getting_started.py b/examples/wifi/getting_started/pytest_wifi_getting_started.py index 5a3ad64d27..e774507cf2 100644 --- a/examples/wifi/getting_started/pytest_wifi_getting_started.py +++ b/examples/wifi/getting_started/pytest_wifi_getting_started.py @@ -6,6 +6,7 @@ from typing import Tuple import pytest from pytest_embedded_idf.dut import IdfDut from pytest_embedded_idf.utils import idf_parametrize + # @pytest.mark.supported_targets # This test should support all targets, even between different target types # For now our CI only support multi dut with esp32 @@ -20,7 +21,7 @@ from pytest_embedded_idf.utils import idf_parametrize # ) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize( 'count, app_path', [ @@ -49,7 +50,7 @@ def test_wifi_getting_started(dut: Tuple[IdfDut, IdfDut]) -> None: softap.expect('station .+ join, AID=', timeout=60) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, config, baud, app_path', @@ -80,7 +81,7 @@ def test_wifi_getting_started_esp32c2_xtal_26mhz(dut: Tuple[IdfDut, IdfDut]) -> softap.expect('station .+ join, AID=', timeout=60) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.esp32c2eco4 @pytest.mark.parametrize( @@ -112,7 +113,7 @@ def test_wifi_getting_started_esp32c2eco4_xtal_26mhz(dut: Tuple[IdfDut, IdfDut]) softap.expect('station .+ join, AID=', timeout=60) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'count, config, app_path', diff --git a/examples/wifi/getting_started/station/pytest_wifi_station.py b/examples/wifi/getting_started/station/pytest_wifi_station.py index 5a93da1631..1a27b6ed6f 100644 --- a/examples/wifi/getting_started/station/pytest_wifi_station.py +++ b/examples/wifi/getting_started/station/pytest_wifi_station.py @@ -7,6 +7,7 @@ from typing import Tuple import pytest from pytest_embedded import Dut from pytest_embedded_idf.utils import idf_parametrize + # diff of esp32s2/esp32s3 ~45K, others ~50K DIFF_THRESHOLD = { @@ -16,7 +17,7 @@ DIFF_THRESHOLD = { } -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize('count, config, skip_autoflash', [(2, 'default|enable_softap', 'y')], indirect=True) @idf_parametrize( 'target', diff --git a/tools/ci/idf_pytest/constants.py b/tools/ci/idf_pytest/constants.py index c6c042b40e..9e1d354dff 100644 --- a/tools/ci/idf_pytest/constants.py +++ b/tools/ci/idf_pytest/constants.py @@ -135,7 +135,7 @@ ENV_MARKERS = { 'openthread_bbr': 'tests should be used for openthread border router linked to Internet.', 'openthread_sleep': 'tests should be used for openthread sleepy device.', 'zigbee_multi_dut': 'zigbee runner which have multiple duts.', - 'wifi_two_dut': 'tests should be run on runners which has two wifi duts connected.', + 'two_duts': 'tests should be run on runners which has two wifi duts connected.', 'generic_multi_device': 'generic multiple devices whose corresponding gpio pins are connected to each other.', 'twai_network': 'multiple runners form a TWAI network.', 'sdio_master_slave': 'Test sdio multi board, esp32+esp32', diff --git a/tools/test_apps/phy/phy_tsens/pytest_phy_tsens.py b/tools/test_apps/phy/phy_tsens/pytest_phy_tsens.py index f2fc1e87b4..e559ff14e3 100644 --- a/tools/test_apps/phy/phy_tsens/pytest_phy_tsens.py +++ b/tools/test_apps/phy/phy_tsens/pytest_phy_tsens.py @@ -144,7 +144,7 @@ def run_phy_tsens_test_with_light_sleep(dut: Tuple[Dut, Dut]) -> None: assert 0 < float(temp_val) < 70 -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.parametrize('count', [2], indirect=True) @idf_parametrize('target', ['esp32c3', 'esp32c6', 'esp32c5', 'esp32s2', 'esp32s3', 'esp32c61'], indirect=['target']) def test_phy_tsens_coexist(dut: Tuple[Dut, Dut]) -> None: @@ -163,7 +163,7 @@ def test_phy_tsens_coexist(dut: Tuple[Dut, Dut]) -> None: run_phy_tsens_test_with_light_sleep(dut) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.parametrize( 'count, config, baud', @@ -189,7 +189,7 @@ def test_phy_tsens_coexist_c2_xtal26m(dut: Tuple[Dut, Dut]) -> None: run_phy_tsens_test_with_light_sleep(dut) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.xtal_26mhz @pytest.mark.esp32c2eco4 @pytest.mark.parametrize( @@ -216,7 +216,7 @@ def test_phy_tsens_coexist_c2eco4_xtal26m(dut: Tuple[Dut, Dut]) -> None: run_phy_tsens_test_with_light_sleep(dut) -@pytest.mark.wifi_two_dut +@pytest.mark.two_duts @pytest.mark.esp32c3eco7 @pytest.mark.parametrize( 'count, config', From d3c350d42d0077bbbc090b1d3fc8455e6f46c87c Mon Sep 17 00:00:00 2001 From: Chen Yudong Date: Wed, 12 Nov 2025 18:34:53 +0800 Subject: [PATCH 155/156] ci: fix sdkconfig.ci.xxx for wifi examples --- examples/wifi/getting_started/softAP/sdkconfig.ci | 1 + examples/wifi/getting_started/softAP/sdkconfig.ci.c3eco7 | 2 ++ .../wifi/getting_started/softAP/sdkconfig.ci.esp32c2_xtal26m | 2 ++ .../getting_started/softAP/sdkconfig.ci.esp32c2eco4_xtal26m | 2 ++ examples/wifi/getting_started/softAP/sdkconfig.ci.wpa_psk | 2 ++ examples/wifi/getting_started/station/sdkconfig.ci | 1 + examples/wifi/getting_started/station/sdkconfig.ci.c3eco7 | 2 ++ .../wifi/getting_started/station/sdkconfig.ci.enable_softap | 2 ++ .../wifi/getting_started/station/sdkconfig.ci.esp32c2_xtal26m | 2 ++ .../getting_started/station/sdkconfig.ci.esp32c2eco4_xtal26m | 2 ++ examples/wifi/getting_started/station/sdkconfig.ci.ft | 2 ++ examples/wifi/getting_started/station/sdkconfig.ci.rrm | 2 ++ examples/wifi/getting_started/station/sdkconfig.ci.wnm | 2 ++ examples/wifi/getting_started/station/sdkconfig.ci.wpa_psk | 2 ++ 14 files changed, 26 insertions(+) diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci b/examples/wifi/getting_started/softAP/sdkconfig.ci index b416e9f87c..9633644b46 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci @@ -1,2 +1,3 @@ +# build xxx_default CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci.c3eco7 b/examples/wifi/getting_started/softAP/sdkconfig.ci.c3eco7 index ad055155c9..badfbca2bd 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci.c3eco7 +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci.c3eco7 @@ -1,2 +1,4 @@ CONFIG_IDF_TARGET="esp32c3" CONFIG_ESP32C3_REV_MIN_101=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2_xtal26m b/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2_xtal26m index 172f022b67..814241b72f 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2_xtal26m +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2_xtal26m @@ -1,2 +1,4 @@ CONFIG_IDF_TARGET="esp32c2" CONFIG_XTAL_FREQ_26=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2eco4_xtal26m b/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2eco4_xtal26m index 651a6cc578..db99cc188f 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2eco4_xtal26m +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci.esp32c2eco4_xtal26m @@ -1,3 +1,5 @@ CONFIG_IDF_TARGET="esp32c2" CONFIG_XTAL_FREQ_26=y CONFIG_ESP32C2_REV_MIN_200=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/softAP/sdkconfig.ci.wpa_psk b/examples/wifi/getting_started/softAP/sdkconfig.ci.wpa_psk index 4fee0b0352..240bb635e6 100644 --- a/examples/wifi/getting_started/softAP/sdkconfig.ci.wpa_psk +++ b/examples/wifi/getting_started/softAP/sdkconfig.ci.wpa_psk @@ -1 +1,3 @@ CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT=n +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci b/examples/wifi/getting_started/station/sdkconfig.ci index b416e9f87c..9633644b46 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci +++ b/examples/wifi/getting_started/station/sdkconfig.ci @@ -1,2 +1,3 @@ +# build xxx_default CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.c3eco7 b/examples/wifi/getting_started/station/sdkconfig.ci.c3eco7 index ad055155c9..badfbca2bd 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.c3eco7 +++ b/examples/wifi/getting_started/station/sdkconfig.ci.c3eco7 @@ -1,2 +1,4 @@ CONFIG_IDF_TARGET="esp32c3" CONFIG_ESP32C3_REV_MIN_101=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.enable_softap b/examples/wifi/getting_started/station/sdkconfig.ci.enable_softap index cf2d4f2434..57c9b87740 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.enable_softap +++ b/examples/wifi/getting_started/station/sdkconfig.ci.enable_softap @@ -1 +1,3 @@ CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2_xtal26m b/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2_xtal26m index 172f022b67..814241b72f 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2_xtal26m +++ b/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2_xtal26m @@ -1,2 +1,4 @@ CONFIG_IDF_TARGET="esp32c2" CONFIG_XTAL_FREQ_26=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2eco4_xtal26m b/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2eco4_xtal26m index 651a6cc578..db99cc188f 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2eco4_xtal26m +++ b/examples/wifi/getting_started/station/sdkconfig.ci.esp32c2eco4_xtal26m @@ -1,3 +1,5 @@ CONFIG_IDF_TARGET="esp32c2" CONFIG_XTAL_FREQ_26=y CONFIG_ESP32C2_REV_MIN_200=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.ft b/examples/wifi/getting_started/station/sdkconfig.ci.ft index 10169bbff2..83cd86bfbe 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.ft +++ b/examples/wifi/getting_started/station/sdkconfig.ci.ft @@ -1 +1,3 @@ CONFIG_ESP_WIFI_11R_SUPPORT=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.rrm b/examples/wifi/getting_started/station/sdkconfig.ci.rrm index 61c172f523..a7a05f2a17 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.rrm +++ b/examples/wifi/getting_started/station/sdkconfig.ci.rrm @@ -1,2 +1,4 @@ CONFIG_ESP_WIFI_11KV_SUPPORT=y CONFIG_ESP_WIFI_RRM_SUPPORT=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.wnm b/examples/wifi/getting_started/station/sdkconfig.ci.wnm index 9f87bf640e..91c8f2d587 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.wnm +++ b/examples/wifi/getting_started/station/sdkconfig.ci.wnm @@ -1,2 +1,4 @@ CONFIG_ESP_WIFI_11KV_SUPPORT=y CONFIG_ESP_WIFI_WNM_SUPPORT=y +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" diff --git a/examples/wifi/getting_started/station/sdkconfig.ci.wpa_psk b/examples/wifi/getting_started/station/sdkconfig.ci.wpa_psk index bc969e6b4d..af2ee3f36a 100644 --- a/examples/wifi/getting_started/station/sdkconfig.ci.wpa_psk +++ b/examples/wifi/getting_started/station/sdkconfig.ci.wpa_psk @@ -1 +1,3 @@ CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=n +CONFIG_ESP_WIFI_SSID="ssid_${IDF_TARGET}_${CI_PIPELINE_ID}" +CONFIG_ESP_WIFI_PASSWORD="password_${IDF_TARGET}_${CI_PIPELINE_ID}" From 976709a1151a0b67c406231554ec26709571d3fb Mon Sep 17 00:00:00 2001 From: zwx Date: Tue, 30 Dec 2025 11:03:23 +0800 Subject: [PATCH 156/156] fix(openthread): removed unused ulp configuration --- .../openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt | 2 +- .../openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt b/examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt index e205eff4b8..0eae9c4991 100644 --- a/examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt +++ b/examples/openthread/ot_sleepy_device/deep_sleep/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "esp_ot_sleepy_device.c" - PRIV_REQUIRES esp_event esp_timer openthread nvs_flash ulp + PRIV_REQUIRES esp_event esp_timer openthread nvs_flash INCLUDE_DIRS ".") diff --git a/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults b/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults index 18d548c09c..6c17f055c7 100644 --- a/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults +++ b/examples/openthread/ot_sleepy_device/deep_sleep/sdkconfig.defaults @@ -42,8 +42,6 @@ CONFIG_IEEE802154_ENABLED=y # # deep sleep # -CONFIG_ULP_COPROC_ENABLED=y -CONFIG_ULP_COPROC_RESERVE_MEM=512 CONFIG_LIBC_TIME_SYSCALL_USE_RTC_HRT=y CONFIG_RTC_CLK_SRC_INT_RC=y CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y