Hi,
I have some issues understanding exactly how a BT central acting as a Client can get the info it wants from a BT peripheral acting as a Server. I have a custom periheral (running zephyr BLE on a nrf52840) that I want to communicate with a custom central (same thing, nrf52840).
The custom peripheral I have managed to get working, and it consist of a single service where a client can write to one characteristic and the client can read what has been written in another characteristic. The code is as follows:
Peripheral:
read_write_service.c:
#define BT_UUID_READ_WRITE_SERVICE \ BT_UUID_DECLARE_128(0x3E, 0x09, 0x99, 0x10, 0x29, 0x3F, 0x11, 0xE4, 0x93, \ 0xBD, 0xAF, 0xD0, 0xFE, 0x6D, 0x1D, 0xA0) // input to the peripheral device #define BT_UUID_INPUT \ BT_UUID_DECLARE_128(0x3E, 0x09, 0x99, 0x11, 0x29, 0x3F, 0x11, 0xE4, 0x93, \ 0xBD, 0xAF, 0xD0, 0xFE, 0x6D, 0x1D, 0xA1) // output from the peripheral device #define BT_UUID_OUTPUT \ BT_UUID_DECLARE_128(0x3E, 0x09, 0x99, 0x11, 0x29, 0x3F, 0x11, 0xE4, 0x93, \ 0xBD, 0xAF, 0xD0, 0xFE, 0x6D, 0x1D, 0xA2) static struct bt_gatt_attr attrs[] = { BT_GATT_PRIMARY_SERVICE(BT_UUID_READ_WRITE_SERVICE), BT_GATT_CHARACTERISTIC(BT_UUID_INPUT, BT_GATT_CHRC_WRITE, BT_GATT_PERM_WRITE, NULL, write_input, NULL), BT_GATT_CHARACTERISTIC(BT_UUID_OUTPUT, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_output, NULL, NULL), }; static struct bt_gatt_service read_write_service = BT_GATT_SERVICE(attrs); u8_t a_number = 0; void read_write_service_init() { bt_gatt_service_register(&read_write_service); } ssize_t write_input(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, u16_t len, u16_t offset, u8_t flags) { const u8_t *new_number = buf; if (!len) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN); } if (*new_number >= 0 && *new_number <= 10) { a_number = *new_number; } else { return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED); } printk("write_input [%d]\n", a_number); return len; } ssize_t read_output(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) { printk("read_output\n"); return bt_gatt_attr_read(conn, attr, buf, len, offset, &a_number, sizeof(a_number)); }
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) struct bt_conn *default_conn; static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), }; static void connected(struct bt_conn *conn, u8_t err) { if (err) { printk("Connection failed (err %u)\n", err); } else { printk("Connected\n"); default_conn = bt_conn_ref(conn); } } static void disconnected(struct bt_conn *conn, u8_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 bt_ready(int err) { if (err) { printk("Bluetooth init failed (err %d)\n", err); return; } read_write_service_init(); /*if (IS_ENABLED(CONFIG_SETTINGS)) { settings_load(); }*/ err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0); if (err) { printk("Advertising failed to start (err %d)\n", err); return; } printk("Advertising successfully started\n"); } void main(void) { printk("starting in main \n\n"); int err; err = bt_enable(bt_ready); if (err) { printk("Bluetooth initialization failed."); return; } bt_conn_cb_register(&conn_callbacks); }
#define BT_UUID_READ_WRITE_SERVICE \ BT_UUID_DECLARE_128(0x3E, 0x09, 0x99, 0x10, 0x29, 0x3F, 0x11, 0xE4, \ 0x93, 0xBD, 0xAF, 0xD0, 0xFE, 0x6D, 0x1D, 0xA0) // input to the peripheral device #define BT_UUID_INPUT \ BT_UUID_DECLARE_128(0x3E, 0x09, 0x99, 0x11, 0x29, 0x3F, 0x11, 0xE4, \ 0x93, 0xBD, 0xAF, 0xD0, 0xFE, 0x6D, 0x1D, 0xA1) // output from the peripheral device #define BT_UUID_OUTPUT \ BT_UUID_DECLARE_128(0x3E, 0x09, 0x99, 0x11, 0x29, 0x3F, 0x11, 0xE4, \ 0x93, 0xBD, 0xAF, 0xD0, 0xFE, 0x6D, 0x1D, 0xA2) #define BT_UUID_NAMING_CHARACTERISTIC \ BT_UUID_DECLARE_128(0x3E, 0x09, 0x99, 0x11, 0x29, 0x3F, 0x11, 0xE4, \ 0x93, 0xBD, 0xAF, 0xD0, 0xFE, 0x6D, 0x1D, 0xA3) static void start_scan(void); static struct bt_conn *default_conn; static u8_t discovered(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params); static struct bt_gatt_discover_params discover_params; static struct bt_uuid_128 uuid = BT_UUID_INIT_128(0); static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, struct net_buf_simple *ad) { char addr_str[BT_ADDR_LE_STR_LEN]; int err; if (default_conn) { return; } /* We're only interested in connectable events */ if (type != BT_GAP_ADV_TYPE_ADV_IND && type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { return; } bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); printk("Device found: %s (RSSI %d)\n", addr_str, rssi); /* connect only to devices in close proximity */ if (rssi < -50) { return; } if (bt_le_scan_stop()) { return; } err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &default_conn); if (err) { printk("Create conn to %s failed (%u)\n", addr_str, err); start_scan(); } } static void start_scan(void) { int err; /* This demo doesn't require active scan */ err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); if (err) { printk("Scanning failed to start (err %d)\n", err); return; } printk("Scanning successfully started\n"); } static u8_t discovered(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { int err; if (!attr) { printk("Discover complete\n"); memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (bt_uuid_cmp(discover_params.uuid, BT_UUID_OUTPUT)) { memcpy(&uuid, BT_UUID_OUTPUT, sizeof(uuid)); discover_params.uuid = &uuid.uuid; discover_params.start_handle = attr->handle + 1; discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; err = bt_gatt_discover(conn, &discover_params); if (err) { printk("Discover failed (err %d)\n", err); } char dest2[150]; bt_uuid_to_str(params->uuid, dest2, sizeof(dest2)); printk("Discovered attribute again- uuid: %s, handle: %u\n", dest2, attr->handle); bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); return BT_GATT_ITER_STOP; } char dest[150]; bt_uuid_to_str(attr->uuid, dest, sizeof(dest)); printk("Discovered attribute - uuid: %s, handle: %u\n", dest, attr->handle); bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); return BT_GATT_ITER_STOP; } static void connected(struct bt_conn *conn, u8_t err) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); if (err) { printk("Failed to connect to %s (%u)\n", addr, err); bt_conn_unref(default_conn); default_conn = NULL; start_scan(); return; } if (conn != default_conn) { return; } printk("Connected: %s\n", addr); discover_params.func = discovered; discover_params.start_handle = 0x0001; discover_params.end_handle = 0xFFFF; discover_params.type = BT_GATT_DISCOVER_PRIMARY; bt_gatt_discover(conn, &discover_params); } static void disconnected(struct bt_conn *conn, u8_t reason) { char addr[BT_ADDR_LE_STR_LEN]; if (conn != default_conn) { return; } bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); bt_conn_unref(default_conn); default_conn = NULL; start_scan(); } static struct bt_conn_cb conn_callbacks = { .connected = connected, .disconnected = disconnected, }; 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); start_scan(); }