Cannot connect to nRF when in direct advertisement mode

Hello, I'm trying to manage connecting to my board (nRF52840-DK) which direct advertise (low prio) with peer address set to MAC address of my PC running Linux with bluez 5.62-1. Unfortunately I cannot connect to the board, no matter what. I develop the board with Zephyr RTOS. This is the code responsible for setting up advertisement:

static void bt_ready(void)
{
  int err;
  bt_addr_le_t dir_addr;

  const char *address = "D8:8F:76:5B:57:7E";
  const char *type = "public";
  if ((err = bt_addr_le_from_str(address, type, &dir_addr))) {
    printk("Bt_addr_le_from_str error: %d\n", err);
  }

  err = bt_le_adv_start(BT_LE_ADV_CONN_DIR_LOW_DUTY(&dir_addr), ad, ARRAY_SIZE(ad), NULL, 0);
  if (err) {
    printk("Advertising failed to start (err %d)\n", err);
    return;
  }

  printk("Advertising successfully started\n");
}

If i set the advertisement mode to BT_LE_ADV_CONN_NAME, then there is no problem - the device is scannable and connectable.

My question is - can someone post any code or describe any method that will allow me to connect my PC to the board?

Parents
  • Hi

    Raspberry Pi 4 and BlueZ v5.62-1 should support directed advertising from what I can tell, but please make sure that your scanning device is doing active scanning. I'm not too familiar with the BlueZ stack, so you'll need to find out exactly how, but I assume you set this in the scan parameters.

    Best regards,

    Simon

  • Ok, I managed to connect to the board using bettercap tool. Now, what's happening is that after my PC disconnects from the board I cannot start direct advertisement again. What I tried to do was to start it in the disconnection callback:

    static void bt_start_adv_direct(const char *address, const char *type) {
      printk("Begin direct advertising to %s (%s).\n", address, type);
      int err;
    
      bt_addr_le_t dir_addr;
      if ((err = bt_addr_le_from_str(address, type, &dir_addr))) {
        printk("Bt_addr_le_from_str error: %d\n", err);
      }
    
      err = bt_le_adv_start(BT_LE_ADV_CONN_DIR_LOW_DUTY(&dir_addr), ad, ARRAY_SIZE(ad), NULL, 0);
      if (err) {
        printk("Advertising failed to start (err %d)\n", err);
        return;
      }
    
      printk("Advertising successfully started, directed to: %s\n", address);
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason) {
        printk("Disconnected (reason 0x%02x)\n", reason);
        bt_start_adv_direct(address, type); // global arrays
    }  

    Logs from nRF:

    *** Booting Zephyr OS build v2.6.1-rc1-21-g42d7e712063b  ***
    Set up button at GPIO_0 pin 11
    Set up LED at GPIO_0 pin 13
    Address: DB:94:18:97:FE:0D (random)
    Bluetooth initialized
    Begin direct advertising to 18:1D:EA:9C:EF:E5 (public).
    Advertising successfully started, directed to: 18:1D:EA:9C:EF:E5
    Connected
    Disconnected (reason 0x13)
    Begin direct advertising to 18:1D:EA:9C:EF:E5 (public).
    Advertising failed to start (err -22)

    As you can see, advertisement sets up when I call the `bt_start_adv_direct` for the first time in my main function, but it fails when called from the `disconnected` callback. I don't understand why the error code is 22 (afaik it's "Invalid argument" error). What should I do to restart advertisement after disconnection? 

  • I found what was the issue. The  `bt_le_adv_start` function calls at some point `bt_conn_exists_le`, which looks like this:

    bool bt_conn_exists_le(uint8_t id, const bt_addr_le_t *peer)
    {
    	struct bt_conn *conn = bt_conn_lookup_addr_le(id, peer);
    
    	if (conn) {
    		/* Connection object already exists.
    		 * If the connection state is not "disconnected",then the
    		 * connection was created but has not yet been disconnected.
    		 * If the connection state is "disconnected" then the connection
    		 * still has valid references. The last reference of the stack
    		 * is released after the disconnected callback.
    		 */
    		BT_WARN("Found valid connection in %s state",
    			state2str(conn->state));
    		bt_conn_unref(conn);
    		return true;
    	}
    
    	return false;
    }

    So, you cannot start advertisement in the disconnected callback.

Reply
  • I found what was the issue. The  `bt_le_adv_start` function calls at some point `bt_conn_exists_le`, which looks like this:

    bool bt_conn_exists_le(uint8_t id, const bt_addr_le_t *peer)
    {
    	struct bt_conn *conn = bt_conn_lookup_addr_le(id, peer);
    
    	if (conn) {
    		/* Connection object already exists.
    		 * If the connection state is not "disconnected",then the
    		 * connection was created but has not yet been disconnected.
    		 * If the connection state is "disconnected" then the connection
    		 * still has valid references. The last reference of the stack
    		 * is released after the disconnected callback.
    		 */
    		BT_WARN("Found valid connection in %s state",
    			state2str(conn->state));
    		bt_conn_unref(conn);
    		return true;
    	}
    
    	return false;
    }

    So, you cannot start advertisement in the disconnected callback.

Children
No Data
Related