How to connected severals smartphone HID Keyboard

Good Morning,

I started with example ble_app_hids_keyboard for nrf52840 with nRF5_SDK_17.1.0 and I added uart_init() function to use UARTE0 and I modified uart_event_handle() for received a message "UART_OK" when I received on the rx pin an character, this works quite. My issue I want to connect 2 smartphones with HID Keyboard. 

When I connect me to smarphone 1 the example HID keyboard is OK. But when I disconnect to smartphone "1" and I want to connect to smartphone "2" the nrf52840 is not discoveable and I can't to connect to smartphone "2". The nrf52840 indicates BSP_INDICATE_ADVERTISING_WHITELIST (LED 1 is blinking fast for period 1 sec). For our product in development  with nrf52840 I can to use only UART signals RX(pin 8) / TX (pin 6), I don't have signals buttons 1 and buttons 2 as example:

During advertising or scanning:

  • Button 1: Sleep (if not also in a connection)
  • Button 2 long push: Turn off whitelist.

During sleep:

  • Button 1: Wake up.
  • Button 2: Wake up and delete bond information.

During connection:

  • Button 1 long push: Disconnect.
  • Push and release on all buttons: Application-specific.

the only solution found is after disconnecting from the phone 1 I must during  advertising "LED 1 is blinking fast for period 1 sec" push Button 1 for sleep and during sleep push Button 2 for delete bond information ! I would like to know to make to connect 2 smartphones or other host peripheral (tablet, computer..) witthout clear bond information ?

Can we have a list of multiple hosts in nrf52840 and each host can to connect to nrf52840 ?

To make simple smartphone "1" connected HID Keyboard and I disconnect me and I connect me to the next smartphone in HID Keyboard.

Thank you help 

Alexandre

/**@brief   Function for handling app_uart events.
 *
 * @details This function will receive a single character from the app_uart module and append it to
 *          a string. 
 */
/**@snippet [Handling the data received over UART] */
void uart_event_handle(app_uart_evt_t * p_event)					//$at_06_04_22
{
	uint8_t message[UARTE_MAX_DATA_LEN] = "UART OK";
	uint8_t i;
	
    static uint8_t data_array[UARTE_MAX_DATA_LEN];
    static uint8_t index = 0;
    uint32_t       err_code;
	
    switch (p_event->evt_type)
    {
        case APP_UART_DATA_READY:
            UNUSED_VARIABLE(app_uart_get(&data_array[index]));
			for (i = 0; i < strlen((const char*)message); i++)
			{
				app_uart_put(message[i]);
			}
            break;

        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}
/**@snippet [Handling the data received over UART] */

/**@brief  Function for initializing the UART module.
 */
/**@snippet [UART Initialization] */
static void uart_init(void)
{
    uint32_t                     err_code;
    app_uart_comm_params_t const comm_params =
    {
        .rx_pin_no    = RX_PIN_NUMBER,
        .tx_pin_no    = TX_PIN_NUMBER,
        .rts_pin_no   = RTS_PIN_NUMBER,
        .cts_pin_no   = CTS_PIN_NUMBER,
        .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
        .use_parity   = false,
#if defined (UART_PRESENT)
        .baud_rate    = NRF_UART_BAUDRATE_115200
#else
        .baud_rate    = NRF_UARTE_BAUDRATE_115200
#endif
    };

    APP_UART_FIFO_INIT(&comm_params,
                       UART_RX_BUF_SIZE,
                       UART_TX_BUF_SIZE,
                       uart_event_handle,
                       APP_IRQ_PRIORITY_LOWEST,
                       err_code);
    APP_ERROR_CHECK(err_code);
}
/**@snippet [UART Initialization] */

/**@brief Function for application main entry.
 */
int main(void)
{
    bool erase_bonds;

    // Initialize.
	uart_init();
    log_init();
    timers_init();
    buttons_leds_init(&erase_bonds);
    power_management_init();
    ble_stack_init();
    scheduler_init();
    gap_params_init();
    gatt_init();
    advertising_init();
    services_init();
    sensor_simulator_init();
    conn_params_init();
    buffer_init();
    peer_manager_init();

    // Start execution.
    NRF_LOG_INFO("HID Keyboard example started.");
    timers_start();
    advertising_start(erase_bonds);

    // Enter main loop.
    for (;;)
    {		
        idle_state_handle();
    }
}

  • Hi,

    I took the HID Keyboard example again and activated the nrf LOG. With the first phone I connect well and the HID application works well "hello" visible on an editor. But I can't connect the second phone. I have read several posts and I did not understand the following remark:

    You could either try to scan without whitelist 

    POST: 

    nRF51822 as hid keyboard: how to pair/bond to multiple devices (smartphones) - Nordic Q&A - Nordic DevZone - Nordic DevZone (nordicsemi.com)

    When you try to establish a connection with the second device, advertising with a whitelist is active and this prevents the connection to the second phone. You could either try to scan without whitelist and add second device to the whitelist when it is connected, or you could consider turning off the whitelist completely. 

    1) How to make "scan without whitelist" ? 

    below my log connection and disconnection with first smartphone and when I'm to "slow advertising" my second smartphone don't saw the peripheral Nordic_Keyboard,  I would like to know how to connect with my second phone without "erase bonds!"  with push button 2 ?

    <info> app_timer: RTC: initialized.
    
    <info> app: HID Keyboard example started.
    
    <info> app: 	m_whitelist_peer_cnt 1, MAX_PEERS_WLIST 8
    
    <info> app: Fast advertising.
    
    <info> app: Slow advertising.
    
    <info> app: Connected
    
    <info> peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 0, procedure: Bonding
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Bonding data, action: Update
    
    <info> app: New Bond, add the peer to the whitelist if possible
    
    <info> app: 	m_whitelist_peer_cnt 2, MAX_PEERS_WLIST 8
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Peer rank, action: Update
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Local database, action: Update
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Central address resolution, action: Update
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Local database, action: Update
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Local database, action: Update
    
    <info> app: High Duty Directed advertising.
    
    <info> app: Disconnected
    
    <info> app: Fast advertising with whitelist.
    
    <info> app: Slow advertising with whitelist.
    
    <info> app_timer: RTC: initialized.
    
    <info> app: HID Keyboard example started.
    
    <info> app: Erase bonds!
    
    <error> peer_manager_handler: Peer deleted successfully: peer_id: 0
    
    <info> peer_manager_handler: All peers deleted.
    
    <info> app: 	m_whitelist_peer_cnt 1, MAX_PEERS_WLIST 8
    
    <info> app: Fast advertising.
    
    <info> app: Connected
    
    <info> peer_manager_handler: Connection secured: role: Peripheral, conn_handle: 0, procedure: Bonding
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Bonding data, action: Update
    
    <info> app: New Bond, add the peer to the whitelist if possible
    
    <info> app: 	m_whitelist_peer_cnt 2, MAX_PEERS_WLIST 8
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Peer rank, action: Update
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Local database, action: Update
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Central address resolution, action: Update
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Local database, action: Update
    
    <info> peer_manager_handler: Peer data updated in flash: peer_id: 0, data_id: Local database, action: Update
    
    

    Thank you very much for help

    Alexandre

  • Please find this devzone case that explain how a peripheral device can "switch" between central devices by manipulating the gap address. By changing the gap address the peripheral will appear as a new/different device to the central, so you can for instance switch back and forth between gap addresses to control which central you want to connect to:
    https://devzone.nordicsemi.com/f/nordic-q-a/37369/switching-keyboard-mouse-between-3-paired-devices 

    Also see (this one is likely most useful for you, since it contain an example to switch gap address):
    https://devzone.nordicsemi.com/f/nordic-q-a/57881/store-custom-application-data-using-peer-manager 

    You must call ble_advertising_restart_without_whitelist() to advertise without whitelist. OR you configure advertisment in the advertising_init(), e.g. 

    init.config.ble_adv_whitelist_enabled          = false;

    Best regards,
    Kenneth

  • Good Morning Kenneth,

    thanks for information, I 'm going to see  accurately examples . 

    On the same example HID Keyboard, my application is always power on. I have so put it comment sleep_mode() function into static void on_adv_evt(ble_adv_evt_t ble_adv_evt),  I have the same problem as this post: 

    "LED 1 blinks indicating that it is advertising, and for a few minutes it is visible in nRF Connect. But, after approximately 5 minutes the device is no longer visible. However, the LED continues to blink as though the device is still advertising."

    this is the POST: Completely disabling sleep mode - Nordic Q&A - Nordic DevZone - Nordic DevZone (nordicsemi.com)

    I looked at the following function "advertising_init" but nothing tells me how to set an infinite time with a value of 0 !

    /**@brief Function for initializing the Advertising functionality.
     */
    static void advertising_init(void)
    {
        uint32_t               err_code;
        uint8_t                adv_flags;
        ble_advertising_init_t init;
    
        memset(&init, 0, sizeof(init));
    
        adv_flags                            = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
        init.advdata.name_type               = BLE_ADVDATA_FULL_NAME;
        init.advdata.include_appearance      = true;
        init.advdata.flags                   = adv_flags;
        init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
        init.advdata.uuids_complete.p_uuids  = m_adv_uuids;
    
        init.config.ble_adv_whitelist_enabled          = true;
        init.config.ble_adv_directed_high_duty_enabled = true;
        init.config.ble_adv_directed_enabled           = false;
        init.config.ble_adv_directed_interval          = 0;
        init.config.ble_adv_directed_timeout           = 0;
        init.config.ble_adv_fast_enabled               = true;
        init.config.ble_adv_fast_interval              = APP_ADV_FAST_INTERVAL;
        init.config.ble_adv_fast_timeout               = APP_ADV_FAST_DURATION;
        init.config.ble_adv_slow_enabled               = true;
        init.config.ble_adv_slow_interval              = APP_ADV_SLOW_INTERVAL;
        init.config.ble_adv_slow_timeout               = APP_ADV_SLOW_DURATION;
    
        init.evt_handler   = on_adv_evt;
        init.error_handler = ble_advertising_error_handler;
    
        err_code = ble_advertising_init(&m_advertising, &init);
        APP_ERROR_CHECK(err_code);
    
        ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
    }
    

    For information, I use nRF SDK 17.1.0 and ble_app_hids_keyboard_pca100056_s140

    Thanks 

    Alexandre

  • The ble_advertising_init() will cycle through advertising as configured by the parameters supplied. The advertisement will throw a callback in on_adv_evt() each time it change mode, and finally when all modes have elapsed it throw the BLE_ADV_EVT_IDLE event in on_adv_evt(). In this case you can either go to sleep or start advertisment again by for instance calling ble_advertising_start() or ble_advertising_restart_without_whitelist().

    Kenneth

Related