* [RFC BlueZ 0/2] Initial D-Bus GATT client API implementation.
From: armansito @ 2014-03-12 4:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Arman Uguray
From: Arman Uguray <armansito@chromium.org>
Hi everyone,
I'm working on the GATT client API and I have an initial implementation that
exposes basic GATT service and characteristic objects via D-Bus. Before I go
any further in the implementation, I wanted to get some feedback on whether or
not I've been taking the right approach so far. Also, since this is the first
time I'm contributing to BlueZ, there might be some general style/convention
issues that I would like to get corrected sooner than later :)
This set includes two patches that add support for GATT service and
characteristic objects. Characteristic descriptors, characteristic value
read/write requests, characteristic value notifications and indications,
characteristic properties (flags) and permissions, and included services are
not yet implemented. The main implementation choices that I've made that I would
especially like comments on are the following:
1. A GATT service is represented by instances of btd_gatt_dbus_service. A
btd_device directly creates and owns services. It might actually be better to
keep track of services and the devices that created them in src/gatt-dbus.c,
as the way I implemented it might make managing included services difficult.
2. btd_gatt_dbus_service objects get created in
src/device.c:register_all_services. This may not be the right place to create
them, but every time register_all_services gets called, a btd_device removes
all GATT services that it created and reconstructs them. I took this route
to keep the initial implementation simple but there might be a smarter way to
go about it.
3. GATT service hierarchies are not cached and services are created only after
we connect to a remote device.
4. A btd_device creates a btd_gatt_dbus_service object for all GATT primary
services that it has created. Each service then individually does
characteristic discovery based on it's handle range.
5. GAttrib is used for discovery. GATT services obtain the GAttrib instance
from btd_device by using its attio callbacks. I did it this way solely based
on profiles (profiles/gatt/gas.c and profiles/gatt/heartrate.c) and for all I
know this might be an absolutely terrible way of managing the ATT connection
to the remote device, so please tell me whether or not this is the right
approach.
6. The first patch introduces a change to the way device_browse_primary gets
called in device.c:att_connect_cb; the existing code doesn't do primary
service discovery unless (as far as I understand) the connect request came
over D-Bus, so an auto-connect won't discover remote GATT services, for
example. I made a change here, not because I intended to change that code
path, but because I was curious why it was done the way it is.
Arman Uguray (2):
gatt-dbus: Add remote GATT service objects.
gatt-dbus: Add remote GATT characteristic objects.
src/device.c | 47 ++++++++++-
src/gatt-dbus.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/gatt-dbus.h | 25 ++++++
3 files changed, 321 insertions(+), 6 deletions(-)
--
1.8.3.2
^ permalink raw reply
* [RFC BlueZ 1/2] gatt-dbus: Add remote GATT service objects.
From: armansito @ 2014-03-12 4:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Arman Uguray
In-Reply-To: <1394597040-4483-1-git-send-email-armansito@chromium.org>
From: Arman Uguray <armansito@chromium.org>
This CL adds the initial GATT client D-Bus API support for remote primary GATT
services. Characteristics, descriptors, and included services are not yet
handled.
---
src/device.c | 47 +++++++++++++++++++++++++++--
src/gatt-dbus.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
src/gatt-dbus.h | 25 ++++++++++++++++
3 files changed, 158 insertions(+), 6 deletions(-)
diff --git a/src/device.c b/src/device.c
index e624445..0623e4d 100644
--- a/src/device.c
+++ b/src/device.c
@@ -65,6 +65,7 @@
#include "textfile.h"
#include "storage.h"
#include "attrib-server.h"
+#include "gatt.h"
#define IO_CAPABILITY_NOINPUTNOOUTPUT 0x03
@@ -186,6 +187,7 @@ struct btd_device {
GSList *uuids;
GSList *primaries; /* List of primary services */
GSList *services; /* List of btd_service */
+ GSList *gatt_services; /* List of GATT DBus Services */
GSList *pending; /* Pending services */
GSList *watches; /* List of disconnect_data */
gboolean temporary;
@@ -511,11 +513,18 @@ static void svc_dev_remove(gpointer user_data)
g_free(cb);
}
+static void gatt_dbus_service_free(gpointer user_data)
+{
+ struct btd_gatt_dbus_service *service = user_data;
+ btd_gatt_dbus_service_free(service);
+}
+
static void device_free(gpointer user_data)
{
struct btd_device *device = user_data;
g_slist_free_full(device->uuids, g_free);
+ g_slist_free_full(device->gatt_services, gatt_dbus_service_free);
g_slist_free_full(device->primaries, g_free);
g_slist_free_full(device->attios, g_free);
g_slist_free_full(device->attios_offline, g_free);
@@ -2287,6 +2296,7 @@ static struct btd_device *device_new(struct btd_adapter *adapter,
str2ba(address, &device->bdaddr);
device->adapter = adapter;
+ device->gatt_services = NULL;
return btd_device_ref(device);
}
@@ -3317,6 +3327,35 @@ done:
return FALSE;
}
+static void expose_btd_dbus_gatt_services(struct btd_device *device)
+{
+ GSList *l;
+
+ /* Clear current list of GATT services. */
+ g_slist_free_full(device->gatt_services, gatt_dbus_service_free);
+ device->gatt_services = NULL;
+ for (l = device->primaries; l; l = g_slist_next(l)) {
+ struct gatt_primary *prim = l->data;
+
+ /* Don't create objects for the GAP and GATT services. */
+ if (bt_uuid_strcmp(prim->uuid, GATT_UUID) == 0) {
+ DBG("Skipping GATT UUID for GATT service objects.");
+ continue;
+ }
+ if (bt_uuid_strcmp(prim->uuid, GAP_UUID) == 0) {
+ DBG("Skipping GAP UUID for GATT service objects.");
+ continue;
+ }
+
+ struct btd_gatt_dbus_service *service;
+ service = btd_gatt_dbus_service_create(device, prim);
+ if (service == NULL)
+ continue;
+ device->gatt_services = g_slist_append(device->gatt_services,
+ service);
+ }
+}
+
static void register_all_services(struct browse_req *req, GSList *services)
{
struct btd_device *device = req->device;
@@ -3329,6 +3368,8 @@ static void register_all_services(struct browse_req *req, GSList *services)
device_register_primaries(device, g_slist_copy(services), -1);
+ expose_btd_dbus_gatt_services(device);
+
device_probe_profiles(device, req->profiles_added);
if (device->attios == NULL && device->attios_offline == NULL)
@@ -3501,10 +3542,10 @@ done:
bonding_request_free(device->bonding);
}
- if (device->connect) {
- if (!device->le_state.svc_resolved)
- device_browse_primary(device, NULL);
+ if (!device->le_state.svc_resolved)
+ device_browse_primary(device, NULL);
+ if (device->connect) {
if (err < 0)
reply = btd_error_failed(device->connect,
strerror(-err));
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index c5f1597..60b87fa 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -37,6 +37,9 @@
#include "lib/uuid.h"
#include "dbus-common.h"
#include "log.h"
+#include "attrib/att.h"
+#include "attrib/gattrib.h"
+#include "attrib/gatt.h"
#include "error.h"
#include "gatt.h"
@@ -47,6 +50,12 @@
#define GATT_CHR_IFACE "org.bluez.GattCharacteristic1"
#define GATT_DESCRIPTOR_IFACE "org.bluez.GattDescriptor1"
+struct btd_gatt_dbus_service {
+ bt_uuid_t uuid;
+ struct btd_device *device;
+ char *path;
+};
+
struct external_app {
char *owner;
char *path;
@@ -436,7 +445,7 @@ static DBusMessage *unregister_service(DBusConnection *conn,
return dbus_message_new_method_return(msg);
}
-static const GDBusMethodTable methods[] = {
+static const GDBusMethodTable manager_methods[] = {
{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("RegisterService",
GDBUS_ARGS({ "service", "o"},
{ "options", "a{sv}"}),
@@ -450,8 +459,8 @@ static const GDBusMethodTable methods[] = {
gboolean gatt_dbus_manager_register(void)
{
if (g_dbus_register_interface(btd_get_dbus_connection(),
- "/org/bluez", GATT_MGR_IFACE,
- methods, NULL, NULL, NULL, NULL) == FALSE)
+ "/org/bluez", GATT_MGR_IFACE, manager_methods,
+ NULL, NULL, NULL, NULL) == FALSE)
return FALSE;
proxy_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
@@ -468,3 +477,80 @@ void gatt_dbus_manager_unregister(void)
g_dbus_unregister_interface(btd_get_dbus_connection(), "/org/bluez",
GATT_MGR_IFACE);
}
+
+static gboolean service_property_get_uuid(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ char uuid[MAX_LEN_UUID_STR + 1];
+ const char *ptr = uuid;
+ struct btd_gatt_dbus_service *service = data;
+
+ bt_uuid_to_string(&service->uuid, uuid, sizeof(uuid));
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
+
+ return TRUE;
+}
+
+static const GDBusPropertyTable service_properties[] = {
+ { "UUID", "s", service_property_get_uuid },
+ {}
+};
+
+static void service_free(gpointer user_data)
+{
+ struct btd_gatt_dbus_service *service = user_data;
+
+ g_free(service->path);
+ g_free(service);
+}
+
+struct btd_gatt_dbus_service *btd_gatt_dbus_service_create(
+ struct btd_device *device, struct gatt_primary *primary)
+{
+ struct btd_gatt_dbus_service *service;
+ bt_uuid_t uuid;
+ const char *device_path = device_get_path(device);
+
+ DBG("GATT service UUID: %s", primary->uuid);
+
+ service = g_try_malloc0(sizeof(struct btd_gatt_dbus_service));
+ if (service == NULL)
+ return NULL;
+
+ service->path = g_strdup_printf("%s/service%04X", device_path,
+ primary->range.start);
+
+ if (bt_string_to_uuid(&uuid, primary->uuid)) {
+ error("Primary has invalid UUID: %s", primary->uuid);
+ goto fail;
+ }
+
+ bt_uuid_to_uuid128(&uuid, &service->uuid);
+
+ DBG("Creating GATT service %s", service->path);
+
+ if (g_dbus_register_interface(btd_get_dbus_connection(),
+ service->path, GATT_SERVICE_IFACE,
+ NULL, NULL, service_properties,
+ service,
+ service_free) == FALSE) {
+ char device_addr[18];
+ ba2str(device_get_address(device), device_addr);
+ error("Unable to register GATT service: UUID: %s, device: %s",
+ primary->uuid, device_addr);
+ goto fail;
+ }
+
+ service->device = device;
+ return service;
+
+fail:
+ service_free(service);
+ return NULL;
+}
+
+void btd_gatt_dbus_service_free(struct btd_gatt_dbus_service* service)
+{
+ g_dbus_unregister_interface(btd_get_dbus_connection(),
+ service->path, GATT_SERVICE_IFACE);
+}
diff --git a/src/gatt-dbus.h b/src/gatt-dbus.h
index 310cfa9..08d3f11 100644
--- a/src/gatt-dbus.h
+++ b/src/gatt-dbus.h
@@ -21,5 +21,30 @@
*
*/
+struct btd_gatt_dbus_service;
+struct btd_device;
+struct gatt_primary;
+
gboolean gatt_dbus_manager_register(void);
void gatt_dbus_manager_unregister(void);
+
+/*
+ * btd_gatt_dbus_service_create - Create a GATT service that represents a remote
+ * primary GATT service and expose it via D-Bus.
+ *
+ * @device: The remote device that hosts the GATT service.
+ * @primary: The primary GATT service.
+ *
+ * Returns a reference to the GATT service object. In case of error, NULL is
+ * returned.
+ */
+struct btd_gatt_dbus_service *btd_gatt_dbus_service_create(
+ struct btd_device *device, struct gatt_primary *primary);
+
+/*
+ * btd_gatt_dbus_service_free - Unregister a GATT service as a D-Bus object and
+ * free up its memory.
+ *
+ * @service: The GATT service object to remove.
+ */
+void btd_gatt_dbus_service_free(struct btd_gatt_dbus_service* service);
--
1.8.3.2
^ permalink raw reply related
* [RFC BlueZ 2/2] gatt-dbus: Add remote GATT characteristic objects.
From: armansito @ 2014-03-12 4:04 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Arman Uguray
In-Reply-To: <1394597040-4483-1-git-send-email-armansito@chromium.org>
From: Arman Uguray <armansito@chromium.org>
This CL adds remote GATT characteristic objects to the D-Bus API. The
API only exposes the UUID; the characteristic value and permissions have
not yet been implemented.
---
src/gatt-dbus.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 164 insertions(+), 1 deletion(-)
diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 60b87fa..db98137 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -52,8 +52,24 @@
struct btd_gatt_dbus_service {
bt_uuid_t uuid;
+ struct att_range range;
+ GAttrib *attrib;
+ guint attioid;
+ guint request;
+
struct btd_device *device;
char *path;
+ GSList *characteristics;
+};
+
+struct gatt_dbus_characteristic {
+ bt_uuid_t uuid;
+ uint8_t handle;
+ uint8_t value_handle;
+ uint8_t properties;
+
+ struct btd_gatt_dbus_service *service;
+ char *path;
};
struct external_app {
@@ -491,19 +507,156 @@ static gboolean service_property_get_uuid(const GDBusPropertyTable *property,
return TRUE;
}
+static gboolean characteristic_property_get_uuid(
+ const GDBusPropertyTable *table,
+ DBusMessageIter *iter, void *data)
+{
+ char uuid[MAX_LEN_UUID_STR + 1];
+ const char *ptr = uuid;
+ struct gatt_dbus_characteristic *chr = data;
+
+ bt_uuid_to_string(&chr->uuid, uuid, sizeof(uuid));
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
+
+ return TRUE;
+}
+
static const GDBusPropertyTable service_properties[] = {
{ "UUID", "s", service_property_get_uuid },
{}
};
+static const GDBusPropertyTable characteristic_properties[] = {
+ { "UUID", "s", characteristic_property_get_uuid },
+ {}
+};
+
+static void unregister_characteristic(gpointer user_data)
+{
+ struct gatt_dbus_characteristic *chr = user_data;
+ g_dbus_unregister_interface(btd_get_dbus_connection(),
+ chr->path, GATT_CHR_IFACE);
+}
+
+static void attio_cleanup(struct btd_gatt_dbus_service *service)
+{
+ if (!service->attrib)
+ return;
+ GAttrib *attrib = service->attrib;
+ service->attrib = NULL;
+ if (service->request) {
+ g_attrib_cancel(attrib, service->request);
+ service->request = 0;
+ }
+ g_attrib_unref(attrib);
+}
+
static void service_free(gpointer user_data)
{
struct btd_gatt_dbus_service *service = user_data;
+ g_slist_free_full(service->characteristics, unregister_characteristic);
+
+ if (service->attioid) {
+ btd_device_remove_attio_callback(service->device,
+ service->attioid);
+ }
+ attio_cleanup(service);
g_free(service->path);
g_free(service);
}
+static void characteristic_free(gpointer user_data)
+{
+ struct gatt_dbus_characteristic *characteristic = user_data;
+
+ g_free(characteristic->path);
+ g_free(characteristic);
+}
+
+static struct gatt_dbus_characteristic *characteristic_create(
+ struct btd_gatt_dbus_service *service,
+ struct gatt_char *chr)
+{
+ struct gatt_dbus_characteristic *characteristic;
+ bt_uuid_t uuid;
+
+ DBG("GATT characteristic UUID: %s", chr->uuid);
+
+ characteristic = g_try_malloc0(sizeof(struct gatt_dbus_characteristic));
+ if (characteristic == NULL)
+ return NULL;
+
+ characteristic->path = g_strdup_printf("%s/char%04X", service->path,
+ chr->handle);
+ characteristic->service = service;
+ characteristic->handle = chr->handle;
+ characteristic->value_handle = chr->value_handle;
+ characteristic->properties = chr->properties;
+
+ if (bt_string_to_uuid(&uuid, chr->uuid)) {
+ error("Characteristic has invalid UUID: %s", chr->uuid);
+ goto fail;
+ }
+
+ bt_uuid_to_uuid128(&uuid, &characteristic->uuid);
+
+ DBG("Creating GATT characteristic %s", characteristic->path);
+
+ if (g_dbus_register_interface(btd_get_dbus_connection(),
+ characteristic->path,
+ GATT_CHR_IFACE, NULL, NULL,
+ characteristic_properties,
+ characteristic,
+ characteristic_free) == FALSE) {
+ error("Unable to register GATT characteristic: %s", chr->uuid);
+ goto fail;
+ }
+
+ return characteristic;
+
+fail:
+ characteristic_free(characteristic);
+ return NULL;
+}
+
+static void discover_char_cb(uint8_t status, GSList *chars, void *user_data)
+{
+ struct btd_gatt_dbus_service *service = user_data;
+ service->request = 0;
+ if (status) {
+ error("Characteristic discovery failed.");
+ return;
+ }
+ for (; chars; chars = chars->next) {
+ struct gatt_char *chr = chars->data;
+ struct gatt_dbus_characteristic *dbus_chr =
+ characteristic_create(service, chr);
+ if (dbus_chr == NULL)
+ continue;
+ service->characteristics = g_slist_append(
+ service->characteristics, dbus_chr);
+ }
+ attio_cleanup(service);
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+ struct btd_gatt_dbus_service *service = user_data;
+ service->attrib = g_attrib_ref(attrib);
+ service->request = gatt_discover_char(service->attrib,
+ service->range.start,
+ service->range.end,
+ NULL, discover_char_cb,
+ service);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+ struct btd_gatt_dbus_service *service = user_data;
+ attio_cleanup(service);
+}
+
struct btd_gatt_dbus_service *btd_gatt_dbus_service_create(
struct btd_device *device, struct gatt_primary *primary)
{
@@ -520,6 +673,12 @@ struct btd_gatt_dbus_service *btd_gatt_dbus_service_create(
service->path = g_strdup_printf("%s/service%04X", device_path,
primary->range.start);
+ service->device = device;
+ service->range = primary->range;
+ service->characteristics = NULL;
+ service->attrib = NULL;
+ service->request = 0;
+
if (bt_string_to_uuid(&uuid, primary->uuid)) {
error("Primary has invalid UUID: %s", primary->uuid);
goto fail;
@@ -541,7 +700,11 @@ struct btd_gatt_dbus_service *btd_gatt_dbus_service_create(
goto fail;
}
- service->device = device;
+ service->attioid = service->attioid = btd_device_add_attio_callback(
+ service->device,
+ attio_connected_cb,
+ attio_disconnected_cb, service);
+
return service;
fail:
--
1.8.3.2
^ permalink raw reply related
* Re: rctest -c "Can't connect: Device or resource busy (16)"
From: Peter Hurley @ 2014-03-12 4:27 UTC (permalink / raw)
To: Marcel Holtmann, Scott James Remnant; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <531FCE03.4080704@hurleysoftware.com>
On 03/11/2014 11:01 PM, Peter Hurley wrote:
> On 03/11/2014 10:14 PM, Marcel Holtmann wrote:
>> Hi Scott,
>>
>>> 3.10 with bluetooth-next applied - btmon of both sides attached
>>
>> I am seeing the same with bluetooth-next on a 3.13 kernel. It even has a weird pattern for me.
>>
>> rctest[52844]: Connected [handle 11, class 0x000000, priority 0]
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Device or resource busy (16)
>> rctest[52844]: Can't connect: Connection refused (111)
>> rctest[52844]: Can't connect: Connection reset by peer (104)
>> rctest[52844]: Can't connect: Connection reset by peer (104)
>> rctest[52844]: Connected [handle 11, class 0x000000, priority 0]
>>
>> Unfortunately I currently have no idea on why this happens. When using
>> SO_LINGER of 60 seconds with rctest -L 60 -c <bdaddr> I am getting some
>> really odd tracing behavior.
>>
>>> ACL Data RX: Handle 11 flags 0x02 dlen 14
>> L2CAP: Command Reject (0x01) ident 7 len 6
>> Reason: Invalid CID in request (0x0002)
>> Destination CID: 64
>> Source CID: 0
>>
>> This should never happen and makes me wonder if something is
>> even screwed up one down in L2CAP. Do you happen to have time
>> to bisect this and figure out which patch introduced this behavior.
Sorry, I was wrong about the UA non-receipt; found it much further
down in the kernel trace. There's quite a lag between sending
the DISC and receiving the UA reply; about 12ms.
^ permalink raw reply
* [PATCH v4 1/2] android/gatt: Handle Register gatt client command
From: Grzegorz Kolodziejczyk @ 2014-03-12 9:27 UTC (permalink / raw)
To: linux-bluetooth
This adds register gatt client app command handling.
---
android/gatt.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 53 insertions(+), 2 deletions(-)
diff --git a/android/gatt.c b/android/gatt.c
index ce85af4..34549dd 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -31,20 +31,71 @@
#include <glib.h>
#include "ipc.h"
+#include "ipc-common.h"
#include "lib/bluetooth.h"
#include "gatt.h"
#include "src/log.h"
#include "hal-msg.h"
+struct gatt_client {
+ int32_t id;
+ uint8_t uuid[16];
+};
+
static struct ipc *hal_ipc = NULL;
static bdaddr_t adapter_addr;
+static GSList *gatt_clients = NULL;
+
+static int find_client_by_uuid(gconstpointer data, gconstpointer user_data)
+{
+ const uint8_t *exp_uuid = user_data;
+ const struct gatt_client *client = data;
+
+ return memcmp(exp_uuid, client->uuid, sizeof(client->uuid));
+}
static void handle_client_register(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_client_register *cmd = buf;
+ struct hal_ev_gatt_client_register_client ev;
+ struct gatt_client *client;
+ static int32_t client_cnt = 1;
+ uint8_t status;
+
DBG("");
- ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_REGISTER,
- HAL_STATUS_FAILED);
+ if (!cmd->uuid) {
+ error("gatt: no uuid received");
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ if (g_slist_find_custom(gatt_clients, &cmd->uuid,
+ find_client_by_uuid)) {
+ error("gatt: client uuid is already on list");
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ client = g_new0(struct gatt_client, 1);
+ memcpy(client->uuid, cmd->uuid, sizeof(client->uuid));
+
+ client->id = client_cnt++;
+
+ gatt_clients = g_slist_prepend(gatt_clients, client);
+
+ status = HAL_STATUS_SUCCESS;
+
+ ev.status = status;
+ ev.client_if = client->id;
+ memcpy(ev.app_uuid, client->uuid, sizeof(client->uuid));
+
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_EV_GATT_CLIENT_REGISTER_CLIENT, sizeof(ev), &ev);
+
+failed:
+ ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
+ HAL_OP_GATT_CLIENT_REGISTER, status);
}
static void handle_client_unregister(const void *buf, uint16_t len)
--
1.8.5.2
^ permalink raw reply related
* [PATCH v4 2/2] android/gatt: Handle Unregister gatt client command
From: Grzegorz Kolodziejczyk @ 2014-03-12 9:27 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1394616458-5212-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>
This adds unregister gatt client app command handling.
---
android/gatt.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/android/gatt.c b/android/gatt.c
index 34549dd..a874737 100644
--- a/android/gatt.c
+++ b/android/gatt.c
@@ -36,6 +36,7 @@
#include "gatt.h"
#include "src/log.h"
#include "hal-msg.h"
+#include "src/shared/util.h"
struct gatt_client {
int32_t id;
@@ -54,6 +55,14 @@ static int find_client_by_uuid(gconstpointer data, gconstpointer user_data)
return memcmp(exp_uuid, client->uuid, sizeof(client->uuid));
}
+static int find_client_by_id(gconstpointer data, gconstpointer user_data)
+{
+ int32_t exp_id = PTR_TO_INT(user_data);
+ const struct gatt_client *client = data;
+
+ return client->id != exp_id;
+}
+
static void handle_client_register(const void *buf, uint16_t len)
{
const struct hal_cmd_gatt_client_register *cmd = buf;
@@ -100,10 +109,27 @@ failed:
static void handle_client_unregister(const void *buf, uint16_t len)
{
+ const struct hal_cmd_gatt_client_unregister *cmd = buf;
+ GSList *l;
+ uint8_t status;
+
DBG("");
+ l = g_slist_find_custom(gatt_clients, INT_TO_PTR(cmd->client_if),
+ find_client_by_id);
+ if (!l) {
+ error("gatt: client_if=%d not found", cmd->client_if);
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ gatt_clients = g_slist_remove(gatt_clients, l->data);
+
+ status = HAL_STATUS_SUCCESS;
+
+failed:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
- HAL_OP_GATT_CLIENT_UNREGISTER, HAL_STATUS_FAILED);
+ HAL_OP_GATT_CLIENT_UNREGISTER, status);
}
static void handle_client_scan(const void *buf, uint16_t len)
--
1.8.5.2
^ permalink raw reply related
* [PATCHv3 1/5] android/avrcp: Add vendor unique passthrough request
From: Andrei Emeltchenko @ 2014-03-12 10:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <CABBYNZK6yEDvVwda3GBubgh2+J=SwE_Vmr5oEJ_hhqhOLd2CsA@mail.gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
android/avctp.c | 74 +++++++++++++++++++++++++++++++++++++++++------------
android/avctp.h | 8 +++++-
android/avrcp-lib.c | 12 +++++++++
android/avrcp-lib.h | 2 ++
4 files changed, 79 insertions(+), 17 deletions(-)
diff --git a/android/avctp.c b/android/avctp.c
index d970250..e9ba6db 100644
--- a/android/avctp.c
+++ b/android/avctp.c
@@ -159,6 +159,8 @@ struct avctp_channel {
struct key_pressed {
uint8_t op;
+ uint8_t *params;
+ size_t params_len;
guint timer;
};
@@ -1172,25 +1174,38 @@ static const char *op2str(uint8_t op)
return "UNKNOWN";
}
-static int avctp_passthrough_press(struct avctp *session, uint8_t op)
+static int avctp_passthrough_press(struct avctp *session, uint8_t op,
+ uint8_t *params, size_t params_len)
{
- uint8_t operands[2];
+ uint8_t operands[7];
+ size_t len;
- DBG("%s", op2str(op));
+ DBG("op 0x%02x %s params_len %zd", op, op2str(op), params_len);
/* Button pressed */
operands[0] = op & 0x7f;
- operands[1] = 0;
+
+ if (op == AVC_VENDOR_UNIQUE && params &&
+ params_len == 5) {
+ memcpy(&operands[2], params, params_len);
+ len = params_len + 2;
+ operands[1] = params_len;
+ } else {
+ len = 2;
+ operands[1] = 0;
+ }
return avctp_send_req(session, AVC_CTYPE_CONTROL,
AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
- operands, sizeof(operands),
+ operands, len,
avctp_passthrough_rsp, NULL);
}
-static int avctp_passthrough_release(struct avctp *session, uint8_t op)
+static int avctp_passthrough_release(struct avctp *session, uint8_t op,
+ uint8_t *params, size_t params_len)
{
- uint8_t operands[2];
+ uint8_t operands[7];
+ size_t len;
DBG("%s", op2str(op));
@@ -1198,9 +1213,16 @@ static int avctp_passthrough_release(struct avctp *session, uint8_t op)
operands[0] = op | 0x80;
operands[1] = 0;
+ if (op == AVC_VENDOR_UNIQUE && params &&
+ params_len > sizeof(operands) - 2) {
+ memcpy(&operands[2], params, params_len);
+ len = params_len;
+ } else
+ len = 2;
+
return avctp_send_req(session, AVC_CTYPE_CONTROL,
AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
- operands, sizeof(operands),
+ operands, len,
NULL, NULL);
}
@@ -1208,15 +1230,18 @@ static gboolean repeat_timeout(gpointer user_data)
{
struct avctp *session = user_data;
- avctp_passthrough_release(session, session->key.op);
- avctp_passthrough_press(session, session->key.op);
+ avctp_passthrough_release(session, session->key.op, session->key.params,
+ session->key.params_len);
+ avctp_passthrough_press(session, session->key.op, session->key.params,
+ session->key.params_len);
return TRUE;
}
static void release_pressed(struct avctp *session)
{
- avctp_passthrough_release(session, session->key.op);
+ avctp_passthrough_release(session, session->key.op, session->key.params,
+ session->key.params_len);
if (session->key.timer > 0)
g_source_remove(session->key.timer);
@@ -1224,7 +1249,8 @@ static void release_pressed(struct avctp *session)
session->key.timer = 0;
}
-static bool set_pressed(struct avctp *session, uint8_t op)
+static bool set_pressed(struct avctp *session, uint8_t op, uint8_t *params,
+ size_t params_len)
{
if (session->key.timer > 0) {
if (session->key.op == op)
@@ -1236,6 +1262,8 @@ static bool set_pressed(struct avctp *session, uint8_t op)
return FALSE;
session->key.op = op;
+ session->key.params = params;
+ session->key.params_len = params_len;
session->key.timer = g_timeout_add_seconds(AVC_PRESS_TIMEOUT,
repeat_timeout,
session);
@@ -1247,24 +1275,38 @@ static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
uint8_t subunit, uint8_t *operands,
size_t operand_count, void *user_data)
{
+ uint8_t *params;
+ size_t params_len;
+
+ DBG("code 0x%02x operand_count %zd", code, operand_count);
+
if (code != AVC_CTYPE_ACCEPTED)
return FALSE;
- if (set_pressed(session, operands[0]))
+ if (operands[0] == AVC_VENDOR_UNIQUE) {
+ params = &operands[2];
+ params_len = operand_count - 2;
+ } else {
+ params = NULL;
+ params_len = 0;
+ }
+
+ if (set_pressed(session, operands[0], params, params_len))
return FALSE;
- avctp_passthrough_release(session, operands[0]);
+ avctp_passthrough_release(session, operands[0], params, params_len);
return FALSE;
}
-int avctp_send_passthrough(struct avctp *session, uint8_t op)
+int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
+ size_t params_len)
{
/* Auto release if key pressed */
if (session->key.timer > 0)
release_pressed(session);
- return avctp_passthrough_press(session, op);
+ return avctp_passthrough_press(session, op, params, params_len);
}
int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
diff --git a/android/avctp.h b/android/avctp.h
index 2f419a2..98c1142 100644
--- a/android/avctp.h
+++ b/android/avctp.h
@@ -108,6 +108,11 @@
#define AVC_BLUE 0x7c
#define AVC_YELLOW 0x7c
+#define AVC_VENDOR_UNIQUE 0x7e
+
+#define AVC_VENDOR_NEXT_GROUP 0x00
+#define AVC_VENDOR_PREV_GROUP 0x01
+
struct avctp;
typedef bool (*avctp_passthrough_cb) (struct avctp *session,
@@ -159,7 +164,8 @@ unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
unsigned int id);
-int avctp_send_passthrough(struct avctp *session, uint8_t op);
+int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
+ size_t params_len);
int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
uint8_t code, uint8_t subunit,
uint8_t *operands, size_t operand_count);
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 5400f80..2cdd1e0 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -471,3 +471,15 @@ int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
AVC_SUBUNIT_PANEL, AVRCP_REGISTER_NOTIFICATION,
params, params_len);
}
+
+int avrcp_send_passthrough_vendor(struct avrcp *session, uint8_t vendor_op,
+ uint16_t vendor_id)
+{
+ uint8_t params[5];
+
+ hton24(params, vendor_id);
+ bt_put_be16(vendor_op, ¶ms[3]);
+
+ return avctp_send_passthrough(session->conn, AVC_VENDOR_UNIQUE, params,
+ sizeof(params));
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 91a7d47..3a2012a 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -164,3 +164,5 @@ int avrcp_get_element_attrs_rsp(struct avrcp *session, uint8_t transaction,
int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
uint8_t code, uint8_t *params,
size_t params_len);
+int avrcp_send_passthrough_vendor(struct avrcp *session, uint8_t vendor_op,
+ uint16_t vendor_id);
--
1.8.3.2
^ permalink raw reply related
* [PATCHv3 2/5] unit/avrcp: Add /TP/BGN/BV-01-I test
From: Andrei Emeltchenko @ 2014-03-12 10:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1394621673-13718-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the Controller can send Next Group command to the
Target.
---
unit/test-avrcp.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 3702d39..a5a7a38 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -636,6 +636,10 @@ static void test_client(gconstpointer data)
AVRCP_EVENT_STATUS_CHANGED, 0,
NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/BGN/BV-01-I"))
+ avrcp_send_passthrough_vendor(context->session,
+ AVC_VENDOR_NEXT_GROUP,
+ IEEEID_BTSIG);
execute_context(context);
}
@@ -1030,5 +1034,12 @@ int main(int argc, char *argv[])
0xff, 0x00, 0x00, 0x01,
AVRCP_STATUS_INVALID_COMMAND));
+ /* Next Group command transfer - CT */
+ define_test("/TP/BGN/BV-01-I", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48,
+ AVC_OP_PASSTHROUGH,
+ AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
+ 0x58, 0x00, AVC_VENDOR_NEXT_GROUP));
+
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCHv3 3/5] unit/avrcp: Add /TP/BGN/BV-02-I test
From: Andrei Emeltchenko @ 2014-03-12 10:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1394621673-13718-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the Controller can send Prev Group command to the
Target.
---
unit/test-avrcp.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index a5a7a38..fd95a7d 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -640,6 +640,12 @@ static void test_client(gconstpointer data)
avrcp_send_passthrough_vendor(context->session,
AVC_VENDOR_NEXT_GROUP,
IEEEID_BTSIG);
+
+ if (g_str_equal(context->data->test_name, "/TP/BGN/BV-02-I"))
+ avrcp_send_passthrough_vendor(context->session,
+ AVC_VENDOR_PREV_GROUP,
+ IEEEID_BTSIG);
+
execute_context(context);
}
@@ -1041,5 +1047,12 @@ int main(int argc, char *argv[])
AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
0x58, 0x00, AVC_VENDOR_NEXT_GROUP));
+ /* Previous Group command transfer - CT */
+ define_test("/TP/BGN/BV-02-I", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48,
+ AVC_OP_PASSTHROUGH,
+ AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
+ 0x58, 0x00, AVC_VENDOR_PREV_GROUP));
+
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCHv3 4/5] unit/avrcp: Add /TP/BGN/BV-01-I TG test
From: Andrei Emeltchenko @ 2014-03-12 10:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1394621673-13718-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the Target responds to Next Group command.
---
unit/test-avrcp.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index fd95a7d..ea421b0 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -280,11 +280,20 @@ static bool handle_select(struct avrcp *session, bool pressed, void *user_data)
return true;
}
+static bool handle_vendor_uniq(struct avrcp *session, bool pressed,
+ void *user_data)
+{
+ DBG("");
+
+ return true;
+}
+
static const struct avrcp_passthrough_handler passthrough_handlers[] = {
{ AVC_PLAY, handle_play },
{ AVC_VOLUME_UP, handle_volume_up },
{ AVC_CHANNEL_UP, handle_channel_up },
{ AVC_SELECT, handle_select },
+ { AVC_VENDOR_UNIQUE, handle_vendor_uniq },
{ },
};
@@ -1047,6 +1056,17 @@ int main(int argc, char *argv[])
AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
0x58, 0x00, AVC_VENDOR_NEXT_GROUP));
+ /* Next Group command transfer - TG */
+ define_test("/TP/BGN/BV-01-I", test_server,
+ raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48,
+ AVC_OP_PASSTHROUGH,
+ AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
+ 0x58, 0x00, AVC_VENDOR_NEXT_GROUP),
+ raw_pdu(0x02, 0x11, 0x0e, AVC_CTYPE_ACCEPTED,
+ 0x48, AVC_OP_PASSTHROUGH,
+ AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
+ 0x58, 0x00, AVC_VENDOR_NEXT_GROUP));
+
/* Previous Group command transfer - CT */
define_test("/TP/BGN/BV-02-I", test_client,
raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48,
--
1.8.3.2
^ permalink raw reply related
* [PATCHv3 5/5] unit/avrcp: Add /TP/BGN/BV-02-I TG test
From: Andrei Emeltchenko @ 2014-03-12 10:54 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1394621673-13718-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the Target responds to Prev Group command.
---
unit/test-avrcp.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index ea421b0..31d17b9 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -1074,5 +1074,16 @@ int main(int argc, char *argv[])
AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
0x58, 0x00, AVC_VENDOR_PREV_GROUP));
+ /* Previous Group command transfer - TG */
+ define_test("/TP/BGN/BV-02-I", test_server,
+ raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48,
+ AVC_OP_PASSTHROUGH,
+ AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
+ 0x58, 0x00, AVC_VENDOR_PREV_GROUP),
+ raw_pdu(0x02, 0x11, 0x0e, AVC_CTYPE_ACCEPTED,
+ 0x48, AVC_OP_PASSTHROUGH,
+ AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
+ 0x58, 0x00, AVC_VENDOR_PREV_GROUP));
+
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH v2 01/10] emulator: Minor style fix
From: Johan Hedberg @ 2014-03-12 11:22 UTC (permalink / raw)
To: Lukasz Rymanowski; +Cc: linux-bluetooth
In-Reply-To: <1394406363-6751-2-git-send-email-lukasz.rymanowski@tieto.com>
Hi Lukasz,
On Mon, Mar 10, 2014, Lukasz Rymanowski wrote:
> ---
> emulator/btdev.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/emulator/btdev.c b/emulator/btdev.c
> index b54f91e..2cf8f89 100644
> --- a/emulator/btdev.c
> +++ b/emulator/btdev.c
> @@ -709,8 +709,8 @@ static void inquiry_complete(struct btdev *btdev, uint8_t status)
> ir.rssi = -60;
> memcpy(ir.data, btdev_list[i]->ext_inquiry_rsp, 240);
>
> - send_event(btdev, BT_HCI_EVT_EXT_INQUIRY_RESULT,
> - &ir, sizeof(ir));
> + send_event(btdev, BT_HCI_EVT_EXT_INQUIRY_RESULT, &ir,
> + sizeof(ir));
> continue;
> }
>
> @@ -738,8 +738,8 @@ static void inquiry_complete(struct btdev *btdev, uint8_t status)
> memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
> ir.clock_offset = 0x0000;
>
> - send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT,
> - &ir, sizeof(ir));
> + send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT, &ir,
> + sizeof(ir));
> }
> }
I wouldn't bother with this one. The reason these two variables have
been put on the same line is that they are tightly related to each
other.
Johan
^ permalink raw reply
* Re: [PATCH v2 02/10] emulator: Use timeout for sending inquiry results
From: Johan Hedberg @ 2014-03-12 11:28 UTC (permalink / raw)
To: Lukasz Rymanowski; +Cc: linux-bluetooth
In-Reply-To: <1394406363-6751-3-git-send-email-lukasz.rymanowski@tieto.com>
Hi Lukasz,
On Mon, Mar 10, 2014, Lukasz Rymanowski wrote:
> +#define DEFAULT_INQUIRY_INTERVAL 100 /* 100 miliseconds */
> +
> #define MAX_BTDEV_ENTRIES 16
>
> +
> static const uint8_t LINK_KEY_NONE[16] = { 0 };
Seems like you're introducing an unnecessary empty line above.
> static const uint8_t LINK_KEY_DUMMY[16] = { 0, 1, 2, 3, 4, 5, 6, 7,
> 8, 9, 0, 1, 2, 3, 4, 5 };
> @@ -528,9 +540,13 @@ void btdev_destroy(struct btdev *btdev)
> if (!btdev)
> return;
>
> + if (btdev->inquiry_id)
> + timeout_remove(btdev->inquiry_id);
We usually check for valid timeout or GSource IDs with id > 0.
> +
> del_btdev(btdev);
>
> free(btdev);
> + btdev = NULL;
> }
This last btdev = NULL is pointless since you're leaving the function
and the variable goes out of scope.
>
> - struct bt_hci_evt_inquiry_complete ic;
> + struct inquiry_data *data = user_data;
> + struct btdev *btdev = data->btdev;
> + int sent = data->sent_count;
> int i;
>
> - for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
> + for (i = data->iter; i < MAX_BTDEV_ENTRIES; i++, data->iter++) {
Iterating data->iter and i++ throughout the entire loop seems overkill
I'd just assign the resulting value of i to data->iter once you've
exited to loop.
> + /*Lets sent 10 inquiry results at once */
> + if (sent + 10 == data->sent_count)
> + break;
I'd prefer if we can make this so that you instead have the timeout
called as many times as necessary and send just one event each time.
I.e. upon reception of HCI_Inquiry you check the duration of the
inquiry, the maximum amount of responses, MAX_BTDEV_ENTRIES and
determine how frequently the timeout should be called in order to send
all events by the time the inquiry should complete.
> +static void inquiry_cmd(struct btdev *btdev, const void *cmd)
> +{
> + struct inquiry_data *data;
> + struct bt_hci_evt_inquiry_complete ic;
> + int status = BT_HCI_ERR_HARDWARE_FAILURE;
> +
> + if (btdev->inquiry_id) {
if (btdev->inquiry_id > 0)
> + data = malloc(sizeof(*data));
> + if (!data)
> + goto error;
We usually use "failed" for this kind of labels.
> + btdev->inquiry_id = timeout_add(DEFAULT_INQUIRY_INTERVAL,
> + inquiry_callback, data, inquiry_destroy);
This looks like possibly incorrect indentation. The indentation should
go past the opening ( and then have more lines if necessary.
Johan
^ permalink raw reply
* Re: [PATCH v2 03/10] emulator: Add inquiry cancel
From: Johan Hedberg @ 2014-03-12 11:39 UTC (permalink / raw)
To: Lukasz Rymanowski; +Cc: linux-bluetooth
In-Reply-To: <1394406363-6751-4-git-send-email-lukasz.rymanowski@tieto.com>
Hi Lukasz,
On Mon, Mar 10, 2014, Lukasz Rymanowski wrote:
> With this patch, scheduled inquiry session in btdev can be canceled
>
> Conflicts:
> emulator/btdev.c
Seems like you forgot to clean up the commit message here.
> @@ -70,6 +70,7 @@ struct btdev {
> void *send_data;
>
> int inquiry_id;
> + bool inquiry_cancel;
>
> struct hook *hook_list[MAX_HOOK_ENTRIES];
>
> @@ -784,10 +785,20 @@ static bool inquiry_callback(void *user_data)
> static void inquiry_destroy(void *user_data)
> {
> struct inquiry_data *data = user_data;
> + struct btdev *btdev = data->btdev;
> + uint8_t status = BT_HCI_ERR_SUCCESS;
> +
> + if (!btdev)
> + goto finish;
>
> - if (data->btdev)
> - data->btdev->inquiry_id = 0;
> + if (btdev->inquiry_cancel)
> + cmd_complete(btdev, BT_HCI_CMD_INQUIRY_CANCEL, &status,
> + sizeof(status));
>
> + btdev->inquiry_cancel = false;
> + btdev->inquiry_id = 0;
> +
> +finish:
> free(data);
> }
>
> @@ -820,6 +831,20 @@ error:
> send_event(btdev, BT_HCI_EVT_INQUIRY_COMPLETE, &ic, sizeof(ic));
> }
>
> +static void inquiry_cancel(struct btdev *btdev)
> +{
> + uint8_t status = BT_HCI_ERR_COMMAND_DISALLOWED;
> +
> + if (!btdev->inquiry_id) {
> + cmd_complete(btdev, BT_HCI_CMD_INQUIRY_CANCEL, &status,
> + sizeof(status));
> + return;
> + }
> +
> + btdev->inquiry_cancel = true;
> + timeout_remove(btdev->inquiry_id);
This whole btdev->inquiry_cancel variable seems pointless to me. Why
don't you simply send the cmd_complete for it after calling
timeout_remove here in the inquiry_cancel function?
Johan
^ permalink raw reply
* Re: [PATCH v2 04/10] emulator: Add handling inquiry number of responses
From: Johan Hedberg @ 2014-03-12 11:42 UTC (permalink / raw)
To: Lukasz Rymanowski; +Cc: linux-bluetooth
In-Reply-To: <1394406363-6751-5-git-send-email-lukasz.rymanowski@tieto.com>
Hi Lukasz,
On Mon, Mar 10, 2014, Lukasz Rymanowski wrote:
> @@ -769,17 +772,22 @@ static bool inquiry_callback(void *user_data)
> }
> }
>
> - if (i == MAX_BTDEV_ENTRIES) {
> - struct bt_hci_evt_inquiry_complete ic;
> -
> - ic.status = BT_HCI_ERR_SUCCESS;
> - send_event(btdev, BT_HCI_EVT_INQUIRY_COMPLETE, &ic, sizeof(ic));
> + /* Check if we sent already required amount of responses*/
> + if (data->num_resp && data->sent_count == data->num_resp)
> + goto finish;
>
> - btdev->inquiry_id = 0;
> - return false;
> - }
> + if (i == MAX_BTDEV_ENTRIES)
> + goto finish;
>
> return true;
> +
> +finish:
> + /* Note that destroy will be called */
> + ic.status = BT_HCI_ERR_SUCCESS;
> + send_event(btdev, BT_HCI_EVT_INQUIRY_COMPLETE, &ic, sizeof(ic));
> +
> + btdev->inquiry_id = 0;
> + return false;
> }
I know you're just moving it around from the first patch but isn't the
btdev->inquiry_id = unnecessary here since you're doing the same in the
destroy function which gets called as soon as you return false?
Johan
^ permalink raw reply
* Re: [PATCH v2 05/10] emulator: Add handling inquiry_lenght from inquiry command
From: Johan Hedberg @ 2014-03-12 11:44 UTC (permalink / raw)
To: Lukasz Rymanowski; +Cc: linux-bluetooth
In-Reply-To: <1394406363-6751-6-git-send-email-lukasz.rymanowski@tieto.com>
Hi Lukasz,
On Mon, Mar 10, 2014, Lukasz Rymanowski wrote:
> --- a/emulator/btdev.c
> +++ b/emulator/btdev.c
> @@ -70,6 +70,7 @@ struct btdev {
> void *send_data;
>
> int inquiry_id;
> + int inquiry_timeout_id;
> bool inquiry_cancel;
>
> struct hook *hook_list[MAX_HOOK_ENTRIES];
> @@ -133,6 +134,8 @@ struct inquiry_data {
>
> int sent_count;
> int iter;
> +
> + bool timeout;
> };
>
> #define DEFAULT_INQUIRY_INTERVAL 100 /* 100 miliseconds */
> @@ -711,6 +714,14 @@ static bool inquiry_callback(void *user_data)
> int sent = data->sent_count;
> int i;
>
> + /* Check if inquiry timeout fired. */
> + if (data->timeout)
> + goto finish;
> +
> + /*Report devices only once and wait for inquiry timeout*/
> + if (data->iter == MAX_BTDEV_ENTRIES)
> + return true;
> +
> for (i = data->iter; i < MAX_BTDEV_ENTRIES; i++, data->iter++) {
> /*Lets sent 10 inquiry results at once */
> if (sent + 10 == data->sent_count)
> @@ -771,14 +782,10 @@ static bool inquiry_callback(void *user_data)
> data->sent_count++;
> }
> }
> -
> /* Check if we sent already required amount of responses*/
> if (data->num_resp && data->sent_count == data->num_resp)
> goto finish;
>
> - if (i == MAX_BTDEV_ENTRIES)
> - goto finish;
> -
> return true;
>
> finish:
> @@ -806,16 +813,33 @@ static void inquiry_destroy(void *user_data)
> btdev->inquiry_cancel = false;
> btdev->inquiry_id = 0;
>
> + if (btdev->inquiry_timeout_id)
> + timeout_remove(btdev->inquiry_timeout_id);
> +
> + btdev->inquiry_timeout_id = 0;
> +
> finish:
> free(data);
> }
>
> +static bool inquiry_timeout(void *user_data)
> +{
> + struct inquiry_data *data = user_data;
> + struct btdev *btdev = data->btdev;
> +
> + data->timeout = true;
> + btdev->inquiry_timeout_id = 0;
> +
> + return false;
> +}
Instead of adding the new data->timeout variable why don't you simply
send the inquiry_complete from within the inquiry_timeout callback?
Johan
^ permalink raw reply
* Re: [PATCHv3 1/5] android/avrcp: Add vendor unique passthrough request
From: Luiz Augusto von Dentz @ 2014-03-12 12:48 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1394621673-13718-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Wed, Mar 12, 2014 at 12:54 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> ---
> android/avctp.c | 74 +++++++++++++++++++++++++++++++++++++++++------------
> android/avctp.h | 8 +++++-
> android/avrcp-lib.c | 12 +++++++++
> android/avrcp-lib.h | 2 ++
> 4 files changed, 79 insertions(+), 17 deletions(-)
>
> diff --git a/android/avctp.c b/android/avctp.c
> index d970250..e9ba6db 100644
> --- a/android/avctp.c
> +++ b/android/avctp.c
> @@ -159,6 +159,8 @@ struct avctp_channel {
>
> struct key_pressed {
> uint8_t op;
> + uint8_t *params;
> + size_t params_len;
> guint timer;
> };
>
> @@ -1172,25 +1174,38 @@ static const char *op2str(uint8_t op)
> return "UNKNOWN";
> }
>
> -static int avctp_passthrough_press(struct avctp *session, uint8_t op)
> +static int avctp_passthrough_press(struct avctp *session, uint8_t op,
> + uint8_t *params, size_t params_len)
> {
> - uint8_t operands[2];
> + uint8_t operands[7];
> + size_t len;
>
> - DBG("%s", op2str(op));
> + DBG("op 0x%02x %s params_len %zd", op, op2str(op), params_len);
>
> /* Button pressed */
> operands[0] = op & 0x7f;
> - operands[1] = 0;
> +
> + if (op == AVC_VENDOR_UNIQUE && params &&
> + params_len == 5) {
> + memcpy(&operands[2], params, params_len);
> + len = params_len + 2;
> + operands[1] = params_len;
> + } else {
> + len = 2;
> + operands[1] = 0;
> + }
>
> return avctp_send_req(session, AVC_CTYPE_CONTROL,
> AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
> - operands, sizeof(operands),
> + operands, len,
> avctp_passthrough_rsp, NULL);
> }
>
> -static int avctp_passthrough_release(struct avctp *session, uint8_t op)
> +static int avctp_passthrough_release(struct avctp *session, uint8_t op,
> + uint8_t *params, size_t params_len)
> {
> - uint8_t operands[2];
> + uint8_t operands[7];
> + size_t len;
>
> DBG("%s", op2str(op));
>
> @@ -1198,9 +1213,16 @@ static int avctp_passthrough_release(struct avctp *session, uint8_t op)
> operands[0] = op | 0x80;
> operands[1] = 0;
>
> + if (op == AVC_VENDOR_UNIQUE && params &&
> + params_len > sizeof(operands) - 2) {
> + memcpy(&operands[2], params, params_len);
> + len = params_len;
> + } else
> + len = 2;
> +
> return avctp_send_req(session, AVC_CTYPE_CONTROL,
> AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
> - operands, sizeof(operands),
> + operands, len,
> NULL, NULL);
> }
>
> @@ -1208,15 +1230,18 @@ static gboolean repeat_timeout(gpointer user_data)
> {
> struct avctp *session = user_data;
>
> - avctp_passthrough_release(session, session->key.op);
> - avctp_passthrough_press(session, session->key.op);
> + avctp_passthrough_release(session, session->key.op, session->key.params,
> + session->key.params_len);
> + avctp_passthrough_press(session, session->key.op, session->key.params,
> + session->key.params_len);
>
> return TRUE;
> }
>
> static void release_pressed(struct avctp *session)
> {
> - avctp_passthrough_release(session, session->key.op);
> + avctp_passthrough_release(session, session->key.op, session->key.params,
> + session->key.params_len);
>
> if (session->key.timer > 0)
> g_source_remove(session->key.timer);
> @@ -1224,7 +1249,8 @@ static void release_pressed(struct avctp *session)
> session->key.timer = 0;
> }
>
> -static bool set_pressed(struct avctp *session, uint8_t op)
> +static bool set_pressed(struct avctp *session, uint8_t op, uint8_t *params,
> + size_t params_len)
> {
> if (session->key.timer > 0) {
> if (session->key.op == op)
> @@ -1236,6 +1262,8 @@ static bool set_pressed(struct avctp *session, uint8_t op)
> return FALSE;
>
> session->key.op = op;
> + session->key.params = params;
> + session->key.params_len = params_len;
> session->key.timer = g_timeout_add_seconds(AVC_PRESS_TIMEOUT,
> repeat_timeout,
> session);
> @@ -1247,24 +1275,38 @@ static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
> uint8_t subunit, uint8_t *operands,
> size_t operand_count, void *user_data)
> {
> + uint8_t *params;
> + size_t params_len;
> +
> + DBG("code 0x%02x operand_count %zd", code, operand_count);
> +
> if (code != AVC_CTYPE_ACCEPTED)
> return FALSE;
>
> - if (set_pressed(session, operands[0]))
> + if (operands[0] == AVC_VENDOR_UNIQUE) {
> + params = &operands[2];
> + params_len = operand_count - 2;
> + } else {
> + params = NULL;
> + params_len = 0;
> + }
> +
> + if (set_pressed(session, operands[0], params, params_len))
> return FALSE;
>
> - avctp_passthrough_release(session, operands[0]);
> + avctp_passthrough_release(session, operands[0], params, params_len);
>
> return FALSE;
> }
>
> -int avctp_send_passthrough(struct avctp *session, uint8_t op)
> +int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
> + size_t params_len)
> {
> /* Auto release if key pressed */
> if (session->key.timer > 0)
> release_pressed(session);
>
> - return avctp_passthrough_press(session, op);
> + return avctp_passthrough_press(session, op, params, params_len);
> }
>
> int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
> diff --git a/android/avctp.h b/android/avctp.h
> index 2f419a2..98c1142 100644
> --- a/android/avctp.h
> +++ b/android/avctp.h
> @@ -108,6 +108,11 @@
> #define AVC_BLUE 0x7c
> #define AVC_YELLOW 0x7c
>
> +#define AVC_VENDOR_UNIQUE 0x7e
> +
> +#define AVC_VENDOR_NEXT_GROUP 0x00
> +#define AVC_VENDOR_PREV_GROUP 0x01
> +
> struct avctp;
>
> typedef bool (*avctp_passthrough_cb) (struct avctp *session,
> @@ -159,7 +164,8 @@ unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
> bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
> unsigned int id);
>
> -int avctp_send_passthrough(struct avctp *session, uint8_t op);
> +int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
> + size_t params_len);
> int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
> uint8_t code, uint8_t subunit,
> uint8_t *operands, size_t operand_count);
> diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
> index 5400f80..2cdd1e0 100644
> --- a/android/avrcp-lib.c
> +++ b/android/avrcp-lib.c
> @@ -471,3 +471,15 @@ int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
> AVC_SUBUNIT_PANEL, AVRCP_REGISTER_NOTIFICATION,
> params, params_len);
> }
> +
> +int avrcp_send_passthrough_vendor(struct avrcp *session, uint8_t vendor_op,
> + uint16_t vendor_id)
> +{
> + uint8_t params[5];
> +
> + hton24(params, vendor_id);
> + bt_put_be16(vendor_op, ¶ms[3]);
> +
> + return avctp_send_passthrough(session->conn, AVC_VENDOR_UNIQUE, params,
> + sizeof(params));
> +}
Looks like this the type of vendor_id should uint32 to be used with
hton24, also I would turn this into a generic avrcp_send_passthrough
which from AV/C perspective is a vendor unique anyway so the function
would look like this:
int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op);
If vendor is not set e.g. 0 then we can probably treat as a regular
passthrough operation otherwise send it as AVC_VENDOR_UNIQUE. Btw make
this into 2 patches, one introducing the changes to
avctp_send_passthrough and another for adding avrcp_send_passthrough.
> diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
> index 91a7d47..3a2012a 100644
> --- a/android/avrcp-lib.h
> +++ b/android/avrcp-lib.h
> @@ -164,3 +164,5 @@ int avrcp_get_element_attrs_rsp(struct avrcp *session, uint8_t transaction,
> int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
> uint8_t code, uint8_t *params,
> size_t params_len);
> +int avrcp_send_passthrough_vendor(struct avrcp *session, uint8_t vendor_op,
> + uint16_t vendor_id);
> --
> 1.8.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v4 1/2] android/gatt: Handle Register gatt client command
From: Szymon Janc @ 2014-03-12 13:09 UTC (permalink / raw)
To: Grzegorz Kolodziejczyk; +Cc: linux-bluetooth
In-Reply-To: <1394616458-5212-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>
Hi Grzegorz,
On Wednesday 12 of March 2014 10:27:37 Grzegorz Kolodziejczyk wrote:
> This adds register gatt client app command handling.
> ---
> android/gatt.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 53 insertions(+), 2 deletions(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index ce85af4..34549dd 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -31,20 +31,71 @@
> #include <glib.h>
>
> #include "ipc.h"
> +#include "ipc-common.h"
> #include "lib/bluetooth.h"
> #include "gatt.h"
> #include "src/log.h"
> #include "hal-msg.h"
>
> +struct gatt_client {
> + int32_t id;
> + uint8_t uuid[16];
> +};
> +
> static struct ipc *hal_ipc = NULL;
> static bdaddr_t adapter_addr;
> +static GSList *gatt_clients = NULL;
> +
> +static int find_client_by_uuid(gconstpointer data, gconstpointer user_data)
> +{
> + const uint8_t *exp_uuid = user_data;
> + const struct gatt_client *client = data;
> +
> + return memcmp(exp_uuid, client->uuid, sizeof(client->uuid));
> +}
>
> static void handle_client_register(const void *buf, uint16_t len)
> {
> + const struct hal_cmd_gatt_client_register *cmd = buf;
> + struct hal_ev_gatt_client_register_client ev;
> + struct gatt_client *client;
> + static int32_t client_cnt = 1;
> + uint8_t status;
> +
> DBG("");
>
> - ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT, HAL_OP_GATT_CLIENT_REGISTER,
> - HAL_STATUS_FAILED);
> + if (!cmd->uuid) {
> + error("gatt: no uuid received");
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + if (g_slist_find_custom(gatt_clients, &cmd->uuid,
> + find_client_by_uuid)) {
> + error("gatt: client uuid is already on list");
> + status = HAL_STATUS_FAILED;
> + goto failed;
> + }
> +
> + client = g_new0(struct gatt_client, 1);
> + memcpy(client->uuid, cmd->uuid, sizeof(client->uuid));
> +
> + client->id = client_cnt++;
> +
> + gatt_clients = g_slist_prepend(gatt_clients, client);
> +
> + status = HAL_STATUS_SUCCESS;
> +
> + ev.status = status;
> + ev.client_if = client->id;
> + memcpy(ev.app_uuid, client->uuid, sizeof(client->uuid));
> +
> + ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT,
> + HAL_EV_GATT_CLIENT_REGISTER_CLIENT, sizeof(ev), &ev);
> +
> +failed:
> + ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_GATT,
> + HAL_OP_GATT_CLIENT_REGISTER, status);
> }
>
> static void handle_client_unregister(const void *buf, uint16_t len)
>
Both Patches applied. Thanks.
--
Best regards,
Szymon Janc
^ permalink raw reply
* [PATCH 1/2] android/pixit: Set phone number type
From: Sebastian Chlad @ 2014-03-12 13:12 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Sebastian Chlad
Phone number type should be set accordingly.
---
android/pixit-hfp.txt | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/android/pixit-hfp.txt b/android/pixit-hfp.txt
index 3b04cbe..f539e07 100644
--- a/android/pixit-hfp.txt
+++ b/android/pixit-hfp.txt
@@ -5,6 +5,7 @@ PTS version: 5.0
* - different than PTS defaults
& - should be set to IUT Bluetooth address
# - should be set to the respective phone numbers
+^ - should be set according to the reported phone number's type
Required PIXIT settings
-------------------------------------------------------------------------------
@@ -17,8 +18,8 @@ TSPX_ag_class_of_device 400204
TSPX_packet_type_sco 00A0
TSPX_phone_number 1234567 (#)
TSPX_second_phone_number 7654321 (#)
-TSPX_phone_number_type 129
-TSPX_second_phone_number_type 129
+TSPX_phone_number_type 145 (*^)
+TSPX_second_phone_number_type 145 (*^)
TSPX_phone_number_memory 1
TSPX_phone_number_memory_invalid_index 9999
TSPX_scan_all_memory_dial_locations FALSE
--
1.8.5.3
^ permalink raw reply related
* [PATCH 2/2] android/pts: Add HFP PTS tests results
From: Sebastian Chlad @ 2014-03-12 13:12 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Sebastian Chlad
In-Reply-To: <1394629949-13166-1-git-send-email-sebastian.chlad@tieto.com>
Adding PTS test results for HFP 1.6
---
android/Makefile.am | 3 +-
android/pts-hfp.txt | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 227 insertions(+), 1 deletion(-)
create mode 100644 android/pts-hfp.txt
diff --git a/android/Makefile.am b/android/Makefile.am
index bbd3d2f..330529f 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -218,4 +218,5 @@ EXTRA_DIST += android/Android.mk android/README \
android/pts-a2dp.txt \
android/pts-avrcp.txt \
android/pts-avctp.txt \
- android/pts-pbap.txt
+ android/pts-pbap.txt \
+ android/pts-hfp.txt
diff --git a/android/pts-hfp.txt b/android/pts-hfp.txt
new file mode 100644
index 0000000..719039a
--- /dev/null
+++ b/android/pts-hfp.txt
@@ -0,0 +1,225 @@
+PTS test results for HFP
+
+PTS version: 5.0
+Tested: 11-Mar-2014
+Android version: 4.4.2
+
+Results:
+PASS test passed
+FAIL test failed
+INC test is inconclusive
+N/A test is disabled due to PICS setup
+
+-------------------------------------------------------------------------------
+Test Name Result Notes
+-------------------------------------------------------------------------------
+TC_AG_OOR_BV_01_I PASS
+TC_AG_OOR_BV_02_I PASS
+TC_AG_TRS_BV_01_I PASS
+TC_AG_PSI_BV_01_I PASS
+TC_AG_PSI_BV_02_I N/A
+TC_AG_PSI_BV_03_I PASS
+TC_AG_PSI_BV_04_I PASS
+TC_AG_PSI_BV_05_I PASS
+TC_AG_ACS_BV_02_I N/A
+TC_AG_ACS_BV_04_I PASS
+TC_AG_ACS_BV_06_I N/A
+TC_AG_ACS_BV_08_I PASS
+TC_AG_ACS_BV_10_I N/A
+TC_AG_ACS_BV_11_I PASS
+TC_AG_ACS_BI_14_I PASS
+TC_AG_ACR_BV_01_I PASS
+TC_AG_ACR_BV_02_I PASS
+TC_AG_CLI_BV_01_I PASS
+TC_AG_ICA_BV_01_I N/A
+TC_AG_ICA_BV_02_I N/A
+TC_AG_ICA_BV_04_I PASS
+TC_AG_ICA_BV_05_I N/A
+TC_AG_ICA_BV_06_I PASS
+TC_AG_ICR_BV_01_I PASS
+TC_AG_ICR_BV_02_I PASS
+TC_AG_TCA_BV_01_I PASS
+TC_AG_TCA_BV_02_I PASS
+TC_AG_TCA_BV_03_I PASS
+TC_AG_TCA_BV_04_I PASS
+TC_AG_TCA_BV_05_I PASS
+TC_AG_ATH_BV_03_I PASS
+TC_AG_ATH_BV_04_I PASS
+TC_AG_ATH_BV_05_I PASS
+TC_AG_ATH_BV_06_I PASS
+TC_AG_ATA_BV_01_I PASS
+TC_AG_ATA_BV_02_I PASS
+TC_AG_OCN_BV_01_I PASS
+TC_AG_OCM_BV_01_I PASS
+TC_AG_OCM_BV_02_I PASS
+TC_AG_OCL_BV_01_I PASS
+TC_AG_OCL_BV_02_I PASS
+TC_AG_TWC_BV_01_I INC Not yet implemented
+TC_AG_TWC_BV_02_I INC Not yet implemented
+TC_AG_TWC_BV_03_I INC Not yet implemented
+TC_AG_TWC_BV_04_I INC Not yet implemented
+TC_AG_TWC_BV_05_I INC Not yet implemented
+TC_AG_TWC_BV_06_I N/A
+TC_AG_CIT_BV_01_I PASS
+TC_AG_ENO_BV_01_I PASS
+TC_AG_ENO_BV_02_I N/A
+TC_AG_VRA_BV_01_I PASS
+TC_AG_VRA_BV_02_I N/A
+TC_AG_VRA_BI_01_I N/A
+TC_AG_VRD_BV_01_I PASS
+TC_AG_VTG_BV_01_I N/A
+TC_AG_TDC_BV_01_I PASS
+TC_AG_RSV_BV_01_I PASS
+TC_AG_RSV_BV_02_I PASS
+TC_AG_RSV_BV_03_I PASS
+TC_AG_RMV_BV_01_I N/A
+TC_AG_RMV_BV_02_I N/A
+TC_AG_RMV_BV_03_I N/A
+TC_AG_ECS_BV_01_I PASS
+TC_AG_ECS_BV_02_I PASS
+TC_AG_ECS_BV_03_I PASS
+TC_AG_ECC_BV_01_I N/A
+TC_AG_ECC_BV_02_I N/A
+TC_AG_ECC_BI_03_I PASS
+TC_AG_ECC_BI_04_I PASS
+TC_AG_RHH_BV_01_I N/A
+TC_AG_RHH_BV_02_I N/A
+TC_AG_RHH_BV_03_I N/A
+TC_AG_RHH_BV_04_I N/A
+TC_AG_RHH_BV_05_I N/A
+TC_AG_RHH_BV_06_I N/A
+TC_AG_RHH_BV_07_I N/A
+TC_AG_RHH_BV_08_I N/A
+TC_AG_NUM_BV_01_I PASS
+TC_AG_SLC_BV_01_C PASS
+TC_AG_SLC_BV_02_C PASS
+TC_AG_SLC_BV_03_C PASS
+TC_AG_SLC_BV_04_C PASS
+TC_AG_SLC_BV_05_I N/A
+TC_AG_SLC_BV_06_I N/A
+TC_AG_SLC_BV_07_I N/A
+TC_AG_ACC_BV_08_I N/A
+TC_AG_ACC_BV_09_I N/A
+TC_AG_ACC_BV_10_I N/A
+TC_AG_ACC_BV_11_I N/A
+TC_AG_ACC_BI_12_I N/A
+TC_AG_ACC_BI_13_I N/A
+TC_AG_ACC_BI_14_I N/A
+TC_AG_ACC_BV_15_I N/A
+TC_AG_WBS_BV_01_I N/A
+TC_AG_DIS_BV_01_I PASS
+TC_AG_SDP_BV_01_I PASS
+TC_AG_IIA_BV_01_I PASS
+TC_AG_IIA_BV_02_I PASS
+TC_AG_IIA_BV_03_I N/A
+TC_AG_IIA_BV_05_I PASS
+TC_AG_IID_BV_01_I PASS
+TC_AG_IID_BV_02_I N/A
+TC_AG_IID_BV_03_I PASS
+TC_AG_IID_BV_04_I PASS
+TC_AG_IIC_BV_01_I PASS
+TC_AG_IIC_BV_02_I PASS
+TC_AG_IIC_BV_03_I PASS
+
+TC_HF_OOR_BV_01_I N/A
+TC_HF_OOR_BV_02_I N/A
+TC_HF_TRS_BV_01_I N/A
+TC_HF_PSI_BV_01_I N/A
+TC_HF_PSI_BV_02_I N/A
+TC_HF_PSI_BV_03_I N/A
+TC_HF_PSI_BV_04_I N/A
+TC_HF_ACS_BV_01_I N/A
+TC_HF_ACS_BV_03_I N/A
+TC_HF_ACS_BV_05_I N/A
+TC_HF_ACS_BV_07_I N/A
+TC_HF_ACS_BV_09_I N/A
+TC_HF_ACS_BV_12_I N/A
+TC_HF_ACS_BI_13_I N/A
+TC_HF_ACR_BV_01_I N/A
+TC_HF_ACR_BV_02_I N/A
+TC_HF_CLI_BV_01_I N/A
+TC_HF_ICA_BV_01_I N/A
+TC_HF_ICA_BV_02_I N/A
+TC_HF_ICA_BV_03_I N/A
+TC_HF_ICA_BV_04_I N/A
+TC_HF_ICA_BV_05_I N/A
+TC_HF_ICA_BV_06_I N/A
+TC_HF_ICA_BV_07_I N/A
+TC_HF_ICR_BV_01_I N/A
+TC_HF_ICR_BV_02_I N/A
+TC_HF_TCA_BV_01_I N/A
+TC_HF_TCA_BV_02_I N/A
+TC_HF_TCA_BV_03_I N/A
+TC_HF_TCA_BV_04_I N/A
+TC_HF_ATH_BV_03_I N/A
+TC_HF_ATH_BV_04_I N/A
+TC_HF_ATH_BV_05_I N/A
+TC_HF_ATH_BV_06_I N/A
+TC_HF_ATH_BV_09_I N/A
+TC_HF_ATA_BV_01_I N/A
+TC_HF_ATA_BV_02_I N/A
+TC_HF_ATA_BV_03_I N/A
+TC_HF_OCN_BV_01_I N/A
+TC_HF_OCM_BV_01_I N/A
+TC_HF_OCM_BV_02_I N/A
+TC_HF_OCL_BV_01_I N/A
+TC_HF_OCL_BV_02_I N/A
+TC_HF_TWC_BV_01_I N/A
+TC_HF_TWC_BV_02_I N/A
+TC_HF_TWC_BV_03_I N/A
+TC_HF_TWC_BV_04_I N/A
+TC_HF_TWC_BV_05_I N/A
+TC_HF_TWC_BV_06_I N/A
+TC_HF_CIT_BV_01_I N/A
+TC_HF_ENO_BV_01_I N/A
+TC_HF_VRA_BV_01_I N/A
+TC_HF_VRA_BV_02_I N/A
+TC_HF_VRA_BV_03_I N/A
+TC_HF_VRD_BV_01_I N/A
+TC_HF_VTG_BV_01_I N/A
+TC_HF_TDC_BV_01_I N/A
+TC_HF_RSV_BV_01_I N/A
+TC_HF_RSV_BV_02_I N/A
+TC_HF_RSV_BV_03_I N/A
+TC_HF_RMV_BV_01_I N/A
+TC_HF_RMV_BV_02_I N/A
+TC_HF_RMV_BV_03_I N/A
+TC_HF_ECS_BV_01_I N/A
+TC_HF_ECS_BV_02_I N/A
+TC_HF_ECS_BV_03_I N/A
+TC_HF_ECC_BV_01_I N/A
+TC_HF_ECC_BV_02_I N/A
+TC_HF_RHH_BV_01_I N/A
+TC_HF_RHH_BV_02_I N/A
+TC_HF_RHH_BV_03_I N/A
+TC_HF_RHH_BV_04_I N/A
+TC_HF_RHH_BV_05_I N/A
+TC_HF_RHH_BV_06_I N/A
+TC_HF_RHH_BV_07_I N/A
+TC_HF_RHH_BV_08_I N/A
+TC_HF_NUM_BV_01_I N/A
+TC_HF_NUM_BI_01_I N/A
+TC_HF_SLC_BV_01_C N/A
+TC_HF_SLC_BV_02_C N/A
+TC_HF_SLC_BV_03_C N/A
+TC_HF_SLC_BV_04_C N/A
+TC_HF_SLC_BV_05_I N/A
+TC_HF_SLC_BV_06_I N/A
+TC_HF_SLC_BV_08_I N/A
+TC_HF_ACC_BV_01_I N/A
+TC_HF_ACC_BV_02_I N/A
+TC_HF_ACC_BV_03_I N/A
+TC_HF_ACC_BV_04_I N/A
+TC_HF_ACC_BV_05_I N/A
+TC_HF_ACC_BV_06_I N/A
+TC_HF_ACC_BV_07_I N/A
+TC_HF_WBS_BV_02_I N/A
+TC_HF_WBS_BV_03_I N/A
+TC_HF_DIS_BV_01_I N/A
+TC_HF_DIS_BV_02_I N/A
+TC_HF_SDP_BV_01_I N/A
+TC_HF_SDP_BV_02_C N/A
+TC_HF_SDP_BV_03_C N/A
+TC_HF_ATAH_BV_01_I N/A
+TC_HF_OCA_BV_01_I N/A
+TC_HF_IIA_BV_04_I N/A
--
1.8.5.3
^ permalink raw reply related
* [PATCH BlueZ] android/avrcp-lib: Change API to register callbacks instead of PDU handlers
From: Luiz Augusto von Dentz @ 2014-03-12 13:19 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds avrcp_register_player function to register callbacks for
requests and responses, the fundamental difference is that the
callbacks are called after the original PDU is parsed and the parameter
are converted to host byte order making us able to unit test the
parsing itself.
---
android/avrcp-lib.c | 23 +++++++++++++++++
android/avrcp-lib.h | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 96 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index befc404..953674b 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -73,6 +73,7 @@ struct avrcp_header {
struct avrcp {
struct avctp *conn;
+ struct avrcp_player *player;
size_t tx_mtu;
uint8_t *tx_buf;
@@ -89,6 +90,13 @@ struct avrcp {
void *destroy_data;
};
+struct avrcp_player {
+ const struct avrcp_control_ind *ind;
+ const struct avrcp_control_cfm *cfm;
+
+ void *user_data;
+};
+
void avrcp_shutdown(struct avrcp *session)
{
if (session->conn) {
@@ -249,6 +257,21 @@ void avrcp_set_destroy_cb(struct avrcp *session, avrcp_destroy_cb_t cb,
session->destroy_data = user_data;
}
+void avrcp_register_player(struct avrcp *session,
+ const struct avrcp_control_ind *ind,
+ const struct avrcp_control_cfm *cfm,
+ void *user_data)
+{
+ struct avrcp_player *player;
+
+ player = g_new0(struct avrcp_player, 1);
+ player->ind = ind;
+ player->cfm = cfm;
+ player->user_data = user_data;
+
+ session->player = player;
+}
+
void avrcp_set_control_handlers(struct avrcp *session,
const struct avrcp_control_handler *handlers,
void *user_data)
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 91a7d47..62c989d 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -99,6 +99,74 @@ struct avrcp_control_handler {
uint16_t params_len, uint8_t *params, void *user_data);
};
+struct avrcp_control_ind {
+ int (*get_capabilities) (struct avrcp *session,
+ uint8_t transaction, void *user_data);
+ int (*list_attributes) (struct avrcp *session,
+ uint8_t transaction, void *user_data);
+ int (*get_attribute_text) (struct avrcp *session, uint8_t transaction,
+ uint16_t number, uint8_t *attrs,
+ void *user_data);
+ int (*list_values) (struct avrcp *session, uint8_t transaction,
+ uint8_t attr, void *user_data);
+ int (*get_value_text) (struct avrcp *session, uint8_t transaction,
+ uint8_t attr, void *user_data);
+ int (*get_value) (struct avrcp *session, uint8_t transaction,
+ uint16_t number, uint8_t *attrs,
+ void *user_data);
+ int (*set_value) (struct avrcp *session, uint8_t transaction,
+ uint16_t number, uint8_t *attrs,
+ void *user_data);
+ int (*get_play_status) (struct avrcp *session, uint8_t transaction,
+ void *user_data);
+ int (*get_element_attributes) (struct avrcp *session,
+ uint8_t transaction, uint8_t number,
+ uint32_t *attrs, void *user_data);
+ int (*register_notification) (struct avrcp *session,
+ uint8_t transaction, uint8_t event,
+ uint32_t interval, void *user_data);
+};
+
+struct avrcp_element {
+ uint32_t attr;
+ char *value;
+};
+
+struct avrcp_control_cfm {
+ void (*get_capabilities) (struct avrcp *session, int err,
+ uint8_t *events, void *user_data);
+ void (*list_attributes) (struct avrcp *session, int err,
+ uint8_t number, uint8_t *attrs,
+ void *user_data);
+ void (*get_attribute_text) (struct avrcp *session, int err,
+ uint16_t number, uint8_t *attrs,
+ void *user_data);
+ void (*list_values) (struct avrcp *session, int err,
+ uint8_t number, uint8_t *values,
+ void *user_data);
+ void (*get_value_text) (struct avrcp *session, int err,
+ const char *value, void *user_data);
+ void (*get_value) (struct avrcp *session, int err,
+ uint16_t number, uint8_t *attrs,
+ void *user_data);
+ void (*set_value) (struct avrcp *session, int err,
+ uint16_t number, uint8_t *attrs,
+ void *user_data);
+ void (*get_play_status) (struct avrcp *session, int err,
+ uint32_t position, uint32_t duration,
+ void *user_data);
+ void (*get_element_attributes) (struct avrcp *session, int err,
+ const GSList *elements,
+ void *user_data);
+ void (*status_changed) (struct avrcp *session, int err,
+ uint8_t status, void *user_data);
+ void (*track_changed) (struct avrcp *session, int err,
+ uint64_t uid, void *user_data);
+ void (*settings_changed) (struct avrcp *session, int err,
+ uint8_t number, uint8_t *attrs,
+ void *user_data);
+};
+
struct avrcp_passthrough_handler {
uint8_t op;
bool (*func) (struct avrcp *session, bool pressed, void *user_data);
@@ -122,6 +190,11 @@ struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
void avrcp_shutdown(struct avrcp *session);
void avrcp_set_destroy_cb(struct avrcp *session, avrcp_destroy_cb_t cb,
void *user_data);
+
+void avrcp_register_player(struct avrcp *session,
+ const struct avrcp_control_ind *ind,
+ const struct avrcp_control_cfm *cfm,
+ void *user_data);
void avrcp_set_control_handlers(struct avrcp *session,
const struct avrcp_control_handler *handlers,
void *user_data);
--
1.8.5.3
^ permalink raw reply related
* Re: [PATCH BlueZ] android/avrcp-lib: Change API to register callbacks instead of PDU handlers
From: Andrei Emeltchenko @ 2014-03-12 14:02 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1394630342-32469-1-git-send-email-luiz.dentz@gmail.com>
Hi Luiz,
On Wed, Mar 12, 2014 at 03:19:02PM +0200, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This adds avrcp_register_player function to register callbacks for
> requests and responses, the fundamental difference is that the
> callbacks are called after the original PDU is parsed and the parameter
> are converted to host byte order making us able to unit test the
> parsing itself.
> ---
> android/avrcp-lib.c | 23 +++++++++++++++++
> android/avrcp-lib.h | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 96 insertions(+)
>
> diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
> index befc404..953674b 100644
> --- a/android/avrcp-lib.c
> +++ b/android/avrcp-lib.c
> @@ -73,6 +73,7 @@ struct avrcp_header {
>
> struct avrcp {
> struct avctp *conn;
> + struct avrcp_player *player;
>
> size_t tx_mtu;
> uint8_t *tx_buf;
> @@ -89,6 +90,13 @@ struct avrcp {
> void *destroy_data;
> };
>
> +struct avrcp_player {
> + const struct avrcp_control_ind *ind;
> + const struct avrcp_control_cfm *cfm;
> +
> + void *user_data;
> +};
> +
> void avrcp_shutdown(struct avrcp *session)
> {
> if (session->conn) {
> @@ -249,6 +257,21 @@ void avrcp_set_destroy_cb(struct avrcp *session, avrcp_destroy_cb_t cb,
> session->destroy_data = user_data;
> }
>
> +void avrcp_register_player(struct avrcp *session,
> + const struct avrcp_control_ind *ind,
> + const struct avrcp_control_cfm *cfm,
> + void *user_data)
> +{
> + struct avrcp_player *player;
> +
> + player = g_new0(struct avrcp_player, 1);
where do you free it?
Best regards
Andrei Emeltchenko
> + player->ind = ind;
> + player->cfm = cfm;
> + player->user_data = user_data;
> +
> + session->player = player;
> +}
> +
> void avrcp_set_control_handlers(struct avrcp *session,
> const struct avrcp_control_handler *handlers,
> void *user_data)
> diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
> index 91a7d47..62c989d 100644
> --- a/android/avrcp-lib.h
> +++ b/android/avrcp-lib.h
> @@ -99,6 +99,74 @@ struct avrcp_control_handler {
> uint16_t params_len, uint8_t *params, void *user_data);
> };
>
> +struct avrcp_control_ind {
> + int (*get_capabilities) (struct avrcp *session,
> + uint8_t transaction, void *user_data);
> + int (*list_attributes) (struct avrcp *session,
> + uint8_t transaction, void *user_data);
> + int (*get_attribute_text) (struct avrcp *session, uint8_t transaction,
> + uint16_t number, uint8_t *attrs,
> + void *user_data);
> + int (*list_values) (struct avrcp *session, uint8_t transaction,
> + uint8_t attr, void *user_data);
> + int (*get_value_text) (struct avrcp *session, uint8_t transaction,
> + uint8_t attr, void *user_data);
> + int (*get_value) (struct avrcp *session, uint8_t transaction,
> + uint16_t number, uint8_t *attrs,
> + void *user_data);
> + int (*set_value) (struct avrcp *session, uint8_t transaction,
> + uint16_t number, uint8_t *attrs,
> + void *user_data);
> + int (*get_play_status) (struct avrcp *session, uint8_t transaction,
> + void *user_data);
> + int (*get_element_attributes) (struct avrcp *session,
> + uint8_t transaction, uint8_t number,
> + uint32_t *attrs, void *user_data);
> + int (*register_notification) (struct avrcp *session,
> + uint8_t transaction, uint8_t event,
> + uint32_t interval, void *user_data);
> +};
> +
> +struct avrcp_element {
> + uint32_t attr;
> + char *value;
> +};
> +
> +struct avrcp_control_cfm {
> + void (*get_capabilities) (struct avrcp *session, int err,
> + uint8_t *events, void *user_data);
> + void (*list_attributes) (struct avrcp *session, int err,
> + uint8_t number, uint8_t *attrs,
> + void *user_data);
> + void (*get_attribute_text) (struct avrcp *session, int err,
> + uint16_t number, uint8_t *attrs,
> + void *user_data);
> + void (*list_values) (struct avrcp *session, int err,
> + uint8_t number, uint8_t *values,
> + void *user_data);
> + void (*get_value_text) (struct avrcp *session, int err,
> + const char *value, void *user_data);
> + void (*get_value) (struct avrcp *session, int err,
> + uint16_t number, uint8_t *attrs,
> + void *user_data);
> + void (*set_value) (struct avrcp *session, int err,
> + uint16_t number, uint8_t *attrs,
> + void *user_data);
> + void (*get_play_status) (struct avrcp *session, int err,
> + uint32_t position, uint32_t duration,
> + void *user_data);
> + void (*get_element_attributes) (struct avrcp *session, int err,
> + const GSList *elements,
> + void *user_data);
> + void (*status_changed) (struct avrcp *session, int err,
> + uint8_t status, void *user_data);
> + void (*track_changed) (struct avrcp *session, int err,
> + uint64_t uid, void *user_data);
> + void (*settings_changed) (struct avrcp *session, int err,
> + uint8_t number, uint8_t *attrs,
> + void *user_data);
> +};
> +
> struct avrcp_passthrough_handler {
> uint8_t op;
> bool (*func) (struct avrcp *session, bool pressed, void *user_data);
> @@ -122,6 +190,11 @@ struct avrcp *avrcp_new(int fd, size_t imtu, size_t omtu, uint16_t version);
> void avrcp_shutdown(struct avrcp *session);
> void avrcp_set_destroy_cb(struct avrcp *session, avrcp_destroy_cb_t cb,
> void *user_data);
> +
> +void avrcp_register_player(struct avrcp *session,
> + const struct avrcp_control_ind *ind,
> + const struct avrcp_control_cfm *cfm,
> + void *user_data);
> void avrcp_set_control_handlers(struct avrcp *session,
> const struct avrcp_control_handler *handlers,
> void *user_data);
> --
> 1.8.5.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCHv4 1/9] android/avctp: Add parameters to avctp passthrough send
From: Andrei Emeltchenko @ 2014-03-12 14:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <CABBYNZL5hjJzaxsnXtrHTzJSHSKYjemUnUr=YRE4Zq9qCmoj0g@mail.gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
This allows to use vendor unique commands
---
android/avctp.c | 74 ++++++++++++++++++++++++++++++++++++++++++++-------------
android/avctp.h | 8 ++++++-
2 files changed, 65 insertions(+), 17 deletions(-)
diff --git a/android/avctp.c b/android/avctp.c
index d970250..e9ba6db 100644
--- a/android/avctp.c
+++ b/android/avctp.c
@@ -159,6 +159,8 @@ struct avctp_channel {
struct key_pressed {
uint8_t op;
+ uint8_t *params;
+ size_t params_len;
guint timer;
};
@@ -1172,25 +1174,38 @@ static const char *op2str(uint8_t op)
return "UNKNOWN";
}
-static int avctp_passthrough_press(struct avctp *session, uint8_t op)
+static int avctp_passthrough_press(struct avctp *session, uint8_t op,
+ uint8_t *params, size_t params_len)
{
- uint8_t operands[2];
+ uint8_t operands[7];
+ size_t len;
- DBG("%s", op2str(op));
+ DBG("op 0x%02x %s params_len %zd", op, op2str(op), params_len);
/* Button pressed */
operands[0] = op & 0x7f;
- operands[1] = 0;
+
+ if (op == AVC_VENDOR_UNIQUE && params &&
+ params_len == 5) {
+ memcpy(&operands[2], params, params_len);
+ len = params_len + 2;
+ operands[1] = params_len;
+ } else {
+ len = 2;
+ operands[1] = 0;
+ }
return avctp_send_req(session, AVC_CTYPE_CONTROL,
AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
- operands, sizeof(operands),
+ operands, len,
avctp_passthrough_rsp, NULL);
}
-static int avctp_passthrough_release(struct avctp *session, uint8_t op)
+static int avctp_passthrough_release(struct avctp *session, uint8_t op,
+ uint8_t *params, size_t params_len)
{
- uint8_t operands[2];
+ uint8_t operands[7];
+ size_t len;
DBG("%s", op2str(op));
@@ -1198,9 +1213,16 @@ static int avctp_passthrough_release(struct avctp *session, uint8_t op)
operands[0] = op | 0x80;
operands[1] = 0;
+ if (op == AVC_VENDOR_UNIQUE && params &&
+ params_len > sizeof(operands) - 2) {
+ memcpy(&operands[2], params, params_len);
+ len = params_len;
+ } else
+ len = 2;
+
return avctp_send_req(session, AVC_CTYPE_CONTROL,
AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
- operands, sizeof(operands),
+ operands, len,
NULL, NULL);
}
@@ -1208,15 +1230,18 @@ static gboolean repeat_timeout(gpointer user_data)
{
struct avctp *session = user_data;
- avctp_passthrough_release(session, session->key.op);
- avctp_passthrough_press(session, session->key.op);
+ avctp_passthrough_release(session, session->key.op, session->key.params,
+ session->key.params_len);
+ avctp_passthrough_press(session, session->key.op, session->key.params,
+ session->key.params_len);
return TRUE;
}
static void release_pressed(struct avctp *session)
{
- avctp_passthrough_release(session, session->key.op);
+ avctp_passthrough_release(session, session->key.op, session->key.params,
+ session->key.params_len);
if (session->key.timer > 0)
g_source_remove(session->key.timer);
@@ -1224,7 +1249,8 @@ static void release_pressed(struct avctp *session)
session->key.timer = 0;
}
-static bool set_pressed(struct avctp *session, uint8_t op)
+static bool set_pressed(struct avctp *session, uint8_t op, uint8_t *params,
+ size_t params_len)
{
if (session->key.timer > 0) {
if (session->key.op == op)
@@ -1236,6 +1262,8 @@ static bool set_pressed(struct avctp *session, uint8_t op)
return FALSE;
session->key.op = op;
+ session->key.params = params;
+ session->key.params_len = params_len;
session->key.timer = g_timeout_add_seconds(AVC_PRESS_TIMEOUT,
repeat_timeout,
session);
@@ -1247,24 +1275,38 @@ static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
uint8_t subunit, uint8_t *operands,
size_t operand_count, void *user_data)
{
+ uint8_t *params;
+ size_t params_len;
+
+ DBG("code 0x%02x operand_count %zd", code, operand_count);
+
if (code != AVC_CTYPE_ACCEPTED)
return FALSE;
- if (set_pressed(session, operands[0]))
+ if (operands[0] == AVC_VENDOR_UNIQUE) {
+ params = &operands[2];
+ params_len = operand_count - 2;
+ } else {
+ params = NULL;
+ params_len = 0;
+ }
+
+ if (set_pressed(session, operands[0], params, params_len))
return FALSE;
- avctp_passthrough_release(session, operands[0]);
+ avctp_passthrough_release(session, operands[0], params, params_len);
return FALSE;
}
-int avctp_send_passthrough(struct avctp *session, uint8_t op)
+int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
+ size_t params_len)
{
/* Auto release if key pressed */
if (session->key.timer > 0)
release_pressed(session);
- return avctp_passthrough_press(session, op);
+ return avctp_passthrough_press(session, op, params, params_len);
}
int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
diff --git a/android/avctp.h b/android/avctp.h
index 2f419a2..98c1142 100644
--- a/android/avctp.h
+++ b/android/avctp.h
@@ -108,6 +108,11 @@
#define AVC_BLUE 0x7c
#define AVC_YELLOW 0x7c
+#define AVC_VENDOR_UNIQUE 0x7e
+
+#define AVC_VENDOR_NEXT_GROUP 0x00
+#define AVC_VENDOR_PREV_GROUP 0x01
+
struct avctp;
typedef bool (*avctp_passthrough_cb) (struct avctp *session,
@@ -159,7 +164,8 @@ unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
bool avctp_unregister_browsing_pdu_handler(struct avctp *session,
unsigned int id);
-int avctp_send_passthrough(struct avctp *session, uint8_t op);
+int avctp_send_passthrough(struct avctp *session, uint8_t op, uint8_t *params,
+ size_t params_len);
int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
uint8_t code, uint8_t subunit,
uint8_t *operands, size_t operand_count);
--
1.8.3.2
^ permalink raw reply related
* [PATCHv4 2/9] android/avrcp: Add avrcp_send_passthrough function
From: Andrei Emeltchenko @ 2014-03-12 14:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1394635232-23774-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
This function allows to send AVRCP vendor unique commands.
---
android/avrcp-lib.c | 11 +++++++++++
android/avrcp-lib.h | 1 +
2 files changed, 12 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 5400f80..f719a00 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -471,3 +471,14 @@ int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
AVC_SUBUNIT_PANEL, AVRCP_REGISTER_NOTIFICATION,
params, params_len);
}
+
+int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op)
+{
+ uint8_t params[5];
+
+ hton24(params, vendor);
+ bt_put_be16(op, ¶ms[3]);
+
+ return avctp_send_passthrough(session->conn, AVC_VENDOR_UNIQUE, params,
+ sizeof(params));
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 91a7d47..cc6c2ee 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -164,3 +164,4 @@ int avrcp_get_element_attrs_rsp(struct avrcp *session, uint8_t transaction,
int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
uint8_t code, uint8_t *params,
size_t params_len);
+int avrcp_send_passthrough(struct avrcp *session, uint32_t vendor, uint8_t op);
--
1.8.3.2
^ permalink raw reply related
* [PATCHv4 3/9] unit/avrcp: Add /TP/BGN/BV-01-I test
From: Andrei Emeltchenko @ 2014-03-12 14:40 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1394635232-23774-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the Controller can send Next Group command to the
Target.
---
unit/test-avrcp.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 3702d39..f0f36dd 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -636,6 +636,9 @@ static void test_client(gconstpointer data)
AVRCP_EVENT_STATUS_CHANGED, 0,
NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/BGN/BV-01-I"))
+ avrcp_send_passthrough(context->session, IEEEID_BTSIG,
+ AVC_VENDOR_NEXT_GROUP);
execute_context(context);
}
@@ -1030,5 +1033,12 @@ int main(int argc, char *argv[])
0xff, 0x00, 0x00, 0x01,
AVRCP_STATUS_INVALID_COMMAND));
+ /* Next Group command transfer - CT */
+ define_test("/TP/BGN/BV-01-I", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48,
+ AVC_OP_PASSTHROUGH,
+ AVC_VENDOR_UNIQUE, 0x05, 0x00, 0x19,
+ 0x58, 0x00, AVC_VENDOR_NEXT_GROUP));
+
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox