38struct ln_bd_addr_v_t {
68static_assert(
sizeof(
struct ln_bd_addr_v_t) == 6,
"ln_bd_addr_v_t must match the SDK's ln_bd_addr_t layout");
69static_assert(
alignof(
struct ln_bd_addr_v_t) == 1,
"ln_bd_addr_v_t must stay byte-aligned like the SDK type");
78static constexpr uint32_t CLK_G_BLE = 1u << 0;
79static constexpr int BLE_EVT_ID_SCAN_REPORT = 3;
85static constexpr uint32_t BLE_COEX_PTI_REG_ADDR = 0x400121F8;
86static constexpr uint32_t BLE_COEX_PTI_ENABLE_ALL = 0x003F;
92static constexpr uint8_t BLE_DEFAULT_ADDR[6] = {0x56, 0x34, 0x12, 0x03, 0xFF, 0x00};
96static bool is_unset_addr(
const uint8_t (&addr)[6]) {
97 return std::all_of(std::begin(addr), std::end(addr), [](uint8_t b) {
return b == 0; });
102static constexpr uint8_t GAPM_SCAN_TYPE_OBSERVER = 2;
103static constexpr uint8_t GAPM_DUP_FILT_DIS = 0;
105static constexpr uint8_t GAPM_SCAN_PROP_PHY_1M_BIT = 1 << 0;
106static constexpr uint8_t GAPM_SCAN_PROP_ACTIVE_1M_BIT = 1 << 2;
111static constexpr uint8_t GAPM_REPORT_TYPE_ADV_LEG = 1;
112static constexpr uint8_t GAPM_REPORT_TYPE_SCAN_RSP_LEG = 3;
115static constexpr uint8_t GAPM_REPORT_INFO_SCAN_ADV_BIT = 1u << 5;
123struct le_scan_parameters_t {
126 uint8_t dup_filt_pol;
134static_assert(
sizeof(le_scan_parameters_t) == 8,
"le_scan_parameters_t must match the SDK layout");
135static_assert(offsetof(le_scan_parameters_t, scan_intv) == 4,
"unexpected padding in le_scan_parameters_t");
141struct ble_scan_report_t {
144 uint8_t trans_addr_type;
145 uint8_t trans_addr[6];
146 uint8_t target_addr_type;
147 uint8_t target_addr[6];
156static_assert(
sizeof(ble_scan_report_t) == 20,
"ble_scan_report_t must match the linked BLE stack's layout");
157static_assert(offsetof(ble_scan_report_t,
length) == 18,
"unexpected padding in ble_scan_report_t");
158static_assert(offsetof(ble_scan_report_t, data) == 20,
"advertisement data must follow the header inline");
181static const char *
const TAG =
"ln882h_ble";
195static le_scan_parameters_t s_scan_params[2]{};
196static uint8_t s_scan_params_idx = 0;
198static le_scan_parameters_t *next_scan_params() {
199 s_scan_params_idx ^= 1;
200 return &s_scan_params[s_scan_params_idx];
209static void ble_scan_callback(
void *param) {
210 if (s_ble ==
nullptr || param ==
nullptr)
212 const auto *info =
reinterpret_cast<const ble_scan_report_t *
>(param);
218 const uint8_t report_type = info->info & 0x07;
219 if (report_type != GAPM_REPORT_TYPE_ADV_LEG && report_type != GAPM_REPORT_TYPE_SCAN_RSP_LEG) {
239 memcpy(slot->
mac, info->trans_addr, MAC_ADDRESS_SIZE);
243 slot->
scannable = (info->info & GAPM_REPORT_INFO_SCAN_ADV_BIT) != 0;
244 slot->
data_len = (info->length <=
sizeof(slot->
data)) ?
static_cast<uint8_t
>(info->length)
245 :
static_cast<uint8_t
>(
sizeof(slot->
data));
253 if (slot ==
nullptr) {
290 *
reinterpret_cast<volatile uint32_t *
>(BLE_COEX_PTI_REG_ADDR) = BLE_COEX_PTI_ENABLE_ALL;
311 le_scan_parameters_t *probe = next_scan_params();
312 probe->type = GAPM_SCAN_TYPE_OBSERVER;
313 probe->prop = GAPM_SCAN_PROP_PHY_1M_BIT;
314 probe->dup_filt_pol = GAPM_DUP_FILT_DIS;
315 probe->scan_intv = 160;
327 ESP_LOGD(TAG,
"BLE stack initialised");
335 uint16_t dropped = this->
report_queue_.get_and_reset_dropped_count();
337 ESP_LOGW(TAG,
"Dropped %u scan reports (queue full or out of memory for a report slot)", dropped);
341 if (report !=
nullptr) {
344#ifdef LN882H_BLE_SCAN_LISTENER_COUNT
346 listener->on_scan_report(*report);
365 ESP_LOGW(TAG,
"Rejected %u scan reports before any was delivered - unexpected report encoding?",
369 ESP_LOGV(TAG,
"Rejected %u non-legacy scan reports", rejected);
378 " MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n"
395 ln_bd_addr_v_t bt_addr{};
396 bool have_unique_addr =
false;
403 memcmp(bt_addr.addr, BLE_DEFAULT_ADDR,
sizeof(bt_addr.addr)) != 0 && !is_unset_addr(bt_addr.addr);
407 ESP_LOGW(TAG,
"BLE address KV unavailable; deriving address from WiFi MAC");
409 if (!have_unique_addr) {
410 uint8_t wifi_mac[MAC_ADDRESS_SIZE] = {0};
415 for (
int i = 0; i < 6; i++)
416 bt_addr.addr[i] = wifi_mac[5 - i];
417 bt_addr.addr[0] =
static_cast<uint8_t
>(bt_addr.addr[0] + 1);
419 ESP_LOGW(TAG,
"Failed to persist derived BLE address (err %d); will re-derive next boot", err);
421 ESP_LOGD(TAG,
"MAC derived (WiFi+1) and stored");
424 memcpy(this->
ble_mac_, bt_addr.addr, MAC_ADDRESS_SIZE);
444 le_scan_parameters_t *p = next_scan_params();
445 p->dup_filt_pol = GAPM_DUP_FILT_DIS;
446 p->type = GAPM_SCAN_TYPE_OBSERVER;
447 p->scan_intv = interval;
451 p->prop = GAPM_SCAN_PROP_PHY_1M_BIT;
453 p->prop |= GAPM_SCAN_PROP_ACTIVE_1M_BIT;
void count_rejected_report()
Internal, rw-task context: count a report rejected by the legacy-only filter, so a wrong assumption a...
esphome::EventPool< BLEScanReport, MAX_SCAN_REPORT_QUEUE_SIZE - 1 > report_pool_
float get_setup_priority() const override
bool reject_diagnosis_done_
void get_mac_lsb_first(uint8_t out[6]) const
Controller BLE address in the SDK's ln_bd_addr_t order: least-significant octet first (the BLE/HCI co...
esphome::LockFreeQueue< BLEScanReport, MAX_SCAN_REPORT_QUEUE_SIZE > report_queue_
uint32_t rejected_before_delivery_
BLEScanReport * allocate_scan_report()
Internal, SDK rw-task event-callback context: allocate a pool slot for a scan report.
std::atomic< uint16_t > rejected_reports_
StaticVector< BLEScanListener *, LN882H_BLE_SCAN_LISTENER_COUNT > scan_listeners_
uint8_t ble_mac_[MAC_ADDRESS_SIZE]
void dump_config() override
void scan_start(uint16_t interval, uint16_t window, bool active)
Start the controller scan.
void push_scan_report(BLEScanReport *report)
Internal: hand a filled slot to the main-task queue (cannot fail — the pool is sized to the queue cap...
void enable()
Bring up the LN882H BLE stack (one-time; the SDK has no teardown path).
void scan_stop()
Stop the controller scan (no-op when not scanning).
struct @66::@67 __attribute__
Wake the main loop task from an ISR. ISR-safe.
void ln_rw_app_task_init(void)
void ln_ble_smp_init(void)
int ln_kv_ble_addr_store(struct ln_bd_addr_v_t addr)
void ln_ble_scan_mgr_init(void)
void ln_ble_scan_start(void *scan_param)
void ln_ble_conn_mgr_init(void)
void ln_kv_ble_app_init(void)
void ln_ble_evt_mgr_init(void)
void ln_ble_evt_mgr_reg_evt(int evt_id, ble_evt_cb_t cb)
void ln_ble_scan_stop(void)
void soc_module_clk_gate_enable(uint32_t clk)
const char va_start(args, format)
void rw_init(uint8_t mac[6])
void ln_ble_scan_actv_creat(void)
void(*)(void *param) ble_evt_cb_t
void ln_gap_app_init(void)
struct ln_bd_addr_v_t * ln_kv_ble_pub_addr_get(void)
void ln_gatt_app_init(void)
constexpr float AFTER_WIFI
For components that should be initialized after WiFi is connected.
void get_mac_address_raw(uint8_t *mac)
Get the device MAC address as raw bytes, written into the provided byte array (6 bytes).
void HOT delay(uint32_t ms)
One scan report from the controller, decoded from the SDK's rw-task event (RSSI already sign-correcte...
uint8_t mac[MAC_ADDRESS_SIZE]