How to count retransmissions when receiving specific NUS data from nRF52832

hello Nordic

i am working with two nrf52832 socs, with ncs v2.9.0.

I would like to know how many retransmissions occurred during a Connection Event in which specific NUS data was received.

Do you have any idea?

I have already read the following ticket.

 https://devzone.nordicsemi.com/f/nordic-q-a/97591/how-can-i-get-the-number-ble-tx-re-transmissions/419584 

hope to read you soon

best regards

fmasataka

Parents Reply Children
  • Hi Kenneth; would you know if anyone has successfully used the softdevice controller with other than zephyr? Either another OS or preferably a simple scheduler?

    I found one older post softdevice-controller-example-code maybe you have some other links.

  • Hello,

    Please reach out to our sales organization so they are aware of this request:
    https://www.nordicsemi.com/About-us/Contact-Us 

    Kenneth

  • Hi, Kenneth

    Thanks for the reply.

    There is no direct way of doing this no, normally the application don't care about this, since it's fully handled by the link layer. 

    Okay, I see.

    I'm considering how to derive retransmissions count during a Connection Event in which specific NUS data was received based on connection event counter.

    I've integrated function enable_qos_conn_evt_report and on_vs_evt, used in LLPM sample code, into Central UART sample code(※1) to obtain QoS connection event reports. I've also integrated function sdc_hci_cmd_vs_get_next_conn_event_counter(※2) to obtain next connection event counter at any desired time.

    ※1: https://github.com/nrfconnect/sdk-nrf/tree/main/samples/bluetooth/central_uart

    ※2: https://docs.nordicsemi.com/bundle/nrfxlib-apis-2.9.0/page/group_HCI_VS_API_ga7c3c54b74ce0554f0250cd38ebd7b4aa.html#ga7c3c54b74ce0554f0250cd38ebd7b4aa

    I modified Central UART sample code as follows.

    static uint16_t event_counter = 0;
    static uint16_t next_conn_event_counter = 0;
    static int re_tx_count = 0;
    
    static bool on_vs_evt(struct net_buf_simple *buf)
    {
    	uint8_t code;
    	sdc_hci_subevent_vs_qos_conn_event_report_t *evt;
    
    	code = net_buf_simple_pull_u8(buf);
    	if (code != SDC_HCI_SUBEVENT_VS_QOS_CONN_EVENT_REPORT) {
    		return false;
    	}
    
    	evt = (void *)buf->data;
    	llpm_latency.crc_mismatches += evt->crc_error_count;
    	event_counter = evt->event_counter;
    	re_tx_count = evt->nak_count + evt->rx_timeout + evt->crc_error_count;
    
    	return true;
    }
    
    static int enable_qos_conn_evt_report(void)
    {
    	int err;
    	sdc_hci_cmd_vs_qos_conn_event_report_enable_t cmd_enable;
    
    	err = bt_hci_register_vnd_evt_cb(on_vs_evt);
    	if (err) {
    		printk("Failed registering vendor specific callback (err %d)\n",
    		       err);
    		return err;
    	}
    
    	cmd_enable.enable = true;
    
    	err = hci_vs_sdc_qos_conn_event_report_enable(&cmd_enable);
    	if (err) {
    		printk("Could not enable QoS reports (err %d)\n", err);
    		return err;
    	}
    
    	printk("Connection event reports enabled\n");
    	return 0;
    }
    
    void update_conn_event_counter(void)
    {
    	uint16_t conn_handle;
    	struct bt_conn_info conn_info;
    
    	int err = bt_conn_get_info(nus_client.conn, &conn_info);
    	if (err) {
    		printk("Failed to get connection info (err %d)\n", err);
    		return;
    	}
    	conn_handle = conn_info.id;
    	
    	sdc_hci_cmd_vs_get_next_conn_event_counter_t cmd = {
    		.conn_handle = conn_handle
    	};
        sdc_hci_cmd_vs_get_next_conn_event_counter_return_t return_params;
    
        uint8_t status = sdc_hci_cmd_vs_get_next_conn_event_counter(&cmd, &return_params);
    
        if (status == 0) {
            next_conn_event_counter = return_params.next_conn_event_counter;
        }
    }
    
    static uint8_t ble_data_received(struct bt_nus_client *nus,
    						const uint8_t *data, uint16_t len)
    {
    	ARG_UNUSED(nus);
    
    	int err;
    
    	for (uint16_t pos = 0; pos != len;) {
    		struct uart_data_t *tx = k_malloc(sizeof(*tx));
    
    		if (!tx) {
    			LOG_WRN("Not able to allocate UART send data buffer");
    			return BT_GATT_ITER_CONTINUE;
    		}
    
    		/* Keep the last byte of TX buffer for potential LF char. */
    		size_t tx_data_size = sizeof(tx->data) - 1;
    
    		if ((len - pos) > tx_data_size) {
    			tx->len = tx_data_size;
    		} else {
    			tx->len = (len - pos);
    		}
    
    		memcpy(tx->data, &data[pos], tx->len);
    
    		pos += tx->len;
    
    		/* Append the LF character when the CR character triggered
    		 * transmission from the peer.
    		 */
    		if ((pos == len) && (data[len - 1] == '\r')) {
    			tx->data[tx->len] = '\n';
    			tx->len++;
    		}
    
    		
    		update_conn_event_counter();
    		printk("event_counter%d\n",event_counter);
    		printk("re_tx_count:%d\n", re_tx_count);
    		printk("next_conn_event_counter:%d\n", next_conn_event_counter);
    		
    		err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
    		if (err) {
    			k_fifo_put(&fifo_uart_tx_data, tx);
    		}
    	}
    
    	return BT_GATT_ITER_CONTINUE;
    }

    And an example of console output is shown below.

    event_counter33
    re_tx_count:0
    next_conn_event_counter:35
    event_counter73
    re_tx_count:0
    next_conn_event_counter:75
    event_counter113
    next_conn_event_counter:115
    event_counter153
    re_tx_count:0
    next_conn_event_counter:155

    Is it correct to assume that the connection event counter when specific NUS data is received is either event_counter or next_conn_event_counter-1? If so, what I want to do is feasible.

    Please give me your opinion on whether this approach is versatile or not. In particular, I am wondering if it is valid no matter what value is set for connection interval.

  • Hi,

    Unfortunately I dont' have any further information than what you may already find from the header files for the functions are you using. None do exactly what you ask for, but maybe they can still help.

    Kenneth

Related