mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
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:
@@ -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
|
||||
|
||||
@@ -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 (0x00–0xFE) */
|
||||
uint8_t group_id; /*!< Group_ID to assign (0x00–0x7F) */
|
||||
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 1–128;
|
||||
* 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);
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user