This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Nrf Connect SDK peripheral always reads RSSI as 127 upon a connection

Hello, I'm using an nRF5340 board with nRF Connect SDK as a BLE peripheral device, and I'm trying to get RSSI value when another device connects to it.

So I'm trying to read it as in the Zephyr hci_pwr_ctrl example. Specifically, I'm calling this function in the connection handler:

bt_hci_cmd_send_sync(BT_HCI_OP_READ_RSSI, requestBuffer, &responseBuffer);

Note that I'm using SoftDevice BLE stack on the CPU_NET, and my code runs on the CPU_APP.
And I have created a hci_rpmsg.conf in the child_image folder, which has the following lines:

CONFIG_BT_LL_SOFTDEVICE_DEFAULT=y
CONFIG_BT_LL_SOFTDEVICE_VS_INCLUDE=y
CONFIG_BT_LL_SOFTDEVICE=y

CONFIG_BT_EXT_ADV=y
CONFIG_BT_CTLR=y
CONFIG_BT_CTLR_ADV_EXT=y
CONFIG_BT_EXT_ADV_MAX_ADV_SET=2
CONFIG_BT_CTLR_PHY_CODED=y
CONFIG_BT_CTLR_ADVANCED_FEATURES=y
CONFIG_BT_CTLR_CONN_RSSI=y
CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y

And I also have flashed merged_CPUNET.hex to the board, so that CPU_NET runs with these settings.

Now, the function to read RSSI runs without any errors, it returns 0 as error code, and it always gives the value of RSSI equal to 127, irrelevant of the distance and signal strength shown in NRF Connect. 

So, this code:

auto* commandResponse = reinterpret_cast<bt_hci_rp_read_rssi*>(responseBuffer->data);
printk("Rssi %d, status %u, handle %u\n", commandResponse->rssi, commandResponse->status, commandResponse->handle);

Produces the following log upon connection:

00> Req rssi for handle 14
00> 
00> Rssi 127, status 0, handle 14

What can be done to read RSSI properly?

Parents
  • Hi,

    Have you considered doing as demonstrated by the hci_pwr_ctrl sample (see how read_conn_rssi() is implemented in zephyr/samples/bluetooth/hci_pwr_ctrl/src/main.c)?

    Ignoring the above and looking at what you have attempted to do, you configurations look good. However, while I must admit I am rusty in modern C++,  your way of obtaining the RSSI before you print it looks odd to me. Have you tried simply calling bt_hci_rp_read_rssi() the old fashioned way, and the accessing rssi in the returned struct(sdc_hci_cmd_sp_read_rssi_return_t)?

  • To me it seems my attempt to read RSSI is the same as in the hci_pwr_ctrl example, the only difference is that casting from void pointers is needed in C++.
    As in the example it is like this:

    err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_RSSI, buf, &rsp);
    if (err) {
    	uint8_t reason = rsp ?
    		((struct bt_hci_rp_read_rssi *)rsp->data)->status : 0;
    	printk("Read RSSI err: %d reason 0x%02x\n", err, reason);
    	return;
    }
    
    rp = (void *)rsp->data;
    *rssi = rp->rssi;

    I'm not sure I understand you, how can I call bt_hci_rp_read_rssi as it is a struct not a function? And I'm reading its fields after it's returned in the response buffer. Maybe in the latest Zephyr update it was changed? I'm using Zephyr 1.6.1, by the way.

    struct bt_hci_rp_read_rssi {
    	uint8_t  status;
    	uint16_t handle;
    	int8_t   rssi;
    } __packed;

    And what is sdc_hci_cmd_sp_read_rssi_return_t? Can you please provide a code example for better understanding?

  • CodeLoader said:
    I'm not sure I understand you, how can I call bt_hci_rp_read_rssi as it is a struct not a function?

    hah, good point. I must admit I was very quick when looking at this earlier Slight smile

    CodeLoader said:
    Maybe in the latest Zephyr update it was changed? I'm using Zephyr 1.6.1, by the way.

    I assume you are referring to nRF Connect SDK 1.6.1 (as Zephyr 1.6.1 is really old)? If so, then the approach demonstrated in the hci_pwr_ctrl should work, and I just tested on a nRF5340 DK, where I get the RSSI reading without any issues.

    CodeLoader said:
    And what is sdc_hci_cmd_sp_read_rssi_return_t? Can you please provide a code example for better understanding?

    That is the type of the struct holding the rssi in the SoftDevice controller API. The only code example you should refer to is the hci_pwr_ctrl which does this. If. you are using 1.6.1, then that would be this:

    static void read_conn_rssi(uint16_t handle, int8_t *rssi)
    {
    	struct net_buf *buf, *rsp = NULL;
    	struct bt_hci_cp_read_rssi *cp;
    	struct bt_hci_rp_read_rssi *rp;
    
    	int err;
    
    	buf = bt_hci_cmd_create(BT_HCI_OP_READ_RSSI, sizeof(*cp));
    	if (!buf) {
    		printk("Unable to allocate command buffer\n");
    		return;
    	}
    
    	cp = net_buf_add(buf, sizeof(*cp));
    	cp->handle = sys_cpu_to_le16(handle);
    
    	err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_RSSI, buf, &rsp);
    	if (err) {
    		uint8_t reason = rsp ?
    			((struct bt_hci_rp_read_rssi *)rsp->data)->status : 0;
    		printk("Read RSSI err: %d reason 0x%02x\n", err, reason);
    		return;
    	}
    
    	rp = (void *)rsp->data;
    	*rssi = rp->rssi;
    
    	net_buf_unref(rsp);
    }

    I suggest you use that as reference, and simply copy-paste the handling from there, and verifies it still works in your app. After that you can always modify as needed.

Reply
  • CodeLoader said:
    I'm not sure I understand you, how can I call bt_hci_rp_read_rssi as it is a struct not a function?

    hah, good point. I must admit I was very quick when looking at this earlier Slight smile

    CodeLoader said:
    Maybe in the latest Zephyr update it was changed? I'm using Zephyr 1.6.1, by the way.

    I assume you are referring to nRF Connect SDK 1.6.1 (as Zephyr 1.6.1 is really old)? If so, then the approach demonstrated in the hci_pwr_ctrl should work, and I just tested on a nRF5340 DK, where I get the RSSI reading without any issues.

    CodeLoader said:
    And what is sdc_hci_cmd_sp_read_rssi_return_t? Can you please provide a code example for better understanding?

    That is the type of the struct holding the rssi in the SoftDevice controller API. The only code example you should refer to is the hci_pwr_ctrl which does this. If. you are using 1.6.1, then that would be this:

    static void read_conn_rssi(uint16_t handle, int8_t *rssi)
    {
    	struct net_buf *buf, *rsp = NULL;
    	struct bt_hci_cp_read_rssi *cp;
    	struct bt_hci_rp_read_rssi *rp;
    
    	int err;
    
    	buf = bt_hci_cmd_create(BT_HCI_OP_READ_RSSI, sizeof(*cp));
    	if (!buf) {
    		printk("Unable to allocate command buffer\n");
    		return;
    	}
    
    	cp = net_buf_add(buf, sizeof(*cp));
    	cp->handle = sys_cpu_to_le16(handle);
    
    	err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_RSSI, buf, &rsp);
    	if (err) {
    		uint8_t reason = rsp ?
    			((struct bt_hci_rp_read_rssi *)rsp->data)->status : 0;
    		printk("Read RSSI err: %d reason 0x%02x\n", err, reason);
    		return;
    	}
    
    	rp = (void *)rsp->data;
    	*rssi = rp->rssi;
    
    	net_buf_unref(rsp);
    }

    I suggest you use that as reference, and simply copy-paste the handling from there, and verifies it still works in your app. After that you can always modify as needed.

Children
  • So I was doing basically that, and what I've found out, is that right away after the connection the BLE controller seems to be not ready for the RSSI query, and it returns 127. 
    It always returns a normal negative value when I query RSSI after receiving a BLE message, but I need it to be resolved in the connection handler
    I created an infinite loop to run this RSSI-querying function in the connection handler until it gives a normal value, and it usually gets it from 10th-20th attempt. Although sometimes it's at the first attempt.

    So I wonder, why there is no error status or any way to signal this not-readiness?

  • I see the same in nRF Connect SDK 1.6.1. There is no error indicating that it is not ready (the status still indicates 0). This is fixed in 1.7 and later, though. For 1.6 I suggest you simply discard 127 as that can never be a valid value.

Related