Hello,
I'm attempting to write to a ble characteristic but when i call bt_gatt_write, I get BT_ATT_ERR_INVALID_ATTRIBUTE_LEN, I have tried to send the same command using nRF Connect application with ByteArray format and it works.
Here's my source code :
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/sys/printk.h>
static struct bt_conn *default_conn;
static bt_addr_le_t target_addr = {
.type = BT_ADDR_LE_PUBLIC,
.a = {
.val = {0x0e, 0xa0, 0x80, 0x7d, 0xcf, 0x85}
}
};
static struct bt_gatt_read_params read_params;
static struct bt_gatt_subscribe_params subscribe_params;
// K_THREAD_DEFINE(ble_thread, 1024, read_characteristic, NULL, NULL, NULL, 5, 0, 0);
K_SEM_DEFINE(ble_sem, 0, 1);
static struct bt_uuid_128 uuid = BT_UUID_INIT_128(
0xE6, 0xA9, 0xF4, 0xB4, 0x3E, 0x00, 0x0F, 0x9A,
0xDC, 0x4E, 0x42, 0x24, 0xD4, 0x74, 0x3D, 0x36
);
// static struct bt_uuid_128 uuid = BT_UUID_INIT_128(
// 0x36, 0x3D, 0x74, 0xD0, 0x24, 0x42, 0x4E, 0xDC,
// 0x9A, 0x0F, 0x00, 0x3E, 0xB4, 0xF4, 0xA9, 0xE6
// );
static void read_func(struct bt_conn *conn,
struct bt_gatt_subscribe_params *params,
const void *data, uint16_t length)
{
if (data) {
printk("Characteristic value: ");
for (int i = 0; i < length; i++) {
printk("%02x ", ((uint8_t *)data)[i]);
}
printk("\n");
} else {
printk("Read complete\n");
}
}
static void ccc_write_cb(struct bt_conn *conn, uint8_t err,
struct bt_gatt_write_params *params)
{
if (err) {
printk("CCCD write failed (err %u)\n", err);
} else {
printk("CCCD write successful\n");
}
}
static struct bt_gatt_write_params write_params;
static uint8_t ccc_value[] = {0x04, 0x62, 0x15, 0x00, 0x00} ; /* Write cmd to send current value*/
// static uint64_t ccc_value = 0x04062150000; /* Write cmd to send current value*/
// static uint8_t ccc_value[] = {'04', '62', '15', '00', '00'} ;
// static uint8_t ccc_value[] = {'0x04', '0x62', '0x15', '0x00', '0x00'} ;
// static uint8_t ccc_value[] = "0x04062150000" ;
// Write cmd to send current value in byte array
// 0x04, 0x62, 0x15, 0x00, 0x00
static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
struct bt_gatt_discover_params *params)
{
if (!attr) {
printk("Discover complete\n");
memset(params, 0, sizeof(*params));
return BT_GATT_ITER_STOP;
}
struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data;
if (!bt_uuid_cmp(chrc->uuid, &uuid.uuid)) {
printk("Found characteristic\n");
printk("Value handle: %u\n", chrc->value_handle);
// // Read the characteristic value
// read_params.func = read_func;
// read_params.handle_count = 1;
// read_params.single.handle = chrc->value_handle + 1;
// read_params.single.offset = 0;
// Subscribe to notifications
subscribe_params.value = BT_GATT_CCC_NOTIFY;
subscribe_params.notify = read_func;
subscribe_params.ccc_handle = chrc->value_handle; // CCCD handle is usually characteristic handle + 1
int err = bt_gatt_subscribe(conn, &subscribe_params);
if (err) {
printk("Subscribe failed (err %d)\n", err);
}
printk("Subscribed\n");
// Write to CCCD to send value of current
write_params.data = ccc_value;
write_params.length = sizeof(ccc_value);
write_params.handle = chrc->value_handle + 1;// CCCD handle is usually characteristic handle +
write_params.func = ccc_write_cb;
err = bt_gatt_write(conn, &write_params);
printk("Writing CCCD\n");
if (err) {
printk("Failed to write CCCD (err %d)\n", err);
}
printk("CCCD write started\n");
k_sem_give(&ble_sem);
return BT_GATT_ITER_STOP;
}else{
// PRINT UUID
char uuid_str[37];
bt_uuid_to_str(chrc->uuid, uuid_str, sizeof(uuid_str));
printk("UUID Found: %s\n", uuid_str);
}
return BT_GATT_ITER_CONTINUE;
}
static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
printk("Connection failed (err %u)\n", err);
return;
}
default_conn = bt_conn_ref(conn);
printk("Connected\n");
// Discover services and characteristics
static struct bt_gatt_discover_params discover_params;
memset(&discover_params, 0, sizeof(discover_params));
discover_params.func = discover_func;
discover_params.start_handle = 0x0001;
discover_params.end_handle = 0xffff;
discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
printk("Discovering primary services\n");
int ret = bt_gatt_discover(default_conn, &discover_params);
if (ret) {
printk("Discover failed (err %d)\n", ret);
} else {
printk("Discover started\n");
}
}
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
printk("Disconnected (reason %u)\n", reason);
if (default_conn) {
bt_conn_unref(default_conn);
default_conn = NULL;
}
}
static struct bt_conn_cb conn_callbacks = {
.connected = connected,
.disconnected = disconnected,
};
static void scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type,
struct net_buf_simple *buf)
{
char addr_str[18];
char add_str_target[18];
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
bt_addr_le_to_str(&target_addr, add_str_target, sizeof(add_str_target));
printk("Scanned %s || target : %s \n", addr_str, add_str_target);
if (memcmp(add_str_target, addr_str, 18*sizeof(char)) == 0) {
printk("Found device: %s (RSSI %d)\n", addr_str, rssi);
printk("Connecting to %s\n", addr_str);
bt_le_scan_stop();
bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &default_conn);
}
}
void read_characteristic_thread(void)
{
k_sem_take(&ble_sem, K_FOREVER);
printk("characteristic read thread\n");
while (1) {
// if (default_conn) {
// int err = bt_gatt_read(default_conn, &read_params);
// if (err) {
// printk("Read failed (err %d)\n", err);
// }
// }
k_sleep(K_SECONDS(1)); // Adjust the sleep duration as needed
}
}
K_THREAD_DEFINE(read_char_thread, 1024, read_characteristic_thread, NULL, NULL, NULL, 5, 0, 0);
void main(void)
{
int err;
err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d)\n", err);
return;
}
printk("Bluetooth initialized\n");
bt_conn_cb_register(&conn_callbacks);
struct bt_le_scan_param scan_param = {
.type = BT_HCI_LE_SCAN_PASSIVE,
.options = BT_LE_SCAN_OPT_NONE,
.interval = BT_GAP_SCAN_FAST_INTERVAL,
.window = BT_GAP_SCAN_FAST_WINDOW,
};
err = bt_le_scan_start(&scan_param, scan_cb);
if (err) {
printk("Scanning failed to start (err %d)\n", err);
return;
}
printk("Scanning started\n");
}
prj.conf :
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_HCI=y
CONFIG_BT_CTLR=y
CONFIG_BT_SCAN=y
CONFIG_BT_H4=n
CONFIG_BT_SCAN=y
CONFIG_BT_GATT_CLIENT=y
CONFIG_PRINTK=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_RTT_CONSOLE=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_LOG_MODE_IMMEDIATE=n
CONFIG_LOG_MODE_DEFERRED=y
Btw I'm using thingy91/nrf52840
Best regards
Youssef