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, ¶ms);
if(err)
{
printk("Error, unable to send notification, error: %d\n", err);
}
}
else
{
//printk("Warning, notification not enabled on the selected attribute\n");
}
}



