[PATCH BlueZ v2 4/7] tools/btgatt-server: Populate the database.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch populates the GATT database with the GAP and GATT services.
---
 tools/btgatt-server.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 259 insertions(+)

diff --git a/tools/btgatt-server.c b/tools/btgatt-server.c
index e185413..545c8c4 100644
--- a/tools/btgatt-server.c
+++ b/tools/btgatt-server.c
@@ -42,12 +42,18 @@
 
 #define ATT_CID 4
 
+#define UUID_GAP 0x1800
+
 #define PRLOG(...) \
 	do { \
 		printf(__VA_ARGS__); \
 		print_prompt(); \
 	} while (0)
 
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
 #define COLOR_OFF	"\x1B[0m"
 #define COLOR_RED	"\x1B[0;91m"
 #define COLOR_GREEN	"\x1B[0;92m"
@@ -57,12 +63,19 @@
 #define COLOR_BOLDGRAY	"\x1B[1;30m"
 #define COLOR_BOLDWHITE	"\x1B[1;37m"
 
+static const char test_device_name[] = "Very Long Test Device Name For Testing "
+				"ATT Protocol Operations On GATT Server";
 static bool verbose = false;
 
 struct server {
 	int fd;
 	struct gatt_db *db;
 	struct bt_gatt_server *gatt;
+
+	uint8_t *device_name;
+	size_t name_len;
+
+	bool svc_chngd_enabled;
 };
 
 static void print_prompt(void)
@@ -93,10 +106,243 @@ static void gatt_debug_cb(const char *str, void *user_data)
 	PRLOG(COLOR_GREEN "%s%s\n" COLOR_OFF, prefix, str);
 }
 
+static void gap_device_name_read_cb(struct gatt_db_attribute *attrib,
+					unsigned int id, uint16_t offset,
+					uint8_t opcode, bdaddr_t *bdaddr,
+					void *user_data)
+{
+	struct server *server = user_data;
+	uint8_t error = 0;
+	size_t len = 0;
+	const uint8_t *value = NULL;
+
+	PRLOG("GAP Device Name Read called\n");
+
+	len = server->name_len;
+
+	if (offset > len) {
+		error = BT_ATT_ERROR_INVALID_OFFSET;
+		goto done;
+	}
+
+	len -= offset;
+	value = len ? &server->device_name[offset] : NULL;
+
+done:
+	gatt_db_attribute_read_result(attrib, id, error, value, len);
+}
+
+static void gap_device_name_write_cb(struct gatt_db_attribute *attrib,
+					unsigned int id, uint16_t offset,
+					const uint8_t *value, size_t len,
+					uint8_t opcode, bdaddr_t *bdaddr,
+					void *user_data)
+{
+	struct server *server = user_data;
+	uint8_t error = 0;
+
+	PRLOG("GAP Device Name Write called\n");
+
+	/* Implement this as a variable length attribute value. */
+	if (offset > server->name_len) {
+		error = BT_ATT_ERROR_INVALID_OFFSET;
+		goto done;
+	}
+
+	if (offset + len != server->name_len) {
+		uint8_t *name;
+
+		name = realloc(server->device_name, offset + len);
+		if (!name) {
+			error = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
+			goto done;
+		}
+
+		memcpy(name, server->device_name,
+					MIN(offset + len, server->name_len));
+		server->device_name = name;
+		server->name_len = offset + len;
+	}
+
+	if (value)
+		memcpy(server->device_name + offset, value, len);
+
+done:
+	gatt_db_attribute_write_result(attrib, id, error);
+}
+
+static void gap_device_name_ext_prop_read_cb(struct gatt_db_attribute *attrib,
+					unsigned int id, uint16_t offset,
+					uint8_t opcode, bdaddr_t *bdaddr,
+					void *user_data)
+{
+	uint8_t value[2];
+
+	PRLOG("Device Name Extended Properties Read called\n");
+
+	value[0] = BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE;
+	value[1] = 0;
+
+	gatt_db_attribute_read_result(attrib, id, 0, value, sizeof(value));
+}
+
+static void gatt_service_changed_cb(struct gatt_db_attribute *attrib,
+					unsigned int id, uint16_t offset,
+					uint8_t opcode, bdaddr_t *bdaddr,
+					void *user_data)
+{
+	PRLOG("Service Changed Read called\n");
+
+	gatt_db_attribute_read_result(attrib, id, 0, NULL, 0);
+}
+
+static void gatt_svc_chngd_ccc_read_cb(struct gatt_db_attribute *attrib,
+					unsigned int id, uint16_t offset,
+					uint8_t opcode, bdaddr_t *bdaddr,
+					void *user_data)
+{
+	struct server *server = user_data;
+	uint8_t value[2];
+
+	PRLOG("Service Changed CCC Read called\n");
+
+	value[0] = server->svc_chngd_enabled ? 0x02 : 0x00;
+	value[1] = 0x00;
+
+	gatt_db_attribute_read_result(attrib, id, 0, value, sizeof(value));
+}
+
+static void gatt_svc_chngd_ccc_write_cb(struct gatt_db_attribute *attrib,
+					unsigned int id, uint16_t offset,
+					const uint8_t *value, size_t len,
+					uint8_t opcode, bdaddr_t *bdaddr,
+					void *user_data)
+{
+	struct server *server = user_data;
+	uint8_t ecode = 0;
+
+	PRLOG("Service Changed CCC Write called\n");
+
+	if (!value || len != 2) {
+		ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
+		goto done;
+	}
+
+	if (offset) {
+		ecode = BT_ATT_ERROR_INVALID_OFFSET;
+		goto done;
+	}
+
+	if (value[0] == 0x00)
+		server->svc_chngd_enabled = false;
+	else if (value[0] == 0x02)
+		server->svc_chngd_enabled = true;
+	else
+		ecode = 0x80;
+
+	PRLOG("Service Changed Enabled: %s\n",
+				server->svc_chngd_enabled ? "true" : "false");
+
+done:
+	gatt_db_attribute_write_result(attrib, id, ecode);
+}
+
+static void confirm_write(struct gatt_db_attribute *attr, int err,
+							void *user_data)
+{
+	if (!err)
+		return;
+
+	fprintf(stderr, "Error caching attribute %p - err: %d\n", attr, err);
+	exit(1);
+}
+
+static void populate_gap_service(struct server *server)
+{
+	bt_uuid_t uuid;
+	struct gatt_db_attribute *service, *tmp;
+	uint16_t appearance;
+
+	/* Add the GAP service */
+	bt_uuid16_create(&uuid, UUID_GAP);
+	service = gatt_db_add_service(server->db, &uuid, true, 6);
+
+	/*
+	 * Device Name characteristic. Make the value dynamically read and
+	 * written via callbacks.
+	 */
+	bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME);
+	gatt_db_service_add_characteristic(service, &uuid,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+					BT_GATT_CHRC_PROP_READ,
+					gap_device_name_read_cb,
+					gap_device_name_write_cb,
+					server);
+
+	bt_uuid16_create(&uuid, GATT_CHARAC_EXT_PROPER_UUID);
+	gatt_db_service_add_descriptor(service, &uuid, BT_ATT_PERM_READ,
+					gap_device_name_ext_prop_read_cb,
+					NULL, server);
+
+	/*
+	 * Appearance characteristic. Reads and writes should obtain the value
+	 * from the database.
+	 */
+	bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
+	tmp = gatt_db_service_add_characteristic(service, &uuid,
+							BT_ATT_PERM_READ,
+							BT_GATT_CHRC_PROP_READ,
+							NULL, NULL, server);
+
+	/*
+	 * Write the appearance value to the database, since we're not using a
+	 * callback.
+	 */
+	put_le16(128, &appearance);
+	gatt_db_attribute_write(tmp, 0, (void *) &appearance,
+							sizeof(appearance),
+							BT_ATT_OP_WRITE_REQ,
+							NULL, confirm_write,
+							NULL);
+
+	gatt_db_service_set_active(service, true);
+}
+
+static void populate_gatt_service(struct server *server)
+{
+	bt_uuid_t uuid;
+	struct gatt_db_attribute *service;
+
+	/* Add the GATT service */
+	bt_uuid16_create(&uuid, 0x1801);
+	service = gatt_db_add_service(server->db, &uuid, true, 4);
+
+	bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
+	gatt_db_service_add_characteristic(service, &uuid, BT_ATT_PERM_READ,
+			BT_GATT_CHRC_PROP_READ | BT_GATT_CHRC_PROP_INDICATE,
+			gatt_service_changed_cb,
+			NULL, server);
+
+	bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	gatt_db_service_add_descriptor(service, &uuid,
+				BT_ATT_PERM_READ | BT_ATT_PERM_WRITE,
+				gatt_svc_chngd_ccc_read_cb,
+				gatt_svc_chngd_ccc_write_cb, server);
+
+	gatt_db_service_set_active(service, true);
+}
+
+static void populate_db(struct server *server)
+{
+	populate_gap_service(server);
+	populate_gatt_service(server);
+}
+
 static struct server *server_create(int fd, uint16_t mtu)
 {
 	struct server *server;
 	struct bt_att *att;
+	size_t name_len = strlen(test_device_name);
 
 	server = new0(struct server, 1);
 	if (!server) {
@@ -120,6 +366,16 @@ static struct server *server_create(int fd, uint16_t mtu)
 		goto fail;
 	}
 
+	server->name_len = name_len + 1;
+	server->device_name = malloc(name_len + 1);
+	if (!server->device_name) {
+		fprintf(stderr, "Failed to allocate memory for device name\n");
+		goto fail;
+	}
+
+	memcpy(server->device_name, test_device_name, name_len);
+	server->device_name[name_len] = '\0';
+
 	server->fd = fd;
 	server->db = gatt_db_new();
 	if (!server->db) {
@@ -142,10 +398,13 @@ static struct server *server_create(int fd, uint16_t mtu)
 	/* bt_gatt_server already holds a reference */
 	bt_att_unref(att);
 
+	populate_db(server);
+
 	return server;
 
 fail:
 	gatt_db_destroy(server->db);
+	free(server->device_name);
 	bt_att_unref(att);
 	free(server);
 
-- 
2.1.0.rc2.206.gedb03e5

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux