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