* Re: Controlling LEDs and rumble on sixaxis
From: Antonio Ospite @ 2014-03-04 22:11 UTC (permalink / raw)
To: Andrea; +Cc: linux-bluetooth
In-Reply-To: <53164362.4060102@gmail.com>
Hi Andrea,
On Tue, 04 Mar 2014 21:19:30 +0000
Andrea <mariofutire@gmail.com> wrote:
> Hi,
>
> I would like to be able to control from a client app the LEDs and
> rumble of the sixaxis PS3 controller.
>
> As far as I understand the kernel 3.15 will allow LEDs to be set by
> bluez when the controller is connected. If I wanted to change the
> LEDs in my app, would this something that needs to be done by bluez?
> Can I write to some device and bypass bluez?
With older kernels you can already set LEDs and rumble by sending the
HID output report 01 via hidraw (actually there is a regression
preventing that via BT in some versions). See the code in the BlueZ
sixaxis plugin or in the newer linux kernel for the report format.
With recent/newer kernels you can use the sysfs leds class under
/sys/class/leds/ to control the LEDs and the force feedback api[1] to
control the rumble.
No need to "bypass" BlueZ, the BlueZ sixaxis plugin sets the LEDs when
it detects the controller in order to tell the user the controller
number, but after that you are free to change the LEDs as you want.
[1] https://www.kernel.org/doc/Documentation/input/ff.txt
> Would this be a job for dbus?
>
dbus is not necessary, but depending on your application you may want to
use libudev to add the hotplug detection of the controller.
> I use the sixaxis to control an app on the Pi, and given the lack of
> feedbacks from the Pi, the LEDs and rumble could help me on that
> front.
>
> Does it make sense to do it?
>
Why not?
Ciao,
Antonio
--
Antonio Ospite
http://ao2.it
A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
^ permalink raw reply
* Re: Receiving data in BLE non-connectable undirected advertisements
From: Benjamin Adler @ 2014-03-04 22:02 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <A2B9E0B0-27CE-45EC-A4E8-FB630C17DA14@holtmann.org>
[-- Attachment #1: Type: text/plain, Size: 2008 bytes --]
Marcel,
On 03.03.2014 15:28, Marcel Holtmann wrote:
> maybe you need to just read the HCI part of the Bluetooth Core specification. The tools/ibeacon.c is a perfect example on how to get started with HCI commands. You just need to figure out on how to do scanning instead of advertising.
during the last days, I fought through those 2600 pages, and I think I
now have a rough idea how things might work. The source of my
lescanner.c is attached, and it doesn't work yet. My questions are:
- why do you open urandom, but never use it?
- searching for the reason of "Failed to open HCI user channel", I found
a commit log from you, saying that the HCI user channel means exclusive
access to the device, so I'll have to disable e.g. bluetoothd. Is that a
limitation inherent to bluetooth, or just to bluez? Is there a way to
process those advertisements and still use bluetoothd, e.g. for skype?
- in bt_hci_register(), what is the "bt_hci_destroy_func_t destroy"
parameter used for? It seems it's always null when used in the examples?
- I was hoping that line 134 would cause advertising_report_callback()
to be called when advertisements are received. Unfortunately, that's not
the case, nothing happens. What am I missing?
- I'm also confused by how those btle advertisements are handled, they
seem to be a subevent/subtype of a generic btle event. How can I process
this correctly in advertising_report_callback()?
I'd be grateful if you could give me some hints to some of these questions.
Cheers,
ben
output from lescanner:
# ./tools/lescanner
Low Energy Passive Non-Connectable Undirected Advertisement Scanner 5.15
Registering for command-complete-events...
Registering for advertising-events...
Lets see whether we can provoke an error...
Setting bt event-mask...
Setting bt le event-mask...
Setting bt le scan parameters...
Enabling le scan...
check_error_callback: succeeded
check_error_callback: succeeded
check_error_callback: succeeded
check_error_callback: succeeded
[-- Attachment #2: lescanner.c --]
[-- Type: text/x-csrc, Size: 10396 bytes --]
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include "monitor/mainloop.h"
#include "monitor/bt.h"
#include "src/shared/util.h"
#include "src/shared/hci.h"
static int urandom_fd;
static struct bt_hci *hci_dev;
static void shutdown_timeout(int id, void *user_data)
{
fprintf(stdout, "shutdown_timeout()\n");
mainloop_remove_timeout(id);
mainloop_quit();
}
static void shutdown_complete(const void *data, uint8_t size, void *user_data)
{
fprintf(stdout, "shutdown_complete()\n");
unsigned int id = PTR_TO_UINT(user_data);
shutdown_timeout(id, NULL);
}
static void shutdown_device(void)
{
fprintf(stdout, "shutdown_device()\n");
uint8_t enable = 0x00;
unsigned int id;
bt_hci_flush(hci_dev);
id = mainloop_add_timeout(5, shutdown_timeout, NULL, NULL);
bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_ADV_ENABLE, &enable, 1, NULL, NULL, NULL);
bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0, shutdown_complete, UINT_TO_PTR(id), NULL);
}
static void check_error_callback(const void *data, uint8_t size, void *user_data)
{
uint8_t status = *((uint8_t *) data);
if (status) {
fprintf(stderr, "check_error_callback: error occurred, status is %d\n", status);
shutdown_device();
return;
} else {
fprintf(stdout, "check_error_callback: succeeded\n");
}
}
static void advertising_report_callback(const void *data, uint8_t size, void *user_data)
{
const struct bt_hci_evt_le_adv_report *report_adv = data;
fprintf(stdout, "Received %d reports, event-type %d.\n", report_adv->num_reports, report_adv->event_type);
}
static void command_complete_callback(const void *data, uint8_t size, void *user_data)
{
const struct bt_hci_evt_cmd_complete *report_cmd_complete = data;
fprintf(stdout, "command_complete, ncmd %d, opcode %d.\n", report_cmd_complete->ncmd, report_cmd_complete->opcode);
}
static void local_features_callback(const void *data, uint8_t size, void *user_data)
{
const struct bt_hci_rsp_read_local_features *rsp = data;
if (rsp->status) {
fprintf(stderr, "Failed to read local features\n");
shutdown_device();
return;
}
if (!(rsp->features[4] & 0x40)) {
fprintf(stderr, "Controller without Low Energy support\n");
shutdown_device();
return;
}
//bt_hci_send(hci_dev, BT_HCI_CMD_LE_READ_ADV_TX_POWER, NULL, 0, adv_tx_power_callback, NULL, NULL);
// Register for command_complete events
fprintf(stdout, "Registering for command-complete-events...\n");
bt_hci_register(hci_dev,
BT_HCI_EVT_CMD_COMPLETE,
command_complete_callback, //bt_hci_callback_func_t callback,
NULL, //void *user_data,
NULL //bt_hci_destroy_func_t destroy TODO: ask what this does?
);
// Register for advertising events
fprintf(stdout, "Registering for advertising-events...\n");
bt_hci_register(hci_dev,
BT_HCI_EVT_LE_META_EVENT, // 0x3e is LE META Event, subevent code is 0x02 BT_HCI_EVT_LE_ADV_REPORT ??
advertising_report_callback, //bt_hci_callback_func_t callback,
NULL, //void *user_data,
NULL //bt_hci_destroy_func_t destroy TODO: ask what this does?
);
fprintf(stdout, "Lets see whether we can provoke an error...\n");
bt_hci_register(hci_dev,
0xff, // 0xff seems to be undefined
advertising_report_callback, //bt_hci_callback_func_t callback,
NULL, //void *user_data,
NULL //bt_hci_destroy_func_t destroy TODO: ask what this does?
);
// #define BT_HCI_CMD_SET_EVENT_MASK 0x0c01
// struct bt_hci_cmd_set_event_mask {
// uint8_t mask[8];
// } __attribute__ ((packed));
struct bt_hci_cmd_set_event_mask event_mask;
memset(&event_mask, 0, sizeof(event_mask));
event_mask.mask[0] = 0x20; // receive LE meta events
// There is no BT_HCI_RSP_SET_EVENT_MASK, so we only check for errors in the callback
fprintf(stdout, "Setting bt event-mask...\n");
bt_hci_send(hci_dev, BT_HCI_CMD_SET_EVENT_MASK, &event_mask, sizeof(event_mask), check_error_callback, NULL, NULL);
// #define BT_HCI_CMD_LE_SET_EVENT_MASK 0x2001
// struct bt_hci_cmd_le_set_event_mask {
// uint8_t mask[8];
// } __attribute__ ((packed));
struct bt_hci_cmd_le_set_event_mask event_mask_le;
memset(&event_mask_le, 0, sizeof(event_mask_le));
event_mask_le.mask[7] = 0x2; // receive only le_advertising_reports
// There is no BT_HCI_RSP_LE_SET_EVENT_MASK, so we only check for errors in the callback
fprintf(stdout, "Setting bt le event-mask...\n");
bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_EVENT_MASK, &event_mask_le, sizeof(event_mask_le), check_error_callback, NULL, NULL);
// #define BT_HCI_CMD_LE_SET_SCAN_PARAMETERS 0x200b
// struct bt_hci_cmd_le_set_scan_parameters {
// uint8_t type;
// uint16_t interval;
// uint16_t window;
// uint8_t own_addr_type;
// uint8_t filter_policy;
// } __attribute__ ((packed));
struct bt_hci_cmd_le_set_scan_parameters scan_parameters;
memset(&scan_parameters, 0, sizeof(scan_parameters));
scan_parameters.type = 0; // bt-core-spec 4.1, pdf-page 1255: passive scanning
scan_parameters.interval = 0x0100; // Interval of minimum 0x10 is 16 * 0.625msec => 10 msec. Interval of maximum 0x4000 is 16384 * 0.625msec => 10240msec
scan_parameters.window = 0x0100; // window, must be less than or equal to interval
scan_parameters.own_addr_type = 0x0; // // bt-core-spec 4.1, pdf-page 1256: public address
scan_parameters.filter_policy = 0x0; // // bt-core-spec 4.1, pdf-page 1256: accept all advertisements, not just from whitelist
// There is no BT_HCI_RSP_LE_SET_SCAN_PARAMETERS, so we only check for errors in the callback
fprintf(stdout, "Setting bt le scan parameters...\n");
bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS, &scan_parameters, sizeof(scan_parameters), check_error_callback, NULL, NULL);
/* This is non-le scanning, so we try without first
// #define BT_HCI_CMD_WRITE_SCAN_ENABLE 0x0c1a
// struct bt_hci_cmd_write_scan_enable {
// uint8_t enable;
// } __attribute__ ((packed));
struct bt_hci_cmd_write_scan_enable scan_enable;
memset(&scan_enable, 0, sizeof(bt_hci_cmd_write_scan_enable));
scan_enable.enable = 1; // enable!
// There is no BT_HCI_RSP_WRITE_SCAN_ENABLE, so we only check for errors in the callback
bt_hci_send(hci_dev, BT_HCI_CMD_WRITE_SCAN_ENABLE, &scan_enable, sizeof(bt_hci_cmd_write_scan_enable), check_error_callback, NULL, NULL);
*/
// #define BT_HCI_CMD_LE_SET_SCAN_ENABLE 0x200c
// struct bt_hci_cmd_le_set_scan_enable {
// uint8_t enable;
// uint8_t filter_dup;
// } __attribute__ ((packed));
struct bt_hci_cmd_le_set_scan_enable scan_enable_le;
memset(&scan_enable_le, 0, sizeof(scan_enable_le));
scan_enable_le.enable = 1; // enable!
scan_enable_le.filter_dup = 0; // do not filter out duplicates
// There is no BT_HCI_RSP_LE_SET_SCAN_ENABLE, so we only check for errors in the callback
fprintf(stdout, "Enabling le scan...\n");
bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_SCAN_ENABLE, &scan_enable_le, sizeof(scan_enable_le), check_error_callback, NULL, NULL);
}
static void start_scanning(void)
{
bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0, NULL, NULL, NULL);
#warning: bt-core-spec says not to issue commands while reset-in-progress?
bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0, local_features_callback, NULL, NULL);
}
static void signal_callback(int signum, void *user_data)
{
static bool terminated = false;
switch (signum) {
case SIGINT:
case SIGTERM:
if (!terminated) {
shutdown_device();
terminated = true;
}
break;
}
}
static void usage(void)
{
printf("lescanner - Low Energy Passive Non-Connectable Undirected Advertisement Scanner\n"
"Usage:\n");
printf("\tlescanner [options]\n");
printf("Options:\n"
"\t-i, --index <num> Use specified controller\n"
"\t-h, --help Show help options\n");
}
static const struct option main_options[] = {
{ "index", required_argument, NULL, 'i' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ }
};
int main(int argc, char *argv[])
{
uint16_t index = 0;
const char *str;
sigset_t mask;
int exit_status;
for (;;) {
int opt;
opt = getopt_long(argc, argv, "i:vh", main_options, NULL);
if (opt < 0)
break;
switch (opt) {
case 'i':
if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
str = optarg + 3;
else
str = optarg;
if (!isdigit(*str)) {
usage();
return EXIT_FAILURE;
}
index = atoi(str);
break;
case 'v':
printf("%s\n", VERSION);
return EXIT_SUCCESS;
case 'h':
usage();
return EXIT_SUCCESS;
default:
return EXIT_FAILURE;
}
}
if (argc - optind > 0) {
fprintf(stderr, "Invalid command line parameters\n");
return EXIT_FAILURE;
}
urandom_fd = open("/dev/urandom", O_RDONLY);
if (urandom_fd < 0) {
fprintf(stderr, "Failed to open /dev/urandom device\n");
return EXIT_FAILURE;
}
mainloop_init();
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
mainloop_set_signal(&mask, signal_callback, NULL, NULL);
printf("Low Energy Passive Non-Connectable Undirected Advertisement Scanner %s\n", VERSION);
hci_dev = bt_hci_new_user_channel(index);
if (!hci_dev) {
fprintf(stderr, "Failed to open HCI user channel\n");
exit_status = EXIT_FAILURE;
goto done;
}
start_scanning();
exit_status = mainloop_run();
bt_hci_unref(hci_dev);
done:
close(urandom_fd);
return exit_status;
}
^ permalink raw reply
* Controlling LEDs and rumble on sixaxis
From: Andrea @ 2014-03-04 21:19 UTC (permalink / raw)
To: linux-bluetooth
Hi,
I would like to be able to control from a client app the LEDs and rumble of the sixaxis PS3 controller.
As far as I understand the kernel 3.15 will allow LEDs to be set by bluez when the controller is
connected.
If I wanted to change the LEDs in my app, would this something that needs to be done by bluez? Can I
write to some device and bypass bluez?
Would this be a job for dbus?
I use the sixaxis to control an app on the Pi, and given the lack of feedbacks from the Pi, the LEDs
and rumble could help me on that front.
Does it make sense to do it?
Andrea
^ permalink raw reply
* [PATCH 4/4] android/hal-avrcp: Remove unused code
From: Andrzej Kaczmarek @ 2014-03-04 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1393965804-13866-1-git-send-email-andrzej.kaczmarek@tieto.com>
---
android/hal-avrcp.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/android/hal-avrcp.c b/android/hal-avrcp.c
index a720a1e..5f98f5b 100644
--- a/android/hal-avrcp.c
+++ b/android/hal-avrcp.c
@@ -351,7 +351,6 @@ static int write_text(uint8_t *ptr, uint8_t id, uint8_t *text, size_t *len)
value->len = strnlen((const char *) text, BTRC_MAX_ATTR_STR_LEN);
*len += attr_len;
- ptr += attr_len;
if (value->len + *len > IPC_MTU)
value->len = IPC_MTU - *len;
--
1.9.0
^ permalink raw reply related
* [PATCH 3/4] android/avrcp: Fix PDU length calculation
From: Andrzej Kaczmarek @ 2014-03-04 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1393965804-13866-1-git-send-email-andrzej.kaczmarek@tieto.com>
---
android/avrcp.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/android/avrcp.c b/android/avrcp.c
index a763b88..e428486 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -167,25 +167,28 @@ static void handle_get_player_values_text(const void *buf, uint16_t len)
HAL_OP_AVRCP_GET_PLAYER_VALUES_TEXT, HAL_STATUS_FAILED);
}
-static void write_element_text(uint8_t id, uint8_t text_len, uint8_t *text,
- uint8_t *pdu, size_t *len)
+static size_t write_element_text(uint8_t id, uint8_t text_len, uint8_t *text,
+ uint8_t *pdu)
{
uint16_t charset = 106;
+ size_t len = 0;
bt_put_be32(id, pdu);
pdu += 4;
- *len += 4;
+ len += 4;
bt_put_be16(charset, pdu);
pdu += 2;
- *len += 2;
+ len += 2;
bt_put_be16(text_len, pdu);
pdu += 2;
- *len += 2;
+ len += 2;
memcpy(pdu, text, text_len);
- *len += text_len;
+ len += text_len;
+
+ return len;
}
static void write_element_attrs(uint8_t *ptr, uint8_t number, uint8_t *pdu,
@@ -199,11 +202,13 @@ static void write_element_attrs(uint8_t *ptr, uint8_t number, uint8_t *pdu,
for (i = 0; i < number; i++) {
struct hal_avrcp_player_setting_text *text = (void *) ptr;
+ size_t ret;
- write_element_text(text->id, text->len, text->text, pdu, len);
+ ret = write_element_text(text->id, text->len, text->text, pdu);
ptr += sizeof(*text) + text->len;
- pdu += *len;
+ pdu += ret;
+ *len += ret;
}
}
--
1.9.0
^ permalink raw reply related
* [PATCH 2/4] android/avrcp: Fix RegisterNotification response handling
From: Andrzej Kaczmarek @ 2014-03-04 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1393965804-13866-1-git-send-email-andrzej.kaczmarek@tieto.com>
For INTERIM RegisterNotification response we should keep request on
list since it will be needed for CHANGED response.
Requests on lists shall be matched by both pdu_id and event_id since we
can have multiple queued RegisterNotification requests and will need to
reply with proper transaction label.
---
android/avrcp.c | 67 ++++++++++++++++++++++++++++++++++-----------------------
1 file changed, 40 insertions(+), 27 deletions(-)
diff --git a/android/avrcp.c b/android/avrcp.c
index f3427a3..a763b88 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -58,6 +58,7 @@ static struct ipc *hal_ipc = NULL;
struct avrcp_request {
struct avrcp_device *dev;
uint8_t pdu_id;
+ uint8_t event_id;
uint8_t transaction;
};
@@ -68,7 +69,8 @@ struct avrcp_device {
GQueue *queue;
};
-static struct avrcp_request *pop_request(uint8_t pdu_id)
+static struct avrcp_request *pop_request(uint8_t pdu_id, uint8_t event_id,
+ bool peek)
{
GSList *l;
@@ -80,10 +82,13 @@ static struct avrcp_request *pop_request(uint8_t pdu_id)
for (i = 0; reqs; reqs = g_list_next(reqs), i++) {
struct avrcp_request *req = reqs->data;
- if (req->pdu_id == pdu_id) {
+ if (req->pdu_id != pdu_id || req->event_id != event_id)
+ continue;
+
+ if (!peek)
g_queue_pop_nth(dev->queue, i);
- return req;
- }
+
+ return req;
}
}
@@ -99,7 +104,7 @@ static void handle_get_play_status(const void *buf, uint16_t len)
DBG("");
- req = pop_request(AVRCP_GET_PLAY_STATUS);
+ req = pop_request(AVRCP_GET_PLAY_STATUS, 0, false);
if (!req) {
status = HAL_STATUS_FAILED;
goto done;
@@ -214,7 +219,7 @@ static void handle_get_element_attrs_text(const void *buf, uint16_t len)
DBG("");
- req = pop_request(AVRCP_GET_ELEMENT_ATTRIBUTES);
+ req = pop_request(AVRCP_GET_ELEMENT_ATTRIBUTES, 0, false);
if (!req) {
status = HAL_STATUS_FAILED;
goto done;
@@ -256,11 +261,25 @@ static void handle_register_notification(const void *buf, uint16_t len)
uint8_t pdu[IPC_MTU];
size_t pdu_len;
uint8_t code;
+ bool peek = false;
int ret;
DBG("");
- req = pop_request(AVRCP_REGISTER_NOTIFICATION);
+ switch (cmd->type) {
+ case HAL_AVRCP_EVENT_TYPE_INTERIM:
+ code = AVC_CTYPE_INTERIM;
+ peek = true;
+ break;
+ case HAL_AVRCP_EVENT_TYPE_CHANGED:
+ code = AVC_CTYPE_CHANGED;
+ break;
+ default:
+ status = HAL_STATUS_FAILED;
+ goto done;
+ }
+
+ req = pop_request(AVRCP_REGISTER_NOTIFICATION, cmd->event, peek);
if (!req) {
status = HAL_STATUS_FAILED;
goto done;
@@ -281,29 +300,19 @@ static void handle_register_notification(const void *buf, uint16_t len)
goto done;
}
- switch (cmd->type) {
- case HAL_AVRCP_EVENT_TYPE_INTERIM:
- code = AVC_CTYPE_INTERIM;
- break;
- case HAL_AVRCP_EVENT_TYPE_CHANGED:
- code = AVC_CTYPE_CHANGED;
- break;
- default:
- status = HAL_STATUS_FAILED;
- goto done;
- }
-
ret = avrcp_register_notification_rsp(req->dev->session,
req->transaction, code,
pdu, pdu_len);
if (ret < 0) {
status = HAL_STATUS_FAILED;
- g_free(req);
+ if (!peek)
+ g_free(req);
goto done;
}
status = HAL_STATUS_SUCCESS;
- g_free(req);
+ if (!peek)
+ g_free(req);
done:
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_AVRCP,
@@ -552,13 +561,14 @@ static ssize_t handle_get_capabilities_cmd(struct avrcp *session,
}
static void push_request(struct avrcp_device *dev, uint8_t pdu_id,
- uint8_t transaction)
+ uint8_t event_id, uint8_t transaction)
{
struct avrcp_request *req;
req = g_new0(struct avrcp_request, 1);
req->dev = dev;
req->pdu_id = pdu_id;
+ req->event_id = event_id;
req->transaction = transaction;
g_queue_push_tail(dev->queue, req);
@@ -580,7 +590,7 @@ static ssize_t handle_get_play_status_cmd(struct avrcp *session,
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_AVRCP,
HAL_EV_AVRCP_GET_PLAY_STATUS, 0, NULL);
- push_request(dev, AVRCP_GET_PLAY_STATUS, transaction);
+ push_request(dev, AVRCP_GET_PLAY_STATUS, 0, transaction);
return -EAGAIN;
}
@@ -616,7 +626,7 @@ static ssize_t handle_get_element_attrs_cmd(struct avrcp *session,
HAL_EV_AVRCP_GET_ELEMENT_ATTRS,
sizeof(*ev) + ev->number, ev);
- push_request(dev, AVRCP_GET_ELEMENT_ATTRIBUTES, transaction);
+ push_request(dev, AVRCP_GET_ELEMENT_ATTRIBUTES, 0, transaction);
return -EAGAIN;
@@ -630,14 +640,17 @@ static ssize_t handle_register_notification_cmd(struct avrcp *session,
{
struct avrcp_device *dev = user_data;
struct hal_ev_avrcp_register_notification ev;
+ uint8_t event_id;
DBG("");
if (params_len != 5)
return -EINVAL;
+ event_id = params[0];
+
/* TODO: Add any missing events supported by Android */
- switch (params[0]) {
+ switch (event_id) {
case AVRCP_EVENT_STATUS_CHANGED:
case AVRCP_EVENT_TRACK_CHANGED:
case AVRCP_EVENT_PLAYBACK_POS_CHANGED:
@@ -646,14 +659,14 @@ static ssize_t handle_register_notification_cmd(struct avrcp *session,
return -EINVAL;
}
- ev.event = params[0];
+ ev.event = event_id;
ev.param = bt_get_be32(¶ms[1]);
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_AVRCP,
HAL_EV_AVRCP_REGISTER_NOTIFICATION,
sizeof(ev), &ev);
- push_request(dev, AVRCP_REGISTER_NOTIFICATION, transaction);
+ push_request(dev, AVRCP_REGISTER_NOTIFICATION, event_id, transaction);
return -EAGAIN;
}
--
1.9.0
^ permalink raw reply related
* [PATCH 1/4] android/avrcp: Fix response for RegisterNotification
From: Andrzej Kaczmarek @ 2014-03-04 20:43 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
---
android/avrcp.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/android/avrcp.c b/android/avrcp.c
index 8eac4cd..f3427a3 100644
--- a/android/avrcp.c
+++ b/android/avrcp.c
@@ -255,6 +255,7 @@ static void handle_register_notification(const void *buf, uint16_t len)
struct avrcp_request *req;
uint8_t pdu[IPC_MTU];
size_t pdu_len;
+ uint8_t code;
int ret;
DBG("");
@@ -280,8 +281,20 @@ static void handle_register_notification(const void *buf, uint16_t len)
goto done;
}
+ switch (cmd->type) {
+ case HAL_AVRCP_EVENT_TYPE_INTERIM:
+ code = AVC_CTYPE_INTERIM;
+ break;
+ case HAL_AVRCP_EVENT_TYPE_CHANGED:
+ code = AVC_CTYPE_CHANGED;
+ break;
+ default:
+ status = HAL_STATUS_FAILED;
+ goto done;
+ }
+
ret = avrcp_register_notification_rsp(req->dev->session,
- req->transaction, cmd->type,
+ req->transaction, code,
pdu, pdu_len);
if (ret < 0) {
status = HAL_STATUS_FAILED;
--
1.9.0
^ permalink raw reply related
* Re: cannot connect Rock Candy Gesture Controller (wiimote) on Arch Linux
From: David Herrmann @ 2014-03-04 18:46 UTC (permalink / raw)
To: Mark E. Lee; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1393955100.16179.0.camel@melech-server.localdomain>
Hi
On Tue, Mar 4, 2014 at 6:45 PM, Mark E. Lee <mark@markelee.com> wrote:
> On Mon, 2014-03-03 at 22:21 -0500, Mark E. Lee wrote:
>> Salutations,
>>
>> I recently purchased an off-brand wiimote from Target (USA). It is the
>> Rock Candy Gesture Controller (w/o motion plus). I have been unable to
>> connect to it via bluetooth on Arch Linux 64-bit (bluez 5.15-1). This
>> issue has been reported on GitHub
>> <https://github.com/dvdhrm/xwiimote/issues/43#issuecomment-36577704>.
>> I've reiterated my tests with the device below :
>>
>> --OUTPUT of $ hcitool inq --iac=liac
>> Inquiring ...
>>
>> 00:17:AB:39:1C:70 clock offset: 0x5574 class: 0x002504
>>
>> ---OUTPUT of # hcitool info 00:17:AB:39:1C:70---
>> Inquiring ...
>> Requesting information ...
>> BD Address: 00:17:AB:39:1C:70
>> OUI Company: Nintendo Co., Ltd. (00-17-AB)
>> Device Name: Nintendo RVL-CNT-01
>> LMP Version: 3.0 (0x5) LMP Subversion: 0xc
>> Manufacturer: not assigned (771)
>> Features: 0xbc 0x02 0x04 0x38 0x08 0x00 0x00 0x00
>>
>>
>> ---OUTPUT of $ hcitool inq---
>>
>> Inquiring ...
>>
>> ---OUTPUT of $ hcitool scan---
>>
>> Scanning ...
>>
>> ---OUTPUT of $ sdptool browse 00:17:AB:39:1C:70---
>> Browsing 00:17:AB:39:1C:70 ...
>>
>> Service Search failed: Connection timed out
>>
>> ---OUTPUT of $ bluetoothctl; connect 00:17:AB:39:1C:70---
>>
>> Device 00:17:AB:39:1C:70 not available
>>
>> ---OUTPUT of $ sdptool search 00:17:AB:39:1C:70---
>>
>> Unknown service 00:17:AB:39:1C:70
>> ----
>>
>> Any help towards getting this device to work?
>>
>
> Salutations,
>
> I don't have much experience in coding for the wiimote, I was wondering
> if this is simply a wii_id issue in plugins/wiimote.c. How do I find the
> wii_id of the remote?
Thats reported via SDP... but your device seems to not report any such
data ("sdptool browse" times out). No idea whether these devices
provide other ways to get the data. The original Wii-Remotes report
SDP data correctly.
Thanks
David
^ permalink raw reply
* Re: cannot connect Rock Candy Gesture Controller (wiimote) on Arch Linux
From: Mark E. Lee @ 2014-03-04 17:45 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393903271.6313.3.camel@melech-server.localdomain>
[-- Attachment #1: Type: text/plain, Size: 1718 bytes --]
On Mon, 2014-03-03 at 22:21 -0500, Mark E. Lee wrote:
> Salutations,
>
> I recently purchased an off-brand wiimote from Target (USA). It is the
> Rock Candy Gesture Controller (w/o motion plus). I have been unable to
> connect to it via bluetooth on Arch Linux 64-bit (bluez 5.15-1). This
> issue has been reported on GitHub
> <https://github.com/dvdhrm/xwiimote/issues/43#issuecomment-36577704>.
> I've reiterated my tests with the device below :
>
> --OUTPUT of $ hcitool inq --iac=liac
> Inquiring ...
>
> 00:17:AB:39:1C:70 clock offset: 0x5574 class: 0x002504
>
> ---OUTPUT of # hcitool info 00:17:AB:39:1C:70---
> Inquiring ...
> Requesting information ...
> BD Address: 00:17:AB:39:1C:70
> OUI Company: Nintendo Co., Ltd. (00-17-AB)
> Device Name: Nintendo RVL-CNT-01
> LMP Version: 3.0 (0x5) LMP Subversion: 0xc
> Manufacturer: not assigned (771)
> Features: 0xbc 0x02 0x04 0x38 0x08 0x00 0x00 0x00
>
>
> ---OUTPUT of $ hcitool inq---
>
> Inquiring ...
>
> ---OUTPUT of $ hcitool scan---
>
> Scanning ...
>
> ---OUTPUT of $ sdptool browse 00:17:AB:39:1C:70---
> Browsing 00:17:AB:39:1C:70 ...
>
> Service Search failed: Connection timed out
>
> ---OUTPUT of $ bluetoothctl; connect 00:17:AB:39:1C:70---
>
> Device 00:17:AB:39:1C:70 not available
>
> ---OUTPUT of $ sdptool search 00:17:AB:39:1C:70---
>
> Unknown service 00:17:AB:39:1C:70
> ----
>
> Any help towards getting this device to work?
>
Salutations,
I don't have much experience in coding for the wiimote, I was wondering
if this is simply a wii_id issue in plugins/wiimote.c. How do I find the
wii_id of the remote?
Regards,
Mark
--
Mark E. Lee <mark@markelee.com>
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 230 bytes --]
^ permalink raw reply
* Re: [PATCH BlueZ] AVCTP: Fix sending wrong response format
From: Johan Hedberg @ 2014-03-04 16:05 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1393938497-4522-1-git-send-email-luiz.dentz@gmail.com>
Hi Luiz,
On Tue, Mar 04, 2014, Luiz Augusto von Dentz wrote:
> Reject and Not Implemented responses of PASS THROUGH commands shall
> contain the data of the previous frame accourding to AVC Panel Subunit
> specification page 87.
> ---
> android/avctp.c | 4 ++--
> profiles/audio/avctp.c | 4 ++--
> 2 files changed, 4 insertions(+), 4 deletions(-)
Applied. Thanks.
Johan
^ permalink raw reply
* [PATCH 8/8] android/handsfree: Make connection state constants name shorter
From: Szymon Janc @ 2014-03-04 15:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1393947130-11999-1-git-send-email-szymon.janc@tieto.com>
---
android/hal-msg.h | 10 +++++-----
android/handsfree.c | 26 +++++++++++++-------------
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/android/hal-msg.h b/android/hal-msg.h
index dd25f6e..886b5d3 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -979,11 +979,11 @@ struct hal_ev_a2dp_audio_state {
uint8_t bdaddr[6];
} __attribute__((packed));
-#define HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED 0x00
-#define HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTING 0x01
-#define HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED 0x02
-#define HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED 0x03
-#define HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING 0x04
+#define HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTED 0x00
+#define HAL_EV_HANDSFREE_CONN_STATE_CONNECTING 0x01
+#define HAL_EV_HANDSFREE_CONN_STATE_CONNECTED 0x02
+#define HAL_EV_HANDSFREE_CONN_STATE_SLC_CONNECTED 0x03
+#define HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTING 0x04
#define HAL_EV_HANDSFREE_CONN_STATE 0x81
struct hal_ev_handsfree_conn_state {
diff --git a/android/handsfree.c b/android/handsfree.c
index 99e786f..6f91e74 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -114,7 +114,7 @@ static void device_init(const bdaddr_t *bdaddr)
for (i = 0; i < G_N_ELEMENTS(device.active_ind); i++)
device.active_ind[i] = indicators[i].always_active;
- device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTING);
+ device_set_state(HAL_EV_HANDSFREE_CONN_STATE_CONNECTING);
}
static void device_cleanup(void)
@@ -124,7 +124,7 @@ static void device_cleanup(void)
device.gw = NULL;
}
- device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED);
+ device_set_state(HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTED);
memset(&device, 0, sizeof(device));
}
@@ -133,7 +133,7 @@ static void at_command_handler(const char *command, void *user_data)
{
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
- if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED)
+ if (device.state != HAL_EV_HANDSFREE_CONN_STATE_SLC_CONNECTED)
hfp_gw_disconnect(device.gw);
}
@@ -219,7 +219,7 @@ static void at_cmd_cmer(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
/* TODO Check for 3-way calling support */
register_post_slc_at();
- device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED);
+ device_set_state(HAL_EV_HANDSFREE_CONN_STATE_SLC_CONNECTED);
hfp_gw_send_result(device.gw, HFP_RESULT_OK);
@@ -337,13 +337,13 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
if (device.hsp) {
register_post_slc_at();
- device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
- device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED);
+ device_set_state(HAL_EV_HANDSFREE_CONN_STATE_CONNECTED);
+ device_set_state(HAL_EV_HANDSFREE_CONN_STATE_SLC_CONNECTED);
return;
}
register_slc_at();
- device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
+ device_set_state(HAL_EV_HANDSFREE_CONN_STATE_CONNECTED);
return;
@@ -370,7 +370,7 @@ static void confirm_cb(GIOChannel *chan, gpointer data)
DBG("incoming connect from %s", address);
- if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED) {
+ if (device.state != HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTED) {
info("handsfree: refusing connection from %s", address);
goto drop;
}
@@ -572,7 +572,7 @@ static void handle_connect(const void *buf, uint16_t len)
DBG("");
- if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED) {
+ if (device.state != HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTED) {
status = HAL_STATUS_FAILED;
goto failed;
}
@@ -610,22 +610,22 @@ static void handle_disconnect(const void *buf, uint16_t len)
android2bdaddr(cmd->bdaddr, &bdaddr);
- if (device.state == HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED ||
+ if (device.state == HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTED ||
bacmp(&device.bdaddr, &bdaddr)) {
status = HAL_STATUS_FAILED;
goto failed;
}
- if (device.state == HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING) {
+ if (device.state == HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTING) {
status = HAL_STATUS_SUCCESS;
goto failed;
}
- if (device.state == HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTING) {
+ if (device.state == HAL_EV_HANDSFREE_CONN_STATE_CONNECTING) {
device_cleanup();
} else {
- device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING);
+ device_set_state(HAL_EV_HANDSFREE_CONN_STATE_DISCONNECTING);
hfp_gw_disconnect(device.gw);
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 7/8] android/handsfree: Add support for AT+BIA command
From: Szymon Janc @ 2014-03-04 15:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1393947130-11999-1-git-send-email-szymon.janc@tieto.com>
---
android/handsfree.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 67 insertions(+), 6 deletions(-)
diff --git a/android/handsfree.c b/android/handsfree.c
index 50b32da..99e786f 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -71,6 +71,7 @@ static struct {
uint8_t state;
uint32_t features;
bool indicators_enabled;
+ bool active_ind[G_N_ELEMENTS(indicators)];
bool hsp;
struct hfp_gw *gw;
} device;
@@ -106,8 +107,13 @@ static void device_set_state(uint8_t state)
static void device_init(const bdaddr_t *bdaddr)
{
+ unsigned int i;
+
bacpy(&device.bdaddr, bdaddr);
+ for (i = 0; i < G_N_ELEMENTS(device.active_ind); i++)
+ device.active_ind[i] = indicators[i].always_active;
+
device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTING);
}
@@ -138,6 +144,54 @@ static void disconnect_watch(void *user_data)
device_cleanup();
}
+static void at_cmd_bia(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+ void *user_data)
+{
+ unsigned int val, i = 0;
+
+ switch (type) {
+ case HFP_GW_CMD_TYPE_SET:
+ do {
+ if (!hfp_gw_result_get_number_default(result, &val, 0))
+ goto failed;
+
+ if (val > 1)
+ goto failed;
+ } while(hfp_gw_result_has_next(result));
+
+
+ do {
+ if (!hfp_gw_result_get_number(result, &val))
+ device.active_ind[i] = val ||
+ indicators[i].always_active;
+
+ if (++i == G_N_ELEMENTS(indicators))
+ break;
+ } while (hfp_gw_result_has_next(result));
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
+ return;
+ case HFP_GW_CMD_TYPE_TEST:
+ case HFP_GW_CMD_TYPE_READ:
+ case HFP_GW_CMD_TYPE_COMMAND:
+ break;
+ }
+
+failed:
+ hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+}
+
+static void register_post_slc_at(void)
+{
+ if (device.hsp) {
+ /* TODO CKPD, VGS, VGM */
+ return;
+ }
+
+ hfp_gw_register(device.gw, at_cmd_bia, "+BIA", NULL, NULL);
+}
+
static void at_cmd_cmer(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
void *user_data)
{
@@ -164,6 +218,7 @@ static void at_cmd_cmer(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
device.indicators_enabled = val;
/* TODO Check for 3-way calling support */
+ register_post_slc_at();
device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED);
hfp_gw_send_result(device.gw, HFP_RESULT_OK);
@@ -253,6 +308,13 @@ static void at_cmd_brsf(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
+static void register_slc_at(void)
+{
+ hfp_gw_register(device.gw, at_cmd_brsf, "+BRSF", NULL, NULL);
+ hfp_gw_register(device.gw, at_cmd_cind, "+CIND", NULL, NULL);
+ hfp_gw_register(device.gw, at_cmd_cmer, "+CMER", NULL, NULL);
+}
+
static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
DBG("");
@@ -274,16 +336,15 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
if (device.hsp) {
- /* TODO CKPD, VGS, VGM */
+ register_post_slc_at();
device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED);
- } else {
- hfp_gw_register(device.gw, at_cmd_brsf, "+BRSF", NULL, NULL);
- hfp_gw_register(device.gw, at_cmd_cind, "+CIND", NULL, NULL);
- hfp_gw_register(device.gw, at_cmd_cmer, "+CMER", NULL, NULL);
- device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
+ return;
}
+ register_slc_at();
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
+
return;
failed:
--
1.8.3.2
^ permalink raw reply related
* [PATCH 6/8] shared/hfp: Add hfp_gw_result_get_number_default function
From: Szymon Janc @ 2014-03-04 15:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1393947130-11999-1-git-send-email-szymon.janc@tieto.com>
---
src/shared/hfp.c | 15 +++++++++++++++
src/shared/hfp.h | 3 +++
2 files changed, 18 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 44b5b55..e548672 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -224,6 +224,21 @@ static void next_field(struct hfp_gw_result *result)
result->offset++;
}
+bool hfp_gw_result_get_number_default(struct hfp_gw_result *result,
+ unsigned int *val,
+ unsigned int default_val)
+{
+ skip_whitespace(result);
+
+ if (result->data[result->offset] == ',') {
+ if (val)
+ *val = default_val;
+ return true;
+ }
+
+ return hfp_gw_result_get_number(result, val);
+}
+
bool hfp_gw_result_get_number(struct hfp_gw_result *result, unsigned int *val)
{
int tmp = 0;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 4da5c97..743db65 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -114,6 +114,9 @@ bool hfp_gw_register(struct hfp_gw *hfp, hfp_result_func_t callback,
bool hfp_gw_unregister(struct hfp_gw *hfp, const char *prefix);
bool hfp_gw_result_get_number(struct hfp_gw_result *result, unsigned int *val);
+bool hfp_gw_result_get_number_default(struct hfp_gw_result *result,
+ unsigned int *val,
+ unsigned int default_val);
bool hfp_gw_result_open_container(struct hfp_gw_result *result);
bool hfp_gw_result_close_container(struct hfp_gw_result *result);
bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
--
1.8.3.2
^ permalink raw reply related
* [PATCH 5/8] shared/hfp: Add function to check if reach end of command
From: Szymon Janc @ 2014-03-04 15:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1393947130-11999-1-git-send-email-szymon.janc@tieto.com>
---
src/shared/hfp.c | 5 +++++
src/shared/hfp.h | 1 +
2 files changed, 6 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index b10316e..44b5b55 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -336,6 +336,11 @@ bool hfp_gw_result_get_unquoted_string(struct hfp_gw_result *result, char *buf,
return true;
}
+bool hfp_gw_result_has_next(struct hfp_gw_result *result)
+{
+ return result->data[result->offset] != '\0';
+}
+
static void process_input(struct hfp_gw *hfp)
{
char *str, *ptr;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 649b77e..4da5c97 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -120,3 +120,4 @@ bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
uint8_t len);
bool hfp_gw_result_get_unquoted_string(struct hfp_gw_result *result, char *buf,
uint8_t len);
+bool hfp_gw_result_has_next(struct hfp_gw_result *result);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 4/8] android/handsfree: Distinguish between HSP and HFP connection
From: Szymon Janc @ 2014-03-04 15:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1393947130-11999-1-git-send-email-szymon.janc@tieto.com>
---
android/handsfree.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/android/handsfree.c b/android/handsfree.c
index a437fba..50b32da 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -71,6 +71,7 @@ static struct {
uint8_t state;
uint32_t features;
bool indicators_enabled;
+ bool hsp;
struct hfp_gw *gw;
} device;
@@ -272,10 +273,16 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
hfp_gw_set_disconnect_handler(device.gw, disconnect_watch, NULL, NULL);
- hfp_gw_register(device.gw, at_cmd_brsf, "+BRSF", NULL, NULL);
- hfp_gw_register(device.gw, at_cmd_cind, "+CIND", NULL, NULL);
- hfp_gw_register(device.gw, at_cmd_cmer, "+CMER", NULL, NULL);
- device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
+ if (device.hsp) {
+ /* TODO CKPD, VGS, VGM */
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED);
+ } else {
+ hfp_gw_register(device.gw, at_cmd_brsf, "+BRSF", NULL, NULL);
+ hfp_gw_register(device.gw, at_cmd_cind, "+CIND", NULL, NULL);
+ hfp_gw_register(device.gw, at_cmd_cmer, "+CMER", NULL, NULL);
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
+ }
return;
@@ -315,6 +322,8 @@ static void confirm_cb(GIOChannel *chan, gpointer data)
goto drop;
}
+ device.hsp = GPOINTER_TO_INT(data);
+
return;
drop:
@@ -386,6 +395,8 @@ static void sdp_hsp_search_cb(sdp_list_t *recs, int err, gpointer data)
goto fail;
}
+ device.hsp = true;
+
g_io_channel_unref(io);
return;
@@ -804,7 +815,8 @@ static bool enable_hsp_ag(void)
DBG("");
- hsp_server = bt_io_listen(NULL, confirm_cb, NULL, NULL, &err,
+ hsp_server = bt_io_listen(NULL, confirm_cb, GINT_TO_POINTER(true), NULL,
+ &err,
BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
BT_IO_OPT_CHANNEL, HSP_AG_CHANNEL,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
@@ -935,7 +947,8 @@ static bool enable_hfp_ag(void)
if (hfp_server)
return false;
- hfp_server = bt_io_listen(NULL, confirm_cb, NULL, NULL, &err,
+ hfp_server = bt_io_listen(NULL, confirm_cb, GINT_TO_POINTER(false),
+ NULL, &err,
BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
BT_IO_OPT_CHANNEL, HFP_AG_CHANNEL,
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
--
1.8.3.2
^ permalink raw reply related
* [PATCH 3/8] android/handsfree: Add support for AT+CMER command
From: Szymon Janc @ 2014-03-04 15:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1393947130-11999-1-git-send-email-szymon.janc@tieto.com>
When this command is received SLC is connected.
---
android/handsfree.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)
diff --git a/android/handsfree.c b/android/handsfree.c
index 4db0560..a437fba 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -70,6 +70,7 @@ static struct {
bdaddr_t bdaddr;
uint8_t state;
uint32_t features;
+ bool indicators_enabled;
struct hfp_gw *gw;
} device;
@@ -125,7 +126,8 @@ static void at_command_handler(const char *command, void *user_data)
{
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
- hfp_gw_disconnect(device.gw);
+ if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED)
+ hfp_gw_disconnect(device.gw);
}
static void disconnect_watch(void *user_data)
@@ -135,6 +137,46 @@ static void disconnect_watch(void *user_data)
device_cleanup();
}
+static void at_cmd_cmer(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+ void *user_data)
+{
+ unsigned int val;
+
+ switch (type) {
+ case HFP_GW_CMD_TYPE_SET:
+ /* mode must be =3 */
+ if (!hfp_gw_result_get_number(result, &val) || val != 3)
+ break;
+
+ /* keyp is don't care */
+ if (!hfp_gw_result_get_number(result, &val))
+ break;
+
+ /* disp is don't care */
+ if (!hfp_gw_result_get_number(result, &val))
+ break;
+
+ /* ind must be 0 or 1 */
+ if (!hfp_gw_result_get_number(result, &val) || val > 1)
+ break;
+
+ device.indicators_enabled = val;
+
+ /* TODO Check for 3-way calling support */
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED);
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
+ return;
+ case HFP_GW_CMD_TYPE_TEST:
+ case HFP_GW_CMD_TYPE_READ:
+ case HFP_GW_CMD_TYPE_COMMAND:
+ break;
+ }
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+}
+
static void at_cmd_cind(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
void *user_data)
{
@@ -232,6 +274,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
hfp_gw_register(device.gw, at_cmd_brsf, "+BRSF", NULL, NULL);
hfp_gw_register(device.gw, at_cmd_cind, "+CIND", NULL, NULL);
+ hfp_gw_register(device.gw, at_cmd_cmer, "+CMER", NULL, NULL);
device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
return;
--
1.8.3.2
^ permalink raw reply related
* [PATCH 2/8] android/handsfree: Add support for AT+CIND command
From: Szymon Janc @ 2014-03-04 15:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1393947130-11999-1-git-send-email-szymon.janc@tieto.com>
---
android/handsfree.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 96 insertions(+), 1 deletion(-)
diff --git a/android/handsfree.c b/android/handsfree.c
index ce690d7..4db0560 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -51,6 +51,21 @@
#define HFP_AG_FEATURES 0
+static const struct {
+ const char *name;
+ int min;
+ int max;
+ bool always_active;
+} indicators[] = {
+ { "service", 0, 1, false },
+ { "call", 0, 1, true },
+ { "callsetup", 0, 3, true },
+ { "callheld", 0, 2, true },
+ { "signal", 0, 5, false },
+ { "roam", 0, 1, false },
+ { "battchg", 0, 5, false },
+};
+
static struct {
bdaddr_t bdaddr;
uint8_t state;
@@ -120,6 +135,56 @@ static void disconnect_watch(void *user_data)
device_cleanup();
}
+static void at_cmd_cind(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+ void *user_data)
+{
+ char *buf, *ptr;
+ int len;
+ unsigned int i;
+
+ switch (type) {
+ case HFP_GW_CMD_TYPE_TEST:
+
+ len = strlen("+CIND:") + 1;
+
+ for (i = 0; i < G_N_ELEMENTS(indicators); i++) {
+ len += strlen("(\"\",(X,X)),");
+ len += strlen(indicators[i].name);
+ }
+
+ buf = g_malloc(len);
+
+ ptr = buf + sprintf(buf, "+CIND:");
+
+ for (i = 0; i < G_N_ELEMENTS(indicators); i++) {
+ ptr += sprintf(ptr, "(\"%s\",(%d%c%d)),",
+ indicators[i].name,
+ indicators[i].min,
+ indicators[i].max == 1 ? ',' : '-',
+ indicators[i].max);
+ }
+
+ ptr--;
+ *ptr = '\0';
+
+ hfp_gw_send_info(device.gw, "%s", buf);
+ hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
+ g_free(buf);
+
+ return;
+ case HFP_GW_CMD_TYPE_READ:
+ ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
+ HAL_EV_HANDSFREE_CIND, 0, NULL);
+ return;
+ case HFP_GW_CMD_TYPE_SET:
+ case HFP_GW_CMD_TYPE_COMMAND:
+ break;
+ }
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+}
+
static void at_cmd_brsf(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
void *user_data)
{
@@ -166,6 +231,7 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
hfp_gw_register(device.gw, at_cmd_brsf, "+BRSF", NULL, NULL);
+ hfp_gw_register(device.gw, at_cmd_cind, "+CIND", NULL, NULL);
device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
return;
@@ -512,12 +578,41 @@ static void handle_cops(const void *buf, uint16_t len)
HAL_OP_HANDSFREE_COPS_RESPONSE, HAL_STATUS_FAILED);
}
+static unsigned int get_callsetup(uint8_t state)
+{
+ switch (state) {
+ case HAL_HANDSFREE_CALL_STATE_INCOMING:
+ return 1;
+ case HAL_HANDSFREE_CALL_STATE_DIALING:
+ return 2;
+ case HAL_HANDSFREE_CALL_STATE_ALERTING:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
static void handle_cind(const void *buf, uint16_t len)
{
+ const struct hal_cmd_handsfree_cind_response *cmd = buf;
+
DBG("");
+ /* HAL doesn't provide CIND values directly so need to convert here */
+
+ hfp_gw_send_info(device.gw, "+CIND: %u,%u,%u,%u,%u,%u,%u",
+ cmd->svc,
+ !!(cmd->num_active + cmd->num_held),
+ get_callsetup(cmd->state),
+ cmd->num_held ? (cmd->num_active ? 1 : 2) : 0,
+ cmd->signal,
+ cmd->roam,
+ cmd->batt_chg);
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
ipc_send_rsp(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
- HAL_OP_HANDSFREE_CIND_RESPONSE, HAL_STATUS_FAILED);
+ HAL_OP_HANDSFREE_CIND_RESPONSE, HAL_STATUS_SUCCESS);
}
static void handle_formatted_at_resp(const void *buf, uint16_t len)
--
1.8.3.2
^ permalink raw reply related
* [PATCH 1/8] android/handsfree: Add support for AT+BRSF command
From: Szymon Janc @ 2014-03-04 15:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1393947130-11999-1-git-send-email-szymon.janc@tieto.com>
---
android/handsfree.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/android/handsfree.c b/android/handsfree.c
index 4f69e68..ce690d7 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -54,6 +54,7 @@
static struct {
bdaddr_t bdaddr;
uint8_t state;
+ uint32_t features;
struct hfp_gw *gw;
} device;
@@ -119,6 +120,31 @@ static void disconnect_watch(void *user_data)
device_cleanup();
}
+static void at_cmd_brsf(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+ void *user_data)
+{
+ unsigned int feat;
+
+ switch (type) {
+ case HFP_GW_CMD_TYPE_SET:
+ if (!hfp_gw_result_get_number(result, &feat))
+ break;
+
+ /* TODO verify features */
+ device.features = feat;
+
+ hfp_gw_send_info(device.gw, "+BRSF=%u", HFP_AG_FEATURES);
+ hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+ return;
+ case HFP_GW_CMD_TYPE_READ:
+ case HFP_GW_CMD_TYPE_TEST:
+ case HFP_GW_CMD_TYPE_COMMAND:
+ break;
+ }
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+}
+
static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
DBG("");
@@ -138,6 +164,8 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
hfp_gw_set_command_handler(device.gw, at_command_handler, NULL, NULL);
hfp_gw_set_disconnect_handler(device.gw, disconnect_watch, NULL, NULL);
+
+ hfp_gw_register(device.gw, at_cmd_brsf, "+BRSF", NULL, NULL);
device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
return;
--
1.8.3.2
^ permalink raw reply related
* [PATCH 0/8] Initial AT handling for handsfree
From: Szymon Janc @ 2014-03-04 15:32 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
Hi,
This adds initial minimal set of AT commands to establish SLC connection.
Szymon Janc (8):
android/handsfree: Add support for AT+BRSF command
android/handsfree: Add support for AT+CIND command
android/handsfree: Add support for AT+CMER command
android/handsfree: Distinguish between HSP and HFP connection
shared/hfp: Add function to check if reach end of command
shared/hfp: Add hfp_gw_result_get_number_default function
android/handsfree: Add support for AT+BIA command
android/handsfree: Make connection state constants name shorter
android/hal-msg.h | 10 +-
android/handsfree.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++++---
src/shared/hfp.c | 20 ++++
src/shared/hfp.h | 4 +
4 files changed, 282 insertions(+), 18 deletions(-)
--
1.8.3.2
^ permalink raw reply
* [PATCHv2 10/10] doc: Update test coverage document
From: Andrei Emeltchenko @ 2014-03-04 14:02 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393941735-12187-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Update AVRCP test numbers.
---
doc/test-coverage.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/test-coverage.txt b/doc/test-coverage.txt
index ce73b9d..6568286 100644
--- a/doc/test-coverage.txt
+++ b/doc/test-coverage.txt
@@ -18,7 +18,7 @@ test-ringbuf 3 Ring buffer functionality
test-queue 1 Queue handling functionality
test-avdtp 60 AVDTP qualification test cases
test-avctp 9 AVCTP qualification test cases
-test-avrcp 7 AVRCP qualification test cases
+test-avrcp 24 AVRCP qualification test cases
test-gobex 31 Generic OBEX functionality
test-gobex-packet 9 OBEX packet handling
test-gobex-header 28 OBEX header handling
--
1.8.3.2
^ permalink raw reply related
* [PATCHv2 09/10] unit/avrcp: Add /TP/PAS/BI-01-C test
From: Andrei Emeltchenko @ 2014-03-04 14:02 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393941735-12187-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that Get player app setting attribute text returns error
given invalid attribute id.
---
unit/test-avrcp.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 6999d22..803dd6b 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -326,7 +326,16 @@ static ssize_t avrcp_handle_get_player_attr_text(struct avrcp *session,
uint8_t *params,
void *user_data)
{
- DBG("");
+ int i;
+
+ DBG("params[0] %d params_len %d", params[0], params_len);
+
+ for (i = 1; i <= params[0]; i++) {
+ DBG("params[%d] = 0x%02x", i, params[i]);
+ if (params[i] > AVRCP_ATTRIBUTE_LAST ||
+ params[i] == AVRCP_ATTRIBUTE_ILEGAL)
+ return -EINVAL;
+ }
params[0] = 0;
@@ -633,5 +642,18 @@ int main(int argc, char *argv[])
AVRCP_ATTRIBUTE_EQUALIZER, 0xaa,
AVRCP_ATTRIBUTE_REPEAT_MODE, 0xff));
+ /* Get player app setting attribute text invalid behavior - TG */
+ define_test("/TP/PAS/BI-01-C", test_server,
+ raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+ 0x00, 0x19, 0x58,
+ AVRCP_GET_PLAYER_ATTRIBUTE_TEXT,
+ 0x00, 0x00, 0x02, 0x01,
+ /* Invalid attribute id */
+ 0x7f),
+ raw_pdu(0x02, 0x11, 0x0e, AVC_CTYPE_REJECTED,
+ 0x48, 0x00, 0x00, 0x19, 0x58,
+ AVRCP_GET_PLAYER_ATTRIBUTE_TEXT,
+ 0x00, 0x00, 0x01, AVRCP_STATUS_INVALID_PARAM));
+
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCHv2 08/10] unit/avrcp: Add /TP/PAS/BV-11-C test
From: Andrei Emeltchenko @ 2014-03-04 14:02 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393941735-12187-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the set player application setting value command
issued from the Controller.
---
unit/test-avrcp.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index e7d37e0..6999d22 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -448,6 +448,16 @@ static void test_client(gconstpointer data)
sizeof(attributes), NULL, NULL);
}
+ if (g_str_equal(context->data->test_name, "/TP/PAS/BV-11-C")) {
+ uint8_t attributes[2] = { AVRCP_ATTRIBUTE_EQUALIZER,
+ AVRCP_ATTRIBUTE_REPEAT_MODE };
+ uint8_t values[] = { 0xaa, 0xff };
+
+ avrcp_set_player_value(context->session, attributes,
+ sizeof(attributes), values,
+ NULL, NULL);
+ }
+
execute_context(context);
}
@@ -615,5 +625,13 @@ int main(int argc, char *argv[])
AVRCP_ATTRIBUTE_EQUALIZER, 0x00,
AVRCP_ATTRIBUTE_REPEAT_MODE, 0x00));
+ define_test("/TP/PAS/BV-11-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x00, 0x48, 0x00,
+ 0x00, 0x19, 0x58,
+ AVRCP_SET_PLAYER_VALUE,
+ 0x00, 0x00, 0x05, 0x02,
+ AVRCP_ATTRIBUTE_EQUALIZER, 0xaa,
+ AVRCP_ATTRIBUTE_REPEAT_MODE, 0xff));
+
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCHv2 07/10] android/avrcp: Add avrcp_set_player_value() function
From: Andrei Emeltchenko @ 2014-03-04 14:02 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393941735-12187-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
android/avrcp-lib.c | 19 +++++++++++++++++++
android/avrcp-lib.h | 3 +++
2 files changed, 22 insertions(+)
diff --git a/android/avrcp-lib.c b/android/avrcp-lib.c
index 8f18b9c..865a3f9 100644
--- a/android/avrcp-lib.c
+++ b/android/avrcp-lib.c
@@ -404,3 +404,22 @@ int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attributes,
AVRCP_GET_CURRENT_PLAYER_VALUE, buf,
attr_count + 1, func, user_data);
}
+
+int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
+ uint8_t attr_count, uint8_t *values,
+ avctp_rsp_cb func, void *user_data)
+{
+ uint8_t buf[2 * attr_count + 1];
+ int i;
+
+ buf[0] = attr_count;
+
+ for (i = 0; i < attr_count; i++) {
+ buf[i * 2 + 1] = attributes[i];
+ buf[i * 2 + 2] = values[i];
+ }
+
+ return avrcp_send_req(session, AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL,
+ AVRCP_SET_PLAYER_VALUE, buf, 2 * attr_count + 1,
+ func, user_data);
+}
diff --git a/android/avrcp-lib.h b/android/avrcp-lib.h
index 5e396bb..554e064 100644
--- a/android/avrcp-lib.h
+++ b/android/avrcp-lib.h
@@ -149,3 +149,6 @@ int avrcp_register_notification_rsp(struct avrcp *session, uint8_t transaction,
int avrcp_get_current_player_value(struct avrcp *session, uint8_t *attributes,
uint8_t attr_count, avctp_rsp_cb func,
void *user_data);
+int avrcp_set_player_value(struct avrcp *session, uint8_t *attributes,
+ uint8_t attr_count, uint8_t *values,
+ avctp_rsp_cb func, void *user_data);
--
1.8.3.2
^ permalink raw reply related
* [PATCHv2 06/10] unit/avrcp: Add /TP/PAS/BV-10-C test
From: Andrei Emeltchenko @ 2014-03-04 14:02 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393941735-12187-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that the get current player application setting value
response issued from the Target.
---
unit/test-avrcp.c | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index a849be3..e7d37e0 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -365,6 +365,31 @@ static ssize_t avrcp_handle_get_player_value_text(struct avrcp *session,
return 1;
}
+static ssize_t avrcp_handle_get_current_player_value(struct avrcp *session,
+ uint8_t transaction,
+ uint16_t params_len,
+ uint8_t *params,
+ void *user_data)
+{
+ uint8_t *attributes;
+ int i;
+
+ DBG("params[0] %d params_len %d", params[0], params_len);
+
+ attributes = g_memdup(¶ms[1], params[0]);
+
+ for (i = 0; i < params[0]; i++) {
+ params[i * 2 + 1] = attributes[i];
+ params[i * 2 + 2] = 0; /* value */
+ }
+
+ g_free(attributes);
+
+ params[0] = i;
+
+ return params[0] * 2 + 1;
+}
+
static const struct avrcp_control_handler control_handlers[] = {
{ AVRCP_GET_CAPABILITIES,
AVC_CTYPE_STATUS, AVC_CTYPE_STABLE,
@@ -381,6 +406,9 @@ static const struct avrcp_control_handler control_handlers[] = {
{ AVRCP_GET_PLAYER_VALUE_TEXT,
AVC_CTYPE_STATUS, AVC_CTYPE_STABLE,
avrcp_handle_get_player_value_text },
+ { AVRCP_GET_CURRENT_PLAYER_VALUE,
+ AVC_CTYPE_STATUS, AVC_CTYPE_STABLE,
+ avrcp_handle_get_current_player_value },
{ },
};
@@ -573,5 +601,19 @@ int main(int argc, char *argv[])
AVRCP_ATTRIBUTE_EQUALIZER,
AVRCP_ATTRIBUTE_REPEAT_MODE));
+ define_test("/TP/PAS/BV-10-C", test_server,
+ raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+ 0x00, 0x19, 0x58,
+ AVRCP_GET_CURRENT_PLAYER_VALUE,
+ 0x00, 0x00, 0x03, 0x02,
+ AVRCP_ATTRIBUTE_EQUALIZER,
+ AVRCP_ATTRIBUTE_REPEAT_MODE),
+ raw_pdu(0x02, 0x11, 0x0e, 0x0c, 0x48, 0x00,
+ 0x00, 0x19, 0x58,
+ AVRCP_GET_CURRENT_PLAYER_VALUE,
+ 0x00, 0x00, 0x05, 0x02,
+ AVRCP_ATTRIBUTE_EQUALIZER, 0x00,
+ AVRCP_ATTRIBUTE_REPEAT_MODE, 0x00));
+
return g_test_run();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCHv2 05/10] unit/avrcp: Add /TP/PAS/BV-09-C test
From: Andrei Emeltchenko @ 2014-03-04 14:02 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1393941735-12187-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Test verifies that get current player application setting value command
issued from the Controller.
---
unit/test-avrcp.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index a2f554c..a849be3 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -412,6 +412,14 @@ static void test_client(gconstpointer data)
avrcp_get_player_attribute_text(context->session, NULL, 0,
NULL, NULL);
+ if (g_str_equal(context->data->test_name, "/TP/PAS/BV-09-C")) {
+ uint8_t attributes[2] = { AVRCP_ATTRIBUTE_EQUALIZER,
+ AVRCP_ATTRIBUTE_REPEAT_MODE };
+
+ avrcp_get_current_player_value(context->session, attributes,
+ sizeof(attributes), NULL, NULL);
+ }
+
execute_context(context);
}
@@ -557,5 +565,13 @@ int main(int argc, char *argv[])
AVRCP_GET_PLAYER_VALUE_TEXT,
0x00, 0x00, 0x01, 0x00));
+ define_test("/TP/PAS/BV-09-C", test_client,
+ raw_pdu(0x00, 0x11, 0x0e, 0x01, 0x48, 0x00,
+ 0x00, 0x19, 0x58,
+ AVRCP_GET_CURRENT_PLAYER_VALUE,
+ 0x00, 0x00, 0x03, 0x02,
+ AVRCP_ATTRIBUTE_EQUALIZER,
+ AVRCP_ATTRIBUTE_REPEAT_MODE));
+
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