aboutsummaryrefslogtreecommitdiffstats
path: root/attrib
diff options
context:
space:
mode:
authorClaudio Takahasi <claudio.takahasi@openbossa.org>2010-07-15 18:57:16 -0300
committerJohan Hedberg <johan.hedberg@nokia.com>2010-08-09 18:06:44 -0400
commit281e98d3973dabad039ee274fae24d44b463ad17 (patch)
tree2c4ae9140961c0fed793158787ad13ff3525f020 /attrib
parent6fdb8a10ebd6f762cd1380985765171a183b2b9d (diff)
downloadbluez-281e98d3973dabad039ee274fae24d44b463ad17.tar.gz
bluez-281e98d3973dabad039ee274fae24d44b463ad17.tar.xz
bluez-281e98d3973dabad039ee274fae24d44b463ad17.zip
Initial Discover primary service implementation
Add read by group type encode function and initial skeleton for discover all primary services on attribute client plugin.
Diffstat (limited to 'attrib')
-rw-r--r--attrib/att.c28
-rw-r--r--attrib/att.h6
-rw-r--r--attrib/client.c84
3 files changed, 110 insertions, 8 deletions
diff --git a/attrib/att.c b/attrib/att.c
index 5c189501..f78fe41e 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -21,6 +21,7 @@
*
*/
+#include <errno.h>
#include <stdint.h>
#include <bluetooth/bluetooth.h>
@@ -28,13 +29,34 @@
#include "att.h"
-int att_read_by_grp_type_encode(uint16_t start, uint16_t end, uuid_t *uuid,
+uint16_t att_read_by_grp_type_encode(uint16_t start, uint16_t end, uuid_t *uuid,
uint8_t *pdu, int len)
{
- return 0;
+ uint16_t *p16;
+
+ /* FIXME: UUID128 is not supported */
+
+ if (!uuid)
+ return 0;
+
+ if (uuid->type != SDP_UUID16)
+ return 0;
+
+ if (len < 7)
+ return 0;
+
+ pdu[0] = ATT_OP_READ_BY_GROUP_REQ;
+ p16 = (void *) &pdu[1];
+ *p16 = htobs(start);
+ p16++;
+ *p16 = htobs(end);
+ p16++;
+ *p16 = htobs(uuid->value.uuid16);
+
+ return 7;
}
-int att_find_by_type_encode(uint16_t start, uint16_t end, uuid_t *uuid,
+uint16_t att_find_by_type_encode(uint16_t start, uint16_t end, uuid_t *uuid,
uint8_t *pdu, int len)
{
return 0;
diff --git a/attrib/att.h b/attrib/att.h
index 33f7a52a..f82380f6 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -110,9 +110,11 @@ extern "C" {
#define ATT_CHAR_PROPER_EXT_PROPER 0x80
-int att_read_by_grp_type_encode(uint16_t start, uint16_t end, uuid_t *uuid,
+#define ATT_MTU 256
+
+uint16_t att_read_by_grp_type_encode(uint16_t start, uint16_t end, uuid_t *uuid,
uint8_t *pdu, int len);
-int att_find_by_type_encode(uint16_t start, uint16_t end, uuid_t *uuid,
+uint16_t att_find_by_type_encode(uint16_t start, uint16_t end, uuid_t *uuid,
uint8_t *pdu, int len);
#ifdef __cplusplus
}
diff --git a/attrib/client.c b/attrib/client.c
index 9b98ac70..03ce2c73 100644
--- a/attrib/client.c
+++ b/attrib/client.c
@@ -29,11 +29,15 @@
#include <glib.h>
#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include "log.h"
#include "gdbus.h"
#include "btio.h"
+#include "att.h"
+#include "gattrib.h"
#include "client.h"
#define CHAR_INTERFACE "org.bluez.Characteristic"
@@ -45,6 +49,9 @@ struct gatt_service {
char *path;
GIOChannel *io;
GSList *chars;
+ GAttrib *attrib;
+ int psm;
+ guint atid;
};
struct characteristic {
@@ -70,6 +77,7 @@ static void gatt_service_free(void *user_data)
struct gatt_service *gatt = user_data;
g_slist_foreach(gatt->chars, (GFunc) characteristic_free, NULL);
+ g_attrib_unref(gatt->attrib);
g_free(gatt->path);
g_free(gatt);
}
@@ -106,9 +114,55 @@ static GDBusMethodTable char_methods[] = {
{ }
};
+static guint gatt_discover_primary(GAttrib *attrib, uint16_t start,
+ uint16_t end, GAttribResultFunc func, gpointer user_data)
+{
+ uint8_t pdu[ATT_MTU];
+ uuid_t uuid;
+ guint16 plen;
+
+ sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+
+ plen = att_read_by_grp_type_encode(start, end,
+ &uuid, pdu, sizeof(pdu));
+ if (plen == 0)
+ return 0;
+
+ return g_attrib_send(attrib, ATT_OP_READ_BY_GROUP_REQ,
+ pdu, plen, func, user_data, NULL);
+}
+
+static void primary_cb(guint8 status, const guint8 *pdu, guint16 plen,
+ gpointer user_data)
+{
+ struct gatt_service *gatt = user_data;
+
+ if (status == ATT_ECODE_ATTR_NOT_FOUND) {
+ DBG("Discover all primary services finished.");
+ /* FIXME: Register primary services */
+ return;
+ }
+
+ if (status != 0) {
+ error("Discover all primary services failed.");
+ goto fail;
+ }
+
+ if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP) {
+ error("Protocol error");
+ goto fail;
+ }
+
+ DBG("Read by Group Type Response received");
+fail:
+ gatt_service_free(gatt);
+}
+
static void connect_cb(GIOChannel *chan, GError *gerr, gpointer user_data)
{
struct gatt_service *gatt = user_data;
+ GAttrib *attrib;
+ guint atid;
if (gerr) {
error("%s", gerr->message);
@@ -117,10 +171,23 @@ static void connect_cb(GIOChannel *chan, GError *gerr, gpointer user_data)
DBG("GATT connection established.");
+ attrib = g_attrib_new(chan);
+
+ atid = gatt_discover_primary(attrib, 0x0001, 0xffff, primary_cb, gatt);
+ if (atid == 0) {
+ g_attrib_unref(attrib);
+ goto fail;
+ }
+
+ gatt->attrib = attrib;
+ gatt->atid = atid;
+
+ services = g_slist_append(services, gatt);
+
return;
fail:
g_io_channel_unref(gatt->io);
- gatt->io = NULL;
+ gatt_service_free(gatt);
}
int attrib_client_register(bdaddr_t *sba, bdaddr_t *dba, const char *path,
@@ -142,6 +209,7 @@ int attrib_client_register(bdaddr_t *sba, bdaddr_t *dba, const char *path,
gatt->path = g_strdup(path);
bacpy(&gatt->sba, sba);
bacpy(&gatt->dba, dba);
+ gatt->psm = psm;
chr = g_new0(struct characteristic, 1);
chr->path = g_strdup_printf("%s/service%d/characteristic%d",
@@ -156,10 +224,22 @@ int attrib_client_register(bdaddr_t *sba, bdaddr_t *dba, const char *path,
return -1;
}
+ if (psm < 0) {
+ /*
+ * FIXME: when PSM is not given means that L2CAP fixed
+ * channel shall be used. For this case, ATT CID(0x0004).
+ */
+
+ DBG("GATT over LE");
+
+ return 0;
+ }
+
io = bt_io_connect(BT_IO_L2CAP, connect_cb, gatt, NULL, &gerr,
BT_IO_OPT_SOURCE_BDADDR, sba,
BT_IO_OPT_DEST_BDADDR, dba,
BT_IO_OPT_PSM, psm,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
BT_IO_OPT_INVALID);
if (!io) {
@@ -171,8 +251,6 @@ int attrib_client_register(bdaddr_t *sba, bdaddr_t *dba, const char *path,
gatt->io = io;
- services = g_slist_append(services, gatt);
-
DBG("Registered interface %s on path %s", CHAR_INTERFACE, path);
return 0;