Customised TX Power service not working while running RSSI macro on Android nRF Connect mobile application

Hi,

I am developing with the nRF52833 DK using NCS v2.00.

I have edited the existing TX power service (TPS) to allow the client to set a desired TX power. I have added an additional characteristic for this (client sends data to peripheral). This works succesfuly when I test it using an Android device running nRF Conenct mobile - I can change the TX power by writing data using the customised service.

However, as soon as I start running a macro that reads RSSI every 1 second, this service stops working. TX Power notifcations still come through that tell me what the current TX power is but evry time I try send data (TX Power) using the Android, nothing sends. If I stop running the macro, it works again. Any idea why this is happening?

I have attached the code from my tx power service file.

Thanks,

Adam

/** @file
 *  @brief GATT TX Power Service
 */

/*
 * Copyright (c) 2020 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <errno.h>
#include <zephyr/types.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/gatt.h>
#include <bluetooth/uuid.h>
#include <bluetooth/hci.h>

#include "../src/txp_helper.c"

#define LOG_LEVEL CONFIG_BT_TPS_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(tps);

/* Declare in header file */
#define TXP_SET_CHARACTERISTIC_UUID   0xAA, 0x6A, 0x11, 0xED, 0x92, 0xE7, 0x43, 0x5A, \
			                            0xAA, 0xE9, 0x43, 0x94,  0x35, 0x20, 0xD4, 0xD3

#define BT_UUID_TXP_SET     BT_UUID_DECLARE_128(TXP_SET_CHARACTERISTIC_UUID)

#define MAX_TRANSMIT_SIZE 240//TODO figure this out

uint8_t data_rx_txp[MAX_TRANSMIT_SIZE];
uint8_t data_tx_txp[MAX_TRANSMIT_SIZE];

int txp_service_init(void)
{
    int err = 0;

    memset(&data_rx_txp, 0, MAX_TRANSMIT_SIZE);
    memset(&data_tx_txp, 0, MAX_TRANSMIT_SIZE);

    return err;
}

/* This function is called whenever the RX Characteristic has been written to by a Client */
static ssize_t on_receive_txp_set(struct bt_conn *conn,
			  const struct bt_gatt_attr *attr,
			  const void *buf,
			  uint16_t len,
			  uint16_t offset,
			  uint8_t flags)
{
    const uint8_t * buffer = buf;
    
	printk("Received data, handle %d, conn %p, data: 0x", attr->handle, conn);
    for(uint8_t i = 0; i < len; i++){
        printk("%02X\n", buffer[i]);
    }
    printk("\n");

    /* Warning: if buffer has more info after position 0, this will be ignored.
     * Data is read from right to left.
     * e.g. if user sends a 16 bit number, the rightmost 8 bits will be saved into client_set_txp.
     */
    int client_set_txp = buffer[0];

    uint16_t connection_handle;
    bt_hci_get_conn_handle(conn, &connection_handle);
    set_tx_power(BT_HCI_VS_LL_HANDLE_TYPE_CONN, connection_handle, client_set_txp);

	return len;
}

static ssize_t read_tx_power_level(struct bt_conn *conn,
				   const struct bt_gatt_attr *attr, void *buf,
				   uint16_t len, uint16_t offset)
{
	int err;
	struct bt_conn_le_tx_power tx_power_level = {0};

	if (offset) {
		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
	}

	err = bt_conn_le_get_tx_power_level(conn, &tx_power_level);
	if (err) {
		LOG_ERR("Failed to read Tx Power Level over HCI: %d", err);
		return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
	}

	LOG_INF("TPS Tx Power Level read %d", tx_power_level.current_level);

	return bt_gatt_attr_read(conn, attr, buf, len, offset,
				 &tx_power_level.current_level,
				 sizeof(tx_power_level.current_level));
}

void on_cccd_changed_txp(const struct bt_gatt_attr *attr, uint16_t value)
{
    ARG_UNUSED(attr);
    switch(value)
    {
        case BT_GATT_CCC_NOTIFY: 
            // Start sending stuff!
            break;

        case BT_GATT_CCC_INDICATE: 
            // Start sending stuff via indications
            break;

        case 0: 
            // Stop sending stuff
            break;
        
        default: 
            printk("Error, CCCD has been set to an invalid value");     
    }
}

/* This function is called whenever a Notification has been sent by the TX Characteristic */
static void on_sent_txp(struct bt_conn *conn, void *user_data)
{
	ARG_UNUSED(user_data);

    const bt_addr_le_t * addr = bt_conn_get_dst(conn);
        
	/*
    printk("Data sent to Address 0x %02X %02X %02X %02X %02X %02X \n", addr->a.val[0]
                                                                    , addr->a.val[1]
                                                                    , addr->a.val[2]
                                                                    , addr->a.val[3]
                                                                    , addr->a.val[4]
                                                                    , addr->a.val[5]);
    */
}

/* Notifcations are sent using the HCI txp function.
 * However, the txp READ value is populated from the read_tx_power_level in this class.
 * It seems redundant to have 2 different fucntions that do similar things but this is not the case.
 * Firstly, the fucntions have different arguments and return types.
 * Secodnly, the read_tx_power_level calls bt_gatt_attr_read while the other function does not seem
 * to use the ATT profile at all and rather just the HCI.
 */

BT_GATT_SERVICE_DEFINE(tps_svc,
	BT_GATT_PRIMARY_SERVICE(BT_UUID_TPS),
    BT_GATT_CHARACTERISTIC(BT_UUID_TXP_SET,
			       BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
			       BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, 
                   NULL, on_receive_txp_set, NULL),
	BT_GATT_CHARACTERISTIC(BT_UUID_TPS_TX_POWER_LEVEL,
			       BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ,
			       read_tx_power_level, NULL, NULL),
    BT_GATT_CCC(on_cccd_changed_txp,
        BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
);

void txp_service_send(struct bt_conn *conn, const uint8_t *data, uint16_t len)
{
    /* 
    The attribute for the TX characteristic is used with bt_gatt_is_subscribed 
    to check whether notification has been enabled by the peer or not.
    Attribute table: 0 = Service, 1 = Primary service, 2 = set txp, 3 = txp send, 4 = CCC.
    */
    const struct bt_gatt_attr *attr = &tps_svc.attrs[3]; 

    struct bt_gatt_notify_params params = 
    {
        .uuid   = BT_UUID_TPS_TX_POWER_LEVEL,
        .attr   = attr,
        .data   = data,
        .len    = len,
        .func   = on_sent_txp
    };

    // Check whether notifications are enabled or not
    if(bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) 
    {
        // Send the notification
        int err = bt_gatt_notify_cb(conn, &params);
        
	    if(err)
        {
            printk("Error, unable to send notification, error: %d\n", err);
        }
    }
    else
    {
        //printk("Warning, notification not enabled on the selected attribute\n");
    }

}

Parents
  • Hi,

    The way I read this, everything works correctly when you do things "manually" (read RSSI, set Tx power), but when using the a macro on nRF Connect that does the same thing, it does not? Have you checked that it does exactly the same thing? If so, I cannot see what the problem could be. Do you get a hint from the log in nRF Connect? Anything else that happens? What on the nRF side, any error or similar in the log there?

  • Hi Einar,

    I can confirm from the log in the nRF Connect mobile app and the terminal log (connected through VCOM) that the service fails to send data from the client to server when I start a macro (print RSSI every 1 sec) on the mobile app. Here are screenshots to explain:

    1. I can start the RSSI macro in the app. As you can see above it, there is a TX Power service (TPS).

    2. If I select the upload characteristic button under the TPS, I can send data:

    3. I can then see in the application log that data has been sent:

    4. I can confirm the data has been sent by the client as I can see confirmation that data has been receieved on the terminal log (server/peripheral side):

    Received data, handle 0, con 0x20001c00, data: 0x00
    
    Tx power set to 0

    5. If I start the RSSI macro, I can see RSSI measurements appearing in the app log:

    Now the problem begins. While RSSI is continually being printed in the log, any data that I attempt to send (client to server) does not send... I know this service fails as I get no confirmation of data sent on the application log or data received on the terminal log. As I said previously, if I stop the RSSI macro, everything works normally again. 

    I would appreicate any help/suggestions regarding this issue please.

    Thanks very much,

    Adam

Reply
  • Hi Einar,

    I can confirm from the log in the nRF Connect mobile app and the terminal log (connected through VCOM) that the service fails to send data from the client to server when I start a macro (print RSSI every 1 sec) on the mobile app. Here are screenshots to explain:

    1. I can start the RSSI macro in the app. As you can see above it, there is a TX Power service (TPS).

    2. If I select the upload characteristic button under the TPS, I can send data:

    3. I can then see in the application log that data has been sent:

    4. I can confirm the data has been sent by the client as I can see confirmation that data has been receieved on the terminal log (server/peripheral side):

    Received data, handle 0, con 0x20001c00, data: 0x00
    
    Tx power set to 0

    5. If I start the RSSI macro, I can see RSSI measurements appearing in the app log:

    Now the problem begins. While RSSI is continually being printed in the log, any data that I attempt to send (client to server) does not send... I know this service fails as I get no confirmation of data sent on the application log or data received on the terminal log. As I said previously, if I stop the RSSI macro, everything works normally again. 

    I would appreicate any help/suggestions regarding this issue please.

    Thanks very much,

    Adam

Children
Related