bluekitchen / btstack

Dual-mode Bluetooth stack, with small memory footprint.
http://bluekitchen-gmbh.com
Other
1.74k stars 618 forks source link

HOG keyboard example is always reconnecting in MAC #575

Closed emanuellopes closed 8 months ago

emanuellopes commented 8 months ago

Describe the bug I'm using the example hog_keyboard in Android works as expected but in Mac OS the ble device is always reconnecting.

To allow me debugging the code I separated two handlers sm and packet.

static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    UNUSED(channel);
    UNUSED(size);

    if (packet_type != HCI_EVENT_PACKET)
        return;

    switch (hci_event_packet_get_type(packet))
    {
    case HCI_EVENT_DISCONNECTION_COMPLETE:
        con_handle = HCI_CON_HANDLE_INVALID;
        app_connected = false;
        printf("Disconnected\n");
        btstack_run_loop_remove_timer(&typing_timer);
        break;
    case HCI_EVENT_HIDS_META:
        switch (hci_event_hids_meta_get_subevent_code(packet))
        {
        case HIDS_SUBEVENT_INPUT_REPORT_ENABLE:
            con_handle = hids_subevent_input_report_enable_get_con_handle(packet);
            printf("Report Characteristic Subscribed %u\n", hids_subevent_input_report_enable_get_enable(packet));
            if (app_connected)
            {
                setup_timer();
                reset_timer();
            }

            // request connection param update via L2CAP following Apple Bluetooth Design Guidelines
            gap_request_connection_parameter_update(con_handle, 12, 12, 4, 100); // 15 ms, 4, 1s

            // directly update connection params via HCI following Apple Bluetooth Design Guidelines
            gap_update_connection_parameters(con_handle, 12, 12, 4, 100); // 60-75 ms, 4, 1s
            break;
        case HIDS_SUBEVENT_BOOT_KEYBOARD_INPUT_REPORT_ENABLE:
            con_handle = hids_subevent_boot_keyboard_input_report_enable_get_con_handle(packet);
            printf("Boot Keyboard Characteristic Subscribed %u\n", hids_subevent_boot_keyboard_input_report_enable_get_enable(packet));
            break;
        case HIDS_SUBEVENT_PROTOCOL_MODE:
            protocol_mode = hids_subevent_protocol_mode_get_protocol_mode(packet);
            printf("Protocol Mode: %s mode\n", hids_subevent_protocol_mode_get_protocol_mode(packet) ? "Report" : "Boot");
            break;
        case HIDS_SUBEVENT_CAN_SEND_NOW:
            printf("hid subevent can send now!");
            setup_timer();
            reset_timer();
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }
}

static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    UNUSED(channel);
    UNUSED(size);

    if (packet_type != HCI_EVENT_PACKET)
        return;

    switch (hci_event_packet_get_type(packet))
    {
    case SM_EVENT_REENCRYPTION_STARTED:
        printf("SM_EVENT_REENCRYPTION_STARTED\n");
        break;
    case SM_EVENT_REENCRYPTION_COMPLETE:
        printf("SM_EVENT_REENCRYPTION_COMPLETE\n");
        break;
    case SM_EVENT_IDENTITY_RESOLVING_STARTED:
        printf("SM_EVENT_IDENTITY_RESOLVING_STARTED!\n");
        break;
    case SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED:
        printf("SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED!\n");
        break;
    case SM_EVENT_IDENTITY_RESOLVING_FAILED:
        printf("SM_EVENT_IDENTITY_RESOLVING_FAILED!\n");
        break;
    case SM_EVENT_PAIRING_STARTED:
        printf("paring started!\n");
        break;
    case SM_EVENT_PAIRING_COMPLETE:

        switch (sm_event_pairing_complete_get_status(packet))
        {
        case ERROR_CODE_SUCCESS:
            printf("Pairing complete, success\n");
            app_connected = true;
            break;
        case ERROR_CODE_CONNECTION_TIMEOUT:
            printf("Pairing failed, timeout\n");
            break;
        case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION:
            printf("Pairing failed, disconnected\n");
            break;
        case ERROR_CODE_AUTHENTICATION_FAILURE:
            printf("Pairing failed, reason = %u\n", sm_event_pairing_complete_get_reason(packet));
            break;
        default:
            break;
        }
        break;
    case SM_EVENT_JUST_WORKS_REQUEST:
        printf("Just Works requested\n");
        sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
        break;
    case SM_EVENT_NUMERIC_COMPARISON_REQUEST:
        printf("Confirming numeric comparison: %" PRIu32 "\n", sm_event_numeric_comparison_request_get_passkey(packet));
        sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet));
        break;
    case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
        printf("Display Passkey: %" PRIu32 "\n", sm_event_passkey_display_number_get_passkey(packet));
        break;
    default:
        break;
    }
}

To Reproduce

Steps to reproduce the behavior: Compile the code and try disconnect mac from BLE device. The mac will reconnect to the device. (This not happens in Android phone)

Expected behavior The beahaviour should be equal on every device.

Debugging code

For example the first connection I receive:

SM_EVENT_IDENTITY_RESOLVING_STARTED!
SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED!
SM_EVENT_REENCRYPTION_STARTED
SM_EVENT_REENCRYPTION_COMPLETE
paring started!
Just Works requested
Pairing complete, success
Report Characteristic Subscribed 1
Start typing..
Timer Handler
Timer Handler
Timer Handler

When I disconnect the device I receive this:

Disconnected
SM_EVENT_IDENTITY_RESOLVING_STARTED!
SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED!
SM_EVENT_REENCRYPTION_STARTED
SM_EVENT_REENCRYPTION_COMPLETE
Report Characteristic Subscribed 1
Report Characteristic Subscribed 1

In android the HIDS_SUBEVENT_BOOT_KEYBOARD_INPUT_REPORT_ENABLE is triggered.

This is related with services?

How I can avoid the reconnection in MAC?

mringwal commented 8 months ago

In HOGS, the Central device, here macOS or Android, connects to the keyboard. If you disconnect the keyboard, the remote generally tries to reconnect. Feel free to file a bug report with Android as that's the least expected.

If you don't want your keyboard to be connected, you can disable advertisements when you disconnect (which is basically the same as shutting it off...)