| 646 | // ---- GAP callback for HID host central connection ---- |
| 647 | |
| 648 | static int hidHostGapCb(struct ble_gap_event* event, void* /*arg*/) { |
| 649 | if (!hid_host_ctx) return 0; |
| 650 | auto& ctx = *hid_host_ctx; |
| 651 | |
| 652 | switch (event->type) { |
| 653 | case BLE_GAP_EVENT_CONNECT: |
| 654 | if (event->connect.status == 0) { |
| 655 | ctx.connHandle = event->connect.conn_handle; |
| 656 | LOGGER.info("Connected (handle={})", ctx.connHandle); |
| 657 | int rc = ble_gattc_disc_all_svcs(ctx.connHandle, hidHostSvcDiscCb, nullptr); |
| 658 | if (rc != 0) { |
| 659 | LOGGER.warn("disc_all_svcs failed rc={}", rc); |
| 660 | ble_gap_terminate(ctx.connHandle, BLE_ERR_REM_USER_CONN_TERM); |
| 661 | } |
| 662 | } else { |
| 663 | LOGGER.warn("Connect failed status={}", event->connect.status); |
| 664 | hid_host_ctx.reset(); |
| 665 | if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) { |
| 666 | bluetooth_set_hid_host_active(dev, false); |
| 667 | struct BtEvent e = {}; |
| 668 | e.type = BT_EVENT_PROFILE_STATE_CHANGED; |
| 669 | e.profile_state.state = BT_PROFILE_STATE_IDLE; |
| 670 | e.profile_state.profile = BT_PROFILE_HID_HOST; |
| 671 | bluetooth_fire_event(dev, e); |
| 672 | } |
| 673 | } |
| 674 | break; |
| 675 | |
| 676 | case BLE_GAP_EVENT_DISCONNECT: { |
| 677 | LOGGER.info("Disconnected reason={}", event->disconnect.reason); |
| 678 | lv_indev_t* saved_kb = hid_host_ctx ? hid_host_ctx->kbIndev : nullptr; |
| 679 | lv_indev_t* saved_mouse = hid_host_ctx ? hid_host_ctx->mouseIndev : nullptr; |
| 680 | lv_obj_t* saved_cursor = hid_host_ctx ? hid_host_ctx->mouseCursor : nullptr; |
| 681 | QueueHandle_t saved_queue = hid_host_key_queue; |
| 682 | hid_host_ctx.reset(); |
| 683 | hid_host_key_queue = nullptr; |
| 684 | std::memset(hid_host_prev_keys, 0, sizeof(hid_host_prev_keys)); |
| 685 | hid_host_mouse_x.store(0); |
| 686 | hid_host_mouse_y.store(0); |
| 687 | hid_host_mouse_btn.store(false); |
| 688 | hid_host_mouse_active.store(false); |
| 689 | |
| 690 | if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) { |
| 691 | bluetooth_set_hid_host_active(dev, false); |
| 692 | struct BtEvent e = {}; |
| 693 | e.type = BT_EVENT_PROFILE_STATE_CHANGED; |
| 694 | e.profile_state.state = BT_PROFILE_STATE_IDLE; |
| 695 | e.profile_state.profile = BT_PROFILE_HID_HOST; |
| 696 | bluetooth_fire_event(dev, e); |
| 697 | } |
| 698 | |
| 699 | getMainDispatcher().dispatch([saved_kb, saved_mouse, saved_cursor, saved_queue] { |
| 700 | if (!tt::lvgl::lock(1000)) { |
| 701 | LOGGER.warn("Failed to acquire LVGL lock for indev cleanup"); |
| 702 | if (saved_queue) vQueueDelete(saved_queue); |
| 703 | return; |
| 704 | } |
| 705 | if (saved_kb) { |
nothing calls this directly
no test coverage detected