#include "ap2_probe.h" #include "ap2_hub.h" #include "esphome/core/log.h" namespace esphome { namespace ap2_hub { static const char *const TAG = "ap2_hub.probe"; void AP2ProbeClient::start_probe(uint64_t mac, esp_ble_addr_type_t type) { this->active_ = true; this->confirmed_ = false; this->fw_.clear(); this->rx_handle_ = this->tx_handle_ = this->ccc_handle_ = 0; this->set_address(mac); this->set_remote_addr_type(type); this->connect(); } void AP2ProbeClient::abort_probe() { if (!this->active_) return; this->disconnect(); // -> ClientState::IDLE -> set_state() -> hub->probe_finished() } void AP2ProbeClient::set_state(espbt::ClientState st) { BLEClientBase::set_state(st); // IDLE while a probe is active means the attempt is over (confirmed, no-NUS, // failed connect, or aborted) and the client is free again. if (st == espbt::ClientState::IDLE && this->active_) { this->active_ = false; if (this->hub_ != nullptr) this->hub_->probe_finished(this->get_address(), this->confirmed_, this->fw_); } } bool AP2ProbeClient::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) { if (!BLEClientBase::gattc_event_handler(event, gattc_if, param)) return false; if (!this->active_) return true; switch (event) { case ESP_GATTC_SEARCH_CMPL_EVT: { auto *rx = this->get_characteristic(nus_svc(), nus_rx()); auto *tx = this->get_characteristic(nus_svc(), nus_tx()); if (rx == nullptr || tx == nullptr) { ESP_LOGD(TAG, "%s: no Nordic UART — not an AP2", this->address_str()); this->disconnect(); break; } this->rx_handle_ = rx->handle; this->tx_handle_ = tx->handle; auto *ccc = this->get_config_descriptor(this->tx_handle_); this->ccc_handle_ = (ccc != nullptr) ? ccc->handle : 0; esp_ble_gattc_register_for_notify(gattc_if, this->get_remote_bda(), this->tx_handle_); break; } case ESP_GATTC_REG_FOR_NOTIFY_EVT: { if (this->ccc_handle_ != 0) { uint16_t notify_en = 0x0001; esp_ble_gattc_write_char_descr(gattc_if, this->get_conn_id(), this->ccc_handle_, sizeof(notify_en), (uint8_t *) ¬ify_en, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE); } uint8_t f[64]; uint8_t n = ap2_build_frame("M99", 0, f); esp_ble_gattc_write_char((esp_gatt_if_t) this->get_gattc_if(), this->get_conn_id(), this->rx_handle_, n, f, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE); break; } case ESP_GATTC_NOTIFY_EVT: { if (param->notify.handle == this->tx_handle_) { std::string fw = ap2_parse_m99_fw(ap2_ascii(param->notify.value, param->notify.value_len)); if (!fw.empty()) { this->confirmed_ = true; this->fw_ = fw; ESP_LOGD(TAG, "%s: M99 confirmed V%s", this->address_str(), fw.c_str()); this->disconnect(); } } break; } default: break; } return true; } } // namespace ap2_hub } // namespace esphome