fix(ble_esl): apply persist review follow-ups

Let the app supply Absolute Time, keep the AP Sync Key global,
roll back a failed restore, and drop the dead SYNC_LOST generation.
This commit is contained in:
jiminxiang
2026-09-11 17:48:41 +08:00
parent 00738e06d3
commit b17865bfa4
10 changed files with 110 additions and 103 deletions

View File

@@ -413,7 +413,7 @@ esp_err_t ble_esl_export_persisted_tag(ble_esl_persisted_tag_t *out);
*
* Performs bare field assignment (does NOT call esl_state_transition). Sets
* state to UNSYNCHRONIZED and config_complete to Address|AP Sync|Resp only
* (CONFIG_BIT_ABS_TIME cleared). Does not start advertising or timers —
* (Absolute Time bit cleared). Does not start advertising or timers —
* ble_esl_start() must follow to arm unsync_timer and connectable advertising.
*
* @param[in] info Valid association snapshot

View File

@@ -106,6 +106,7 @@ typedef struct {
typedef struct {
ble_esl_ap_cb_t callback; /*!< Application event callback (must not be NULL) */
ble_esl_ap_pawr_config_t pawr_config; /*!< PAwR timing parameters */
ble_esl_key_material_t ap_sync_key; /*!< PAwR train Sync Key (one per AP, not per ESL) */
} ble_esl_ap_config_t;
/* ========================== Connection Event Structures ========================== */
@@ -159,7 +160,6 @@ typedef struct {
typedef struct {
uint8_t esl_id; /*!< ESL_ID to assign (0x000xFE) */
uint8_t group_id; /*!< Group_ID to assign (0x000x7F) */
ble_esl_key_material_t ap_sync_key; /*!< AP Sync Key Material (session key + IV) */
ble_esl_key_material_t resp_key; /*!< ESL Response Key Material (session key + IV) */
} ble_esl_ap_esl_config_t;
@@ -348,13 +348,25 @@ typedef struct {
* Registers the application callback, stores PAwR timing parameters,
* and allocates internal resources. Must be called before any other API.
*
* @param config Pointer to AP configuration (callback + PAwR timing)
* @param config Pointer to AP configuration (callback, PAwR timing, AP Sync Key)
* @return ESP_OK on success; ESP_ERR_INVALID_ARG if config/callback is NULL or
* num_subevents is outside 1128;
* ESP_ERR_INVALID_STATE if already initialized
*/
esp_err_t ble_esl_ap_init(const ble_esl_ap_config_t *config);
/**
* @brief Set or replace the AP-wide PAwR Sync Key Material
*
* One key encrypts the whole PAwR train. ble_esl_ap_init() installs
* config->ap_sync_key; call this to rekey or restore a persisted network
* key. Does not rewrite already-configured ESLs over GATT.
*
* @param key AP Sync Key Material (session key + IV)
* @return ESP_OK on success; ESP_ERR_INVALID_ARG / ESP_ERR_INVALID_STATE
*/
esp_err_t ble_esl_ap_set_sync_key(const ble_esl_key_material_t *key);
/**
* @brief Deinitialize the AP module
*
@@ -483,12 +495,13 @@ esp_err_t ble_esl_ap_abort_tag_connections(void);
/**
* @brief Write ESL configuration characteristics
*
* Writes ESL Address, AP Sync Key Material, ESL Response Key Material, and
* ESL Current Absolute Time in sequence. Async — result via
* Writes ESL Address, the AP-wide Sync Key already installed by
* ble_esl_ap_init() / ble_esl_ap_set_sync_key(), ESL Response Key Material,
* and ESL Current Absolute Time in sequence. Async — result via
* BLE_ESL_AP_EVT_CONFIGURED.
*
* @param conn_handle Connection handle of the connected ESL
* @param config Pointer to configuration parameters
* @param config Pointer to per-ESL parameters (address + response key)
* @return ESP_OK if operation initiated; error code on failure
*/
esp_err_t ble_esl_ap_configure(uint16_t conn_handle,
@@ -537,14 +550,17 @@ bool ble_esl_ap_synchronize_in_progress(void);
/**
* @brief Write ESL Current Absolute Time on an encrypted ACL link
*
* Uses the current boot monotonic clock (esp_timer_get_time()/1000).
* Completion is BLE_ESL_AP_EVT_ABS_TIME_WRITTEN (once, if this returns ESP_OK).
* @p abs_time_ms is the ESL 32-bit millisecond counter (wrapping), not a
* POSIX/RTC timestamp. The application owns the epoch (boot monotonic,
* persisted network time, SNTP-derived, etc.). Completion is
* BLE_ESL_AP_EVT_ABS_TIME_WRITTEN (once, if this returns ESP_OK).
* Rejected while configure occupies the same connection.
*
* @param conn_handle Connection handle of the connected ESL
* @param abs_time_ms Absolute time in milliseconds to write to the ESL
* @return ESP_OK if the GATT write was initiated
*/
esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle);
esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle, uint32_t abs_time_ms);
/**
* @brief In-memory association snapshot used to seed AP tracking after reboot
@@ -552,15 +568,14 @@ esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle);
* Not an NVS/wire blob. Call after ble_esl_ap_init(); may be invoked
* multiple times (once per ESL), including after ble_esl_ap_start_pawr().
* Key material is not checked for all-zeros — the application must
* quarantine corrupt records. The AP Sync Key of the last successful
* restore is installed as the current PAwR key.
* quarantine corrupt records. The AP Sync Key is AP-wide: restore it
* once via ble_esl_ap_init() / ble_esl_ap_set_sync_key(), not per ESL.
*/
typedef struct {
ble_esl_address_t esl_address; /*!< ESL Address (ESL_ID + Group_ID) */
uint8_t ble_addr[6]; /*!< Identity address of the ESL */
uint8_t ble_addr_type; /*!< BLE address type */
ble_esl_key_material_t ap_sync_key;
ble_esl_key_material_t resp_key;
ble_esl_key_material_t resp_key; /*!< Per-ESL Response Key Material */
} ble_esl_ap_persisted_esl_t;
esp_err_t ble_esl_ap_restore_persisted_esl(const ble_esl_ap_persisted_esl_t *info);

View File

@@ -269,6 +269,8 @@ esp_err_t ble_esl_ap_init(const ble_esl_ap_config_t *config)
g_esl_ap->app_cb = config->callback;
g_esl_ap->pawr_config = config->pawr_config;
g_esl_ap->initialized = true;
ble_esl_ap_pawr_set_sync_key(&config->ap_sync_key);
g_esl_ap->ap_sync_key_valid = true;
g_esl_ap->pawr_started = false;
g_esl_ap->pawr_active = false;
@@ -335,6 +337,19 @@ esp_err_t ble_esl_ap_init(const ble_esl_ap_config_t *config)
return ESP_OK;
}
esp_err_t ble_esl_ap_set_sync_key(const ble_esl_key_material_t *key)
{
if (g_esl_ap == NULL || !g_esl_ap->initialized) {
return ESP_ERR_INVALID_STATE;
}
if (key == NULL) {
return ESP_ERR_INVALID_ARG;
}
ble_esl_ap_pawr_set_sync_key(key);
g_esl_ap->ap_sync_key_valid = true;
return ESP_OK;
}
/**
* @brief Run the disconnect cleanup for one established link during deinit
*

View File

@@ -64,6 +64,7 @@ _Static_assert(sizeof(ble_esl_key_material_t) == BLE_ESL_KEY_MATERIAL_SIZE,
typedef struct {
uint16_t conn_handle;
ble_esl_ap_esl_config_t config;
ble_esl_key_material_t ap_sync_key; /*!< Snapshot of the AP-wide sync key */
uint16_t esl_addr;
uint32_t lf_generation;
} configure_ctx_t;
@@ -182,8 +183,7 @@ static TaskHandle_t s_lifecycle_holder;
_Static_assert(sizeof(ble_esl_key_material_t) == 24, "sync key packed 24");
_Static_assert(sizeof(ble_esl_key_material_t) == 24, "resp key packed 24");
/* In-memory compactness only — not an NVS/wire layout. */
_Static_assert(offsetof(ble_esl_ap_persisted_esl_t, ap_sync_key) == 9, "flat key block start");
_Static_assert(offsetof(ble_esl_ap_persisted_esl_t, resp_key) == 9 + 24, "resp key follows sync");
_Static_assert(offsetof(ble_esl_ap_persisted_esl_t, resp_key) == 9, "resp key follows identity");
static void lf_lock(void)
{
@@ -261,11 +261,9 @@ static void lf_release(ble_esl_ap_conn_t *conn, uint32_t generation)
}
}
static esp_err_t write_abs_time_bytes(uint16_t conn_handle,
static esp_err_t write_abs_time_bytes(uint16_t conn_handle, uint32_t abs_time_ms,
ble_esl_ap_gatt_cb_t cb, void *user_data)
{
int64_t now_us = esp_timer_get_time();
uint32_t abs_time_ms = (uint32_t)(now_us / 1000ULL);
uint8_t abs_time_data[4] = {
(uint8_t)(abs_time_ms & 0xFF),
(uint8_t)((abs_time_ms >> 8) & 0xFF),
@@ -318,7 +316,7 @@ static void write_abs_time_gatt_cb(uint16_t conn_handle, esp_err_t status,
free(ctx);
}
esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle)
esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle, uint32_t abs_time_ms)
{
if (g_esl_ap == NULL) {
return ESP_ERR_INVALID_STATE;
@@ -346,7 +344,8 @@ esp_err_t ble_esl_ap_write_absolute_time(uint16_t conn_handle)
ctx->generation = gen;
ctx->public_event = true;
esp_err_t ret = write_abs_time_bytes(conn_handle, write_abs_time_gatt_cb, ctx);
esp_err_t ret = write_abs_time_bytes(conn_handle, abs_time_ms,
write_abs_time_gatt_cb, ctx);
if (ret != ESP_OK) {
lf_lock();
conn = ble_esl_ap_find_conn(conn_handle);
@@ -369,7 +368,9 @@ static esp_err_t write_abs_time_for_configure(uint16_t conn_handle, uint32_t gen
ctx->public_event = false;
ctx->chained_cb = configure_write_abs_time_cb;
ctx->user_data = configure_ctx;
esp_err_t ret = write_abs_time_bytes(conn_handle, write_abs_time_gatt_cb, ctx);
uint32_t abs_time_ms = (uint32_t)(esp_timer_get_time() / 1000ULL);
esp_err_t ret = write_abs_time_bytes(conn_handle, abs_time_ms,
write_abs_time_gatt_cb, ctx);
if (ret != ESP_OK) {
free(ctx);
}
@@ -624,6 +625,11 @@ esp_err_t ble_esl_ap_configure(uint16_t conn_handle,
return ESP_ERR_INVALID_ARG;
}
if (!g_esl_ap->ap_sync_key_valid) {
ESP_LOGE(TAG, "configure: AP Sync Key not set");
return ESP_ERR_INVALID_STATE;
}
/* Validate connection handle */
ble_esl_ap_conn_t *conn = ble_esl_ap_find_conn(conn_handle);
if (conn == NULL) {
@@ -639,6 +645,7 @@ esp_err_t ble_esl_ap_configure(uint16_t conn_handle,
ctx->conn_handle = conn_handle;
memcpy(&ctx->config, config, sizeof(ble_esl_ap_esl_config_t));
ctx->ap_sync_key = g_esl_ap->ap_sync_key;
ctx->esl_addr = BLE_ESL_AP_MAKE_ADDR(config->esl_id, config->group_id);
/* Store ESL address in connection context for cross-reference */
@@ -681,9 +688,6 @@ esp_err_t ble_esl_ap_configure(uint16_t conn_handle,
return occ;
}
/* Set PAwR sync key (shared across all ESLs) */
ble_esl_ap_pawr_set_sync_key(&config->ap_sync_key);
/* Set per-ESL response key */
esp_err_t ret = ble_esl_ap_pawr_set_response_key(ctx->esl_addr,
&config->resp_key);
@@ -731,8 +735,8 @@ static void configure_write_addr_cb(uint16_t conn_handle, esp_err_t status,
/* Step 2: Write AP Sync Key Material (24 bytes: 16-byte key + 8-byte IV) */
esp_err_t ret = ble_esl_ap_gatt_write(conn_handle, BLE_ESL_CHR_UUID_AP_SYNC_KEY,
(const uint8_t *)&ctx->config.ap_sync_key,
sizeof(ctx->config.ap_sync_key),
(const uint8_t *)&ctx->ap_sync_key,
sizeof(ctx->ap_sync_key),
configure_write_sync_key_cb, ctx);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "configure: failed to initiate AP Sync Key write: %s",
@@ -1699,13 +1703,23 @@ esp_err_t ble_esl_ap_restore_persisted_esl(const ble_esl_ap_persisted_esl_t *inf
return ESP_ERR_INVALID_ARG;
}
if (!g_esl_ap->ap_sync_key_valid) {
ESP_LOGE(TAG, "restore: AP Sync Key not set");
return ESP_ERR_INVALID_STATE;
}
ble_esl_ap_tracking_lock();
ble_esl_ap_esl_entry_t *esl = ble_esl_ap_find_esl(esl_addr);
if (esl == NULL) {
esl = ble_esl_ap_find_esl_by_ble_addr(info->ble_addr, info->ble_addr_type);
}
bool created = false;
ble_esl_ap_esl_entry_t backup = { 0 };
if (esl == NULL) {
esl = ble_esl_ap_alloc_esl();
created = true;
} else {
backup = *esl;
}
if (esl == NULL) {
ble_esl_ap_tracking_unlock();
@@ -1722,24 +1736,26 @@ esp_err_t ble_esl_ap_restore_persisted_esl(const ble_esl_ap_persisted_esl_t *inf
esl->pending_pawr_cmd_opcode = 0;
esl->resp_key = info->resp_key;
esl->last_sync_time_us = 0;
ble_esl_ap_tracking_unlock();
ble_esl_ap_pawr_set_sync_key(&info->ap_sync_key);
esp_err_t ret = ble_esl_ap_pawr_set_response_key(esl_addr,
&info->resp_key);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "restore: set response key for 0x%04X failed: %s",
esl_addr, esp_err_to_name(ret));
}
ret = ble_esl_ap_update_esl_state(esl_addr,
BLE_ESL_STATE_UNSYNCHRONIZED);
ble_esl_ap_state_evt_snap_t snap = { 0 };
esp_err_t ret = ble_esl_ap_update_esl_state_locked(esl_addr,
BLE_ESL_STATE_UNSYNCHRONIZED,
&snap);
if (ret != ESP_OK) {
if (created) {
memset(esl, 0, sizeof(*esl));
esl->in_use = false;
esl->conn_handle = BLE_ESL_AP_CONN_HANDLE_INVALID;
} else {
*esl = backup;
}
ble_esl_ap_tracking_unlock();
ESP_LOGE(TAG, "restore: failed to mark ESL 0x%04X unsynchronized: %s",
esl_addr, esp_err_to_name(ret));
return ret;
}
ble_esl_ap_tracking_unlock();
ble_esl_ap_dispatch_state_evt(&snap);
ESP_LOGI(TAG, "Restored ESL 0x%04X from persistence (awaiting resync)",
esl_addr);

View File

@@ -247,6 +247,7 @@ typedef struct {
/* PAwR broadcaster state */
ble_esl_key_material_t ap_sync_key; /*!< AP Sync Key Material */
bool ap_sync_key_valid; /*!< Sync key installed via init/setter */
uint8_t randomizer[BLE_ESL_RANDOMIZER_SIZE]; /*!< Current AP Randomizer (5 octets, LE) */
bool pawr_active; /*!< PAwR broadcaster is running */
ble_esl_ap_pawr_pending_t *pawr_pending; /*!< Per-subevent pending TX buffers (num_subevents entries) */

View File

@@ -30,12 +30,12 @@ extern "C" {
/* ========================== Configuration Bitmask ========================== */
#define CONFIG_BIT_ADDRESS (1 << 0)
#define CONFIG_BIT_AP_SYNC_KEY (1 << 1)
#define CONFIG_BIT_RESP_KEY (1 << 2)
#define CONFIG_BIT_ABS_TIME (1 << 3)
#define CONFIG_COMPLETE_MASK (CONFIG_BIT_ADDRESS | CONFIG_BIT_AP_SYNC_KEY | \
CONFIG_BIT_RESP_KEY | CONFIG_BIT_ABS_TIME)
#define ESL_CONFIG_BIT_ADDRESS (1 << 0)
#define ESL_CONFIG_BIT_AP_SYNC_KEY (1 << 1)
#define ESL_CONFIG_BIT_RESP_KEY (1 << 2)
#define ESL_CONFIG_BIT_ABS_TIME (1 << 3)
#define ESL_CONFIG_COMPLETE_MASK (ESL_CONFIG_BIT_ADDRESS | ESL_CONFIG_BIT_AP_SYNC_KEY | \
ESL_CONFIG_BIT_RESP_KEY | ESL_CONFIG_BIT_ABS_TIME)
/* ========================== Internal State Context ========================== */
typedef struct {
@@ -65,9 +65,7 @@ typedef struct {
* retiring_* tracks a locally terminated old sync so its SYNC_LOST does not
* look like a natural loss of the new train. */
uint16_t current_sync_handle; /* Valid periodic sync; BLE_HS_CONN_HANDLE_NONE if none */
uint32_t sync_generation; /* Bumps each time current_sync_handle is assigned a new value */
uint16_t retiring_sync_handle; /* Locally terminated old sync awaiting SYNC_LOST */
uint32_t retiring_sync_generation; /* Snapshot of sync_generation when current was retired */
bool retiring_local_terminate; /* retiring SYNC_LOST is expected; do not change ESL state */
bool past_received; /* PAST completed in Updating state */
bool pawr_synced; /* Synchronized to the AP's PAwR train (retained across Updating) */

View File

@@ -241,7 +241,7 @@ static int handle_write_esl_address(struct os_mbuf *om)
s_esl_gatts->ctx->esl_address = addr;
s_esl_gatts->ctx->address_valid = true;
s_esl_gatts->ctx->config_complete |= CONFIG_BIT_ADDRESS;
s_esl_gatts->ctx->config_complete |= ESL_CONFIG_BIT_ADDRESS;
ESP_LOGI(TAG, "ESL Address set: id=0x%02x group=0x%02x",
addr.esl_id, BLE_ESL_ADDR_GROUP_ID(addr));
return 0;
@@ -261,7 +261,7 @@ static int handle_write_ap_sync_key(struct os_mbuf *om)
}
s_esl_gatts->ctx->ap_sync_key_valid = true;
s_esl_gatts->ctx->config_complete |= CONFIG_BIT_AP_SYNC_KEY;
s_esl_gatts->ctx->config_complete |= ESL_CONFIG_BIT_AP_SYNC_KEY;
ESP_LOGI(TAG, "AP Sync Key Material written");
return 0;
}
@@ -280,7 +280,7 @@ static int handle_write_resp_key(struct os_mbuf *om)
}
s_esl_gatts->ctx->resp_key_valid = true;
s_esl_gatts->ctx->config_complete |= CONFIG_BIT_RESP_KEY;
s_esl_gatts->ctx->config_complete |= ESL_CONFIG_BIT_RESP_KEY;
ESP_LOGI(TAG, "ESL Response Key Material written");
return 0;
}
@@ -300,7 +300,7 @@ static int handle_write_abs_time(struct os_mbuf *om)
s_esl_gatts->ctx->abs_time_base = time_val;
s_esl_gatts->ctx->abs_time_offset_us = esp_timer_get_time();
s_esl_gatts->ctx->config_complete |= CONFIG_BIT_ABS_TIME;
s_esl_gatts->ctx->config_complete |= ESL_CONFIG_BIT_ABS_TIME;
ESP_LOGI(TAG, "ESL Absolute Time set: %" PRIu32 " ms", time_val);
return 0;
}

View File

@@ -6,7 +6,7 @@
/**
* @file esl_persisted_tag_map.h
* @brief Pure helpers for TAG persisted snapshot field mapping (host-testable).
* @brief Helpers for TAG persisted snapshot field mapping.
*/
#pragma once
@@ -14,20 +14,15 @@
#include <stdbool.h>
#include <string.h>
#include "ble_esl_common.h"
#include "ble_esl_state_int.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef CONFIG_BIT_ADDRESS
#define CONFIG_BIT_ADDRESS (1 << 0)
#define CONFIG_BIT_AP_SYNC_KEY (1 << 1)
#define CONFIG_BIT_RESP_KEY (1 << 2)
#define CONFIG_BIT_ABS_TIME (1 << 3)
#endif
/* Persist does not store Absolute Time; restore must leave that bit clear. */
#define ESL_PERSISTED_CONFIG_MASK \
(CONFIG_BIT_ADDRESS | CONFIG_BIT_AP_SYNC_KEY | CONFIG_BIT_RESP_KEY)
(ESL_CONFIG_BIT_ADDRESS | ESL_CONFIG_BIT_AP_SYNC_KEY | ESL_CONFIG_BIT_RESP_KEY)
typedef struct {
ble_esl_address_t esl_address;

View File

@@ -11,7 +11,6 @@
#include <string.h>
#include <assert.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
@@ -58,7 +57,6 @@ static void clear_retiring_sync(void)
return;
}
s_ctx->retiring_sync_handle = BLE_HS_CONN_HANDLE_NONE;
s_ctx->retiring_sync_generation = 0;
s_ctx->retiring_local_terminate = false;
}
@@ -68,7 +66,6 @@ static void clear_current_sync_bookkeeping(void)
return;
}
s_ctx->current_sync_handle = BLE_HS_CONN_HANDLE_NONE;
/* sync_generation is monotonic across NONE assignments; do not reset. */
}
static void install_current_sync(uint16_t sync_handle)
@@ -77,11 +74,6 @@ static void install_current_sync(uint16_t sync_handle)
return;
}
s_ctx->current_sync_handle = sync_handle;
if (s_ctx->sync_generation == UINT32_MAX) {
s_ctx->sync_generation = 1;
} else {
s_ctx->sync_generation++;
}
}
/**
@@ -112,10 +104,8 @@ static esp_err_t retire_current_sync(bool rearm_past)
}
uint16_t old_handle = s_ctx->current_sync_handle;
uint32_t old_generation = s_ctx->sync_generation;
s_ctx->retiring_sync_handle = old_handle;
s_ctx->retiring_sync_generation = old_generation;
s_ctx->retiring_local_terminate = true;
s_ctx->current_sync_handle = BLE_HS_CONN_HANDLE_NONE;
s_ctx->past_pending = rearm_past;
@@ -130,8 +120,8 @@ static esp_err_t retire_current_sync(bool rearm_past)
return ESP_FAIL;
}
ESP_LOGI(TAG, "Retired sync handle=%u gen=%" PRIu32 " rearm_past=%d",
old_handle, old_generation, rearm_past);
ESP_LOGI(TAG, "Retired sync handle=%u rearm_past=%d",
old_handle, rearm_past);
return ESP_OK;
}
@@ -155,9 +145,7 @@ static void adopt_past_sync(uint16_t sync_handle)
}
uint16_t old_handle = s_ctx->current_sync_handle;
uint32_t old_generation = s_ctx->sync_generation;
s_ctx->retiring_sync_handle = old_handle;
s_ctx->retiring_sync_generation = old_generation;
s_ctx->retiring_local_terminate = true;
s_ctx->current_sync_handle = BLE_HS_CONN_HANDLE_NONE;
s_ctx->past_pending = false;
@@ -176,7 +164,7 @@ static void adopt_past_sync(uint16_t sync_handle)
}
if (s_ctx->current_sync_handle == sync_handle) {
/* Same handle reported again — keep generation. */
/* Same handle reported again. */
return;
}
@@ -455,7 +443,7 @@ void esl_notify_update_complete(void)
case BLE_ESL_STATE_CONFIGURING:
/* First provisioning also requires all mandatory configuration writes. */
if (s_ctx->past_received &&
(s_ctx->config_complete & CONFIG_COMPLETE_MASK) == CONFIG_COMPLETE_MASK) {
(s_ctx->config_complete & ESL_CONFIG_COMPLETE_MASK) == ESL_CONFIG_COMPLETE_MASK) {
esl_state_transition(BLE_ESL_STATE_SYNCHRONIZED);
} else {
ESP_LOGI(TAG, "Update Complete received in Configuring — waiting for PAST / config");
@@ -748,7 +736,7 @@ static void handle_gap_disconnect(struct ble_gap_event *event)
switch (s_ctx->state) {
case BLE_ESL_STATE_CONFIGURING:
if ((s_ctx->config_complete & CONFIG_COMPLETE_MASK) == CONFIG_COMPLETE_MASK) {
if ((s_ctx->config_complete & ESL_CONFIG_COMPLETE_MASK) == ESL_CONFIG_COMPLETE_MASK) {
/* Configuration complete — go to Unsynchronized */
esl_state_transition(BLE_ESL_STATE_UNSYNCHRONIZED);
} else {
@@ -977,7 +965,7 @@ static void handle_gap_periodic_transfer(struct ble_gap_event *event)
* advance the state machine before provisioning finishes. */
s_ctx->past_received = true;
if (s_ctx->update_complete_received &&
(s_ctx->config_complete & CONFIG_COMPLETE_MASK) == CONFIG_COMPLETE_MASK) {
(s_ctx->config_complete & ESL_CONFIG_COMPLETE_MASK) == ESL_CONFIG_COMPLETE_MASK) {
esl_state_transition(BLE_ESL_STATE_SYNCHRONIZED);
} else {
ESP_LOGI(TAG, "PAST received in Configuring — waiting for Update Complete / config");
@@ -1118,9 +1106,7 @@ static int esl_gap_event_handler(struct ble_gap_event *event, void *arg)
uint16_t lost_handle = event->periodic_sync_lost.sync_handle;
esl_sync_lost_ctx_t lost_ctx = {
.current_sync_handle = s_ctx->current_sync_handle,
.sync_generation = s_ctx->sync_generation,
.retiring_sync_handle = s_ctx->retiring_sync_handle,
.retiring_sync_generation = s_ctx->retiring_sync_generation,
.retiring_local_terminate = s_ctx->retiring_local_terminate,
};
esl_sync_lost_class_t kind = esl_classify_sync_lost(&lost_ctx, lost_handle);
@@ -1711,9 +1697,7 @@ esp_err_t ble_esl_restore_persisted_tag(const ble_esl_persisted_tag_t *info)
s_ctx->pawr_synced = false;
s_ctx->update_complete_received = false;
s_ctx->current_sync_handle = BLE_HS_CONN_HANDLE_NONE;
s_ctx->sync_generation = 0;
s_ctx->retiring_sync_handle = BLE_HS_CONN_HANDLE_NONE;
s_ctx->retiring_sync_generation = 0;
s_ctx->retiring_local_terminate = false;
s_ctx->state = BLE_ESL_STATE_UNSYNCHRONIZED;

View File

@@ -4,6 +4,10 @@
* SPDX-License-Identifier: Apache-2.0
*
* Pure classification helpers for PERIODIC_SYNC_LOST (host-testable).
*
* SYNC_LOST carries only a handle. Handle reuse cannot be detected here, so
* classification uses current vs retiring handles plus the local-terminate
* flag — not a generation counter.
*/
#pragma once
@@ -27,29 +31,10 @@ typedef enum {
typedef struct {
uint16_t current_sync_handle;
uint32_t sync_generation;
uint16_t retiring_sync_handle;
uint32_t retiring_sync_generation;
bool retiring_local_terminate;
} esl_sync_lost_ctx_t;
static inline uint32_t esl_sync_lost_generation_hint(const esl_sync_lost_ctx_t *ctx,
uint16_t evt_sync_handle)
{
if (ctx == NULL) {
return 0;
}
if (evt_sync_handle == ctx->current_sync_handle &&
ctx->current_sync_handle != ESL_SYNC_HANDLE_NONE) {
return ctx->sync_generation;
}
if (evt_sync_handle == ctx->retiring_sync_handle &&
ctx->retiring_sync_handle != ESL_SYNC_HANDLE_NONE) {
return ctx->retiring_sync_generation;
}
return 0;
}
static inline esl_sync_lost_class_t esl_classify_sync_lost(const esl_sync_lost_ctx_t *ctx,
uint16_t evt_sync_handle)
{
@@ -65,9 +50,7 @@ static inline esl_sync_lost_class_t esl_classify_sync_lost(const esl_sync_lost_c
if (evt_sync_handle == ctx->current_sync_handle &&
ctx->current_sync_handle != ESL_SYNC_HANDLE_NONE) {
if (esl_sync_lost_generation_hint(ctx, evt_sync_handle) == ctx->sync_generation) {
return ESL_SYNC_LOST_CURRENT_NATURAL;
}
return ESL_SYNC_LOST_CURRENT_NATURAL;
}
return ESL_SYNC_LOST_STALE;