2014-02-02 21:09:11

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 00/13] Initial code for handsfree support

Hi,

This adds initial support for HFP. HAL library is complete, for daemon
only support for RFCOMM connection handling.

There is also minimal set of AT handling needed for SLC establishment
(proper AT parsing code is still missing).

Comments are welcome.

BR
Szymon Janc

Szymon Janc (13):
android/handsfree: Add initial files
android/handsfree: Add commands and events definition to IPC header
android/handsfree: Add stubs for commands handlers
android/hal-handsfree: Implement notifications handling
android/hal-handsfree: Implement sending commands
android/handsfree: Add SDP record for AG
android/handsfree: Add support for RFCOMM connection handling
android/handsfree: Add initial code for AT commands processing
android/handsfree: Add connect command handling
android/handsfree: Add disconnect command handling
android/handsfree: Add AT+BRSF command support
android/handsfree: Add support for AT+CIND command
android/handsfree: Add support for AT+CMER command

android/Android.mk | 2 +
android/Makefile.am | 4 +
android/hal-bluetooth.c | 3 +
android/hal-handsfree.c | 598 +++++++++++++++++++++++++++++++++++++
android/hal-msg.h | 208 +++++++++++++
android/hal.h | 2 +
android/handsfree.c | 763 ++++++++++++++++++++++++++++++++++++++++++++++++
android/handsfree.h | 25 ++
android/main.c | 14 +
9 files changed, 1619 insertions(+)
create mode 100644 android/hal-handsfree.c
create mode 100644 android/handsfree.c
create mode 100644 android/handsfree.h

--
1.8.5.3



2014-02-05 09:10:47

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 06/13] android/handsfree: Add SDP record for AG

Hi Andrei,

On Monday 03 of February 2014 09:56:18 Andrei Emeltchenko wrote:
> Hi Szymon,
>
> On Sun, Feb 02, 2014 at 10:09:17PM +0100, Szymon Janc wrote:
> > Service Name: Hands-Free Audio GatewayService RecHandle: 0x10001
> > Service Class ID List:
> > "Handsfree Audio Gateway" (0x111f)
> > "Generic Audio" (0x1203)
> > Protocol Descriptor List:
> > "L2CAP" (0x0100)
> > "RFCOMM" (0x0003)
> > Channel: 13
> > Profile Descriptor List:
> > "Handsfree" (0x111e)
> > Version: 0x0106
> > ---
> > android/handsfree.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 97 insertions(+)
> >
> > diff --git a/android/handsfree.c b/android/handsfree.c
> > index 3c0d52b..d2dc543 100644
> > --- a/android/handsfree.c
> > +++ b/android/handsfree.c
> > @@ -29,12 +29,19 @@
> > #include <glib.h>
> >
> > #include "lib/bluetooth.h"
> > +#include "lib/sdp.h"
> > +#include "lib/sdp_lib.h"
> > #include "handsfree.h"
> > +#include "bluetooth.h"
> > #include "src/log.h"
> > #include "hal-msg.h"
> > #include "ipc.h"
> >
> > +#define HFP_AG_CHANNEL 13
> > +#define HFP_AG_FEATURES 0
> > +
> > static bdaddr_t adapter_addr;
> > +static uint32_t record_id = 0;
> >
> > static void handle_connect(const void *buf, uint16_t len)
> > {
> > @@ -189,12 +196,99 @@ static const struct ipc_handler cmd_handlers[] = {
> > sizeof(struct hal_cmd_handsfree_phone_state_change)},
> > };
> >
> > +static sdp_record_t *handsfree_ag_record(void)
> > +{
> > + sdp_list_t *svclass_id, *pfseq, *apseq, *root;
> > + uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
> > + uuid_t l2cap_uuid, rfcomm_uuid;
> > + sdp_profile_desc_t profile;
> > + sdp_list_t *aproto, *proto[2];
> > + sdp_record_t *record;
> > + sdp_data_t *channel, *features;
> > + uint8_t netid = 0x01;
> > + uint16_t sdpfeat;
> > + sdp_data_t *network;
> > + uint8_t ch = HFP_AG_CHANNEL;
> > +
> > + record = sdp_record_alloc();
> > + if (!record)
> > + return NULL;
> > +
> > + network = sdp_data_alloc(SDP_UINT8, &netid);
> > + if (!network) {
> > + sdp_record_free(record);
> > + return NULL;
> > + }
> > +
> > + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
> > + root = sdp_list_append(0, &root_uuid);
> > + sdp_set_browse_groups(record, root);
> > +
> > + sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
> > + svclass_id = sdp_list_append(0, &svclass_uuid);
> > + sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
> > + svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
> > + sdp_set_service_classes(record, svclass_id);
> > +
> > + sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
> > + profile.version = 0x0106;
> > + pfseq = sdp_list_append(0, &profile);
> > + sdp_set_profile_descs(record, pfseq);
> > +
> > + sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
> > + proto[0] = sdp_list_append(0, &l2cap_uuid);
> > + apseq = sdp_list_append(0, proto[0]);
> > +
> > + sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
> > + proto[1] = sdp_list_append(0, &rfcomm_uuid);
> > + channel = sdp_data_alloc(SDP_UINT8, &ch);
> > + proto[1] = sdp_list_append(proto[1], channel);
> > + apseq = sdp_list_append(apseq, proto[1]);
> > +
> > + sdpfeat = HFP_AG_FEATURES;
> > + features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
> > + sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
> > +
> > + aproto = sdp_list_append(0, apseq);
> > + sdp_set_access_protos(record, aproto);
> > +
> > + sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
> > +
> > + sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
> > +
> > + sdp_data_free(channel);
> > + sdp_list_free(proto[0], 0);
>
> We have agreed to use NULL for zero pointers.

I've miss that comment, but this is now fixed by follow-up patch.

--
Best regards,
Szymon Janc

2014-02-05 09:10:01

by Szymon Janc

[permalink] [raw]
Subject: Re: [PATCH 00/13] Initial code for handsfree support

On Sunday 02 of February 2014 22:09:11 Szymon Janc wrote:
> Hi,
>
> This adds initial support for HFP. HAL library is complete, for daemon
> only support for RFCOMM connection handling.
>
> There is also minimal set of AT handling needed for SLC establishment
> (proper AT parsing code is still missing).
>
> Comments are welcome.
>
> BR
> Szymon Janc
>
> Szymon Janc (13):
> android/handsfree: Add initial files
> android/handsfree: Add commands and events definition to IPC header
> android/handsfree: Add stubs for commands handlers
> android/hal-handsfree: Implement notifications handling
> android/hal-handsfree: Implement sending commands
> android/handsfree: Add SDP record for AG
> android/handsfree: Add support for RFCOMM connection handling
> android/handsfree: Add initial code for AT commands processing
> android/handsfree: Add connect command handling
> android/handsfree: Add disconnect command handling
> android/handsfree: Add AT+BRSF command support
> android/handsfree: Add support for AT+CIND command
> android/handsfree: Add support for AT+CMER command
>
> android/Android.mk | 2 +
> android/Makefile.am | 4 +
> android/hal-bluetooth.c | 3 +
> android/hal-handsfree.c | 598 +++++++++++++++++++++++++++++++++++++
> android/hal-msg.h | 208 +++++++++++++
> android/hal.h | 2 +
> android/handsfree.c | 763 ++++++++++++++++++++++++++++++++++++++++++++++++
> android/handsfree.h | 25 ++
> android/main.c | 14 +
> 9 files changed, 1619 insertions(+)
> create mode 100644 android/hal-handsfree.c
> create mode 100644 android/handsfree.c
> create mode 100644 android/handsfree.h
>
>

Patches 1-10 are now pushed.

--
Best regards,
Szymon Janc

2014-02-03 07:56:18

by Andrei Emeltchenko

[permalink] [raw]
Subject: Re: [PATCH 06/13] android/handsfree: Add SDP record for AG

Hi Szymon,

On Sun, Feb 02, 2014 at 10:09:17PM +0100, Szymon Janc wrote:
> Service Name: Hands-Free Audio GatewayService RecHandle: 0x10001
> Service Class ID List:
> "Handsfree Audio Gateway" (0x111f)
> "Generic Audio" (0x1203)
> Protocol Descriptor List:
> "L2CAP" (0x0100)
> "RFCOMM" (0x0003)
> Channel: 13
> Profile Descriptor List:
> "Handsfree" (0x111e)
> Version: 0x0106
> ---
> android/handsfree.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 97 insertions(+)
>
> diff --git a/android/handsfree.c b/android/handsfree.c
> index 3c0d52b..d2dc543 100644
> --- a/android/handsfree.c
> +++ b/android/handsfree.c
> @@ -29,12 +29,19 @@
> #include <glib.h>
>
> #include "lib/bluetooth.h"
> +#include "lib/sdp.h"
> +#include "lib/sdp_lib.h"
> #include "handsfree.h"
> +#include "bluetooth.h"
> #include "src/log.h"
> #include "hal-msg.h"
> #include "ipc.h"
>
> +#define HFP_AG_CHANNEL 13
> +#define HFP_AG_FEATURES 0
> +
> static bdaddr_t adapter_addr;
> +static uint32_t record_id = 0;
>
> static void handle_connect(const void *buf, uint16_t len)
> {
> @@ -189,12 +196,99 @@ static const struct ipc_handler cmd_handlers[] = {
> sizeof(struct hal_cmd_handsfree_phone_state_change)},
> };
>
> +static sdp_record_t *handsfree_ag_record(void)
> +{
> + sdp_list_t *svclass_id, *pfseq, *apseq, *root;
> + uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
> + uuid_t l2cap_uuid, rfcomm_uuid;
> + sdp_profile_desc_t profile;
> + sdp_list_t *aproto, *proto[2];
> + sdp_record_t *record;
> + sdp_data_t *channel, *features;
> + uint8_t netid = 0x01;
> + uint16_t sdpfeat;
> + sdp_data_t *network;
> + uint8_t ch = HFP_AG_CHANNEL;
> +
> + record = sdp_record_alloc();
> + if (!record)
> + return NULL;
> +
> + network = sdp_data_alloc(SDP_UINT8, &netid);
> + if (!network) {
> + sdp_record_free(record);
> + return NULL;
> + }
> +
> + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
> + root = sdp_list_append(0, &root_uuid);
> + sdp_set_browse_groups(record, root);
> +
> + sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
> + svclass_id = sdp_list_append(0, &svclass_uuid);
> + sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
> + svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
> + sdp_set_service_classes(record, svclass_id);
> +
> + sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
> + profile.version = 0x0106;
> + pfseq = sdp_list_append(0, &profile);
> + sdp_set_profile_descs(record, pfseq);
> +
> + sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
> + proto[0] = sdp_list_append(0, &l2cap_uuid);
> + apseq = sdp_list_append(0, proto[0]);
> +
> + sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
> + proto[1] = sdp_list_append(0, &rfcomm_uuid);
> + channel = sdp_data_alloc(SDP_UINT8, &ch);
> + proto[1] = sdp_list_append(proto[1], channel);
> + apseq = sdp_list_append(apseq, proto[1]);
> +
> + sdpfeat = HFP_AG_FEATURES;
> + features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
> + sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
> +
> + aproto = sdp_list_append(0, apseq);
> + sdp_set_access_protos(record, aproto);
> +
> + sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
> +
> + sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
> +
> + sdp_data_free(channel);
> + sdp_list_free(proto[0], 0);

We have agreed to use NULL for zero pointers.

Best regards
Andrei Emeltchenko


2014-02-02 21:09:24

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 13/13] android/handsfree: Add support for AT+CMER command

---
android/handsfree.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/android/handsfree.c b/android/handsfree.c
index 02135cb..bf6a575 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -63,6 +63,7 @@ static struct {
struct hfp_gw *gw;

uint32_t features;
+ bool ind_notif_active;
} device;

static bdaddr_t adapter_addr;
@@ -172,6 +173,30 @@ static bool at_cind(const char *at)
return false;
}

+static bool at_cmer(const char *at)
+{
+ unsigned int mode, ind;
+ int ret;
+
+ DBG("");
+
+ ret = sscanf(at, " = %u, %*u, %*u, %u", &mode, &ind);
+ if (ret != 2 || mode != 3 || ind > 1) {
+ hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+
+ return false;
+ }
+
+ device.ind_notif_active = ind;
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
+ /* TODO Check for 3-way calling support */
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED);
+
+ return true;
+}
+
static const struct {
const char *prefix;
int prefix_len;
@@ -179,6 +204,7 @@ static const struct {
} at_cmds[] = {
{ "+BRSF", sizeof("+BRSF") - 1, at_brsf },
{ "+CIND", sizeof("+CIND") - 1, at_cind },
+ { "+CMER", sizeof("+CMER") - 1, at_cmer },
};

static void at_command_handler(const char *command, void *user_data)
--
1.8.5.3


2014-02-02 21:09:20

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 09/13] android/handsfree: Add connect command handling

This allows to query SDP for RFCOMM channel and connect.
---
android/handsfree.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 100 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index a4ce398..79e61b4 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -202,12 +202,111 @@ drop:
g_io_channel_shutdown(chan, TRUE, NULL);
}

+static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
+{
+ sdp_list_t *protos, *classes;
+ GError *gerr = NULL;
+ GIOChannel *io;
+ uuid_t uuid;
+ int channel;
+
+ DBG("");
+
+ if (err < 0) {
+ error("handsfree: unable to get SDP record: %s", strerror(-err));
+ goto fail;
+ }
+
+ if (!recs || !recs->data) {
+ error("handsfree: no SDP records found");
+ goto fail;
+ }
+
+ if (sdp_get_service_classes(recs->data, &classes) < 0) {
+ error("handsfree: unable to get service classes from record");
+ goto fail;
+ }
+
+ if (sdp_get_access_protos(recs->data, &protos) < 0) {
+ error("handsfree: unable to get access protocols from record");
+ goto fail;
+ }
+
+ /* TODO read remote version? */
+
+ memcpy(&uuid, classes->data, sizeof(uuid));
+ sdp_list_free(classes, free);
+
+ if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 ||
+ uuid.value.uuid16 != HANDSFREE_SVCLASS_ID) {
+ sdp_list_free(protos, NULL);
+ error("handsfree: invalid service record or not HFP");
+ goto fail;
+ }
+
+ channel = sdp_get_proto_port(protos, RFCOMM_UUID);
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+ if (channel <= 0) {
+ error("handsfree: unable to get RFCOMM channel from record");
+ goto fail;
+ }
+
+ io = bt_io_connect(connect_cb, NULL, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_DEST_BDADDR, &device.bdaddr,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_CHANNEL, channel,
+ BT_IO_OPT_INVALID);
+ if (!io) {
+ error("handsfree: unable to connect: %s", gerr->message);
+ g_error_free(gerr);
+ goto fail;
+ }
+
+ g_io_channel_unref(io);
+ return;
+
+fail:
+ device_cleanup();
+}
+
static void handle_connect(const void *buf, uint16_t len)
{
+ const struct hal_cmd_handsfree_connect *cmd = buf;
+ char addr[18];
+ uint8_t status;
+ uuid_t uuid;
+ bdaddr_t bdaddr;
+
DBG("");

+ if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ android2bdaddr(&cmd->bdaddr, &bdaddr);
+
+ ba2str(&device.bdaddr, addr);
+ DBG("connecting to %s", addr);
+
+ device_init(&bdaddr);
+
+ bt_string2uuid(&uuid, HFP_HS_UUID);
+ if (bt_search_service(&adapter_addr, &device.bdaddr, &uuid,
+ sdp_search_cb, NULL, NULL, 0) < 0) {
+ error("handsfree: SDP search failed");
+ device_cleanup();
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+failed:
ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CONNECT,
- HAL_STATUS_FAILED);
+ status);
}

static void handle_disconnect(const void *buf, uint16_t len)
--
1.8.5.3


2014-02-02 21:09:21

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 10/13] android/handsfree: Add disconnect command handling

---
android/handsfree.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index 79e61b4..5fe7638 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -311,10 +311,38 @@ failed:

static void handle_disconnect(const void *buf, uint16_t len)
{
+ const struct hal_cmd_handsfree_disconnect *cmd = buf;
+ bdaddr_t bdaddr;
+ uint8_t status;
+
DBG("");

+ android2bdaddr(cmd->bdaddr, &bdaddr);
+
+ if (device.state == HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED ||
+ bacmp(&device.bdaddr, &bdaddr)) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+
+ }
+
+ if (device.state == HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING) {
+ status = HAL_STATUS_SUCCESS;
+ goto failed;
+ }
+
+ if (device.io) {
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTING);
+ g_io_channel_shutdown(device.io, TRUE, NULL);
+ } else {
+ device_cleanup();
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+failed:
ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_DISCONNECT,
- HAL_STATUS_FAILED);
+ status);
}

static void handle_connect_audio(const void *buf, uint16_t len)
--
1.8.5.3


2014-02-02 21:09:19

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 08/13] android/handsfree: Add initial code for AT commands processing

Currently always reply with error and disconnect connection.
---
android/Makefile.am | 2 ++
android/handsfree.c | 21 +++++++++++++++++++++
2 files changed, 23 insertions(+)

diff --git a/android/Makefile.am b/android/Makefile.am
index 23e30c9..41bbbcb 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -27,6 +27,8 @@ android_bluetoothd_SOURCES = android/main.c \
src/shared/queue.h src/shared/queue.c \
src/shared/util.h src/shared/util.c \
src/shared/mgmt.h src/shared/mgmt.c \
+ src/shared/ringbuf.h src/shared/ringbuf.c \
+ src/shared/hfp.h src/shared/hfp.c \
android/bluetooth.h android/bluetooth.c \
android/hidhost.h android/hidhost.c \
android/ipc.h android/ipc.c \
diff --git a/android/handsfree.c b/android/handsfree.c
index ad4c0ff..a4ce398 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -37,6 +37,7 @@
#include "lib/uuid.h"
#include "src/sdp-client.h"
#include "src/uuid-helper.h"
+#include "src/shared/hfp.h"
#include "btio/btio.h"
#include "handsfree.h"
#include "bluetooth.h"
@@ -53,6 +54,7 @@ static struct {
uint8_t state;
GIOChannel *io;
guint watch;
+ struct hfp_gw *gw;
} device;

static bdaddr_t adapter_addr;
@@ -89,6 +91,11 @@ static void device_init(const bdaddr_t *bdaddr)

static void device_cleanup(void)
{
+ if (device.gw) {
+ hfp_gw_unref(device.gw);
+ device.gw = NULL;
+ }
+
if (device.watch) {
g_source_remove(device.watch);
device.watch = 0;
@@ -116,6 +123,13 @@ static gboolean watch_cb(GIOChannel *chan, GIOCondition cond,
return FALSE;
}

+static void at_command_handler(const char *command, void *user_data)
+{
+ hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+
+ g_io_channel_shutdown(device.io, TRUE, NULL);
+}
+
static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
{
DBG("");
@@ -127,6 +141,13 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)

g_io_channel_set_close_on_unref(chan, TRUE);

+ device.gw = hfp_gw_new(g_io_channel_unix_get_fd(chan));
+ if (!device.gw)
+ goto failed;
+
+ hfp_gw_set_close_on_unref(device.gw, true);
+ hfp_gw_set_command_handler(device.gw, at_command_handler, NULL, NULL);
+
device.watch = g_io_add_watch(chan,
G_IO_HUP | G_IO_ERR | G_IO_NVAL,
watch_cb, NULL);
--
1.8.5.3


2014-02-02 21:09:23

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 12/13] android/handsfree: Add support for AT+CIND command

Android supports only fixed number of indicators so this is all static
for now.
---
android/handsfree.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index 990ba2f..02135cb 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -51,6 +51,10 @@

#define AG_FEATURES 0

+#define CIND_SUPPORT_STR "+CIND: (\"service\",(0,1)),(\"call\",(0,1)),\
+ (\"callsetup\",(0-3)),(\"callheld\",(0-2)),\
+ (\"signal\",(0-5)),(\"roam\",(0,1)),(\"battchg\",(0,1))"
+
static struct {
bdaddr_t bdaddr;
uint8_t state;
@@ -146,12 +150,35 @@ static bool at_brsf(const char *at)
return true;
}

+static bool at_cind(const char *at)
+{
+ if (strcmp(at, "?")) {
+ ipc_send_notif(HAL_SERVICE_ID_HANDSFREE, HAL_EV_HANDSFREE_CIND,
+ 0, NULL);
+
+ return true;
+ }
+
+ if (strcmp(at, "=?")) {
+ hfp_gw_send_info(device.gw, "%s", CIND_SUPPORT_STR);
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
+ return true;
+ }
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+
+ return false;
+}
+
static const struct {
const char *prefix;
int prefix_len;
bool (*func)(const char *at_cmds);
} at_cmds[] = {
{ "+BRSF", sizeof("+BRSF") - 1, at_brsf },
+ { "+CIND", sizeof("+CIND") - 1, at_cind },
};

static void at_command_handler(const char *command, void *user_data)
@@ -466,12 +493,41 @@ static void handle_cops(const void *buf, uint16_t len)
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_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CIND_RESPONSE,
- HAL_STATUS_FAILED);
+ HAL_STATUS_SUCCESS);
}

static void handle_formatted_at_resp(const void *buf, uint16_t len)
--
1.8.5.3


2014-02-02 21:09:22

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 11/13] android/handsfree: Add AT+BRSF command support

---
android/handsfree.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index 5fe7638..990ba2f 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -49,12 +49,16 @@
#define HFP_AG_CHANNEL 13
#define HFP_AG_FEATURES 0

+#define AG_FEATURES 0
+
static struct {
bdaddr_t bdaddr;
uint8_t state;
GIOChannel *io;
guint watch;
struct hfp_gw *gw;
+
+ uint32_t features;
} device;

static bdaddr_t adapter_addr;
@@ -123,11 +127,69 @@ static gboolean watch_cb(GIOChannel *chan, GIOCondition cond,
return FALSE;
}

+static bool at_brsf(const char *at)
+{
+ uint32_t feat;
+
+ if (sscanf(at, " = %u", &feat) != 1) {
+ hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
+ return false;
+ }
+
+ /* TODO verify features */
+ device.features = feat;
+
+ hfp_gw_send_info(device.gw, "+BRSF=%u", AG_FEATURES);
+
+ hfp_gw_send_result(device.gw, HFP_RESULT_OK);
+
+ return true;
+}
+
+static const struct {
+ const char *prefix;
+ int prefix_len;
+ bool (*func)(const char *at_cmds);
+} at_cmds[] = {
+ { "+BRSF", sizeof("+BRSF") - 1, at_brsf },
+};
+
static void at_command_handler(const char *command, void *user_data)
{
+ unsigned int i;
+
+ if (strlen(command) < 3)
+ goto error;
+
+ if (strncmp(command, "AT", sizeof("AT") - 1))
+ goto error;
+
+ command += sizeof("AT") - 1;
+
+ for (i = 0; i < G_N_ELEMENTS(at_cmds); i++) {
+ if (strncmp(command, at_cmds[i].prefix, at_cmds[i].prefix_len))
+ continue;
+
+ command += at_cmds[i].prefix_len;
+
+ if (at_cmds[i].func(command))
+ return;
+
+ goto check_slc;
+ }
+
+error:
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);

- g_io_channel_shutdown(device.io, TRUE, NULL);
+check_slc:
+ /* Error while establishing SLC */
+ if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_SLC_CONNECTED)
+ g_io_channel_shutdown(device.io, TRUE, NULL);
+}
+
+static void hfp_gw_debug(const char *str, void *user_data)
+{
+ DBG("%s", str);
}

static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
@@ -148,6 +210,8 @@ static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
hfp_gw_set_close_on_unref(device.gw, true);
hfp_gw_set_command_handler(device.gw, at_command_handler, NULL, NULL);

+ hfp_gw_set_debug(device.gw, hfp_gw_debug, NULL, NULL);
+
device.watch = g_io_add_watch(chan,
G_IO_HUP | G_IO_ERR | G_IO_NVAL,
watch_cb, NULL);
--
1.8.5.3


2014-02-02 21:09:17

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 06/13] android/handsfree: Add SDP record for AG

Service Name: Hands-Free Audio GatewayService RecHandle: 0x10001
Service Class ID List:
"Handsfree Audio Gateway" (0x111f)
"Generic Audio" (0x1203)
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 13
Profile Descriptor List:
"Handsfree" (0x111e)
Version: 0x0106
---
android/handsfree.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)

diff --git a/android/handsfree.c b/android/handsfree.c
index 3c0d52b..d2dc543 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -29,12 +29,19 @@
#include <glib.h>

#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
#include "handsfree.h"
+#include "bluetooth.h"
#include "src/log.h"
#include "hal-msg.h"
#include "ipc.h"

+#define HFP_AG_CHANNEL 13
+#define HFP_AG_FEATURES 0
+
static bdaddr_t adapter_addr;
+static uint32_t record_id = 0;

static void handle_connect(const void *buf, uint16_t len)
{
@@ -189,12 +196,99 @@ static const struct ipc_handler cmd_handlers[] = {
sizeof(struct hal_cmd_handsfree_phone_state_change)},
};

+static sdp_record_t *handsfree_ag_record(void)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t *record;
+ sdp_data_t *channel, *features;
+ uint8_t netid = 0x01;
+ uint16_t sdpfeat;
+ sdp_data_t *network;
+ uint8_t ch = HFP_AG_CHANNEL;
+
+ record = sdp_record_alloc();
+ if (!record)
+ return NULL;
+
+ network = sdp_data_alloc(SDP_UINT8, &netid);
+ if (!network) {
+ sdp_record_free(record);
+ return NULL;
+ }
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+ profile.version = 0x0106;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &ch);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ sdpfeat = HFP_AG_FEATURES;
+ features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
+ sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(record, aproto);
+
+ sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
+
+ sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+
+ return record;
+}
+
bool bt_handsfree_register(const bdaddr_t *addr)
{
+ sdp_record_t *rec;
+
DBG("");

bacpy(&adapter_addr, addr);

+ rec = handsfree_ag_record();
+ if (!rec) {
+ error("Failed to allocate Handsfree record");
+ return false;
+ }
+
+ if (bt_adapter_add_record(rec, 0) < 0) {
+ error("Failed to register Handsfree record");
+ sdp_record_free(rec);
+ return false;
+ }
+ record_id = rec->handle;
+
ipc_register(HAL_SERVICE_ID_HANDSFREE, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));

@@ -206,4 +300,7 @@ void bt_handsfree_unregister(void)
DBG("");

ipc_unregister(HAL_SERVICE_ID_HANDSFREE);
+
+ bt_adapter_remove_record(record_id);
+ record_id = 0;
}
--
1.8.5.3


2014-02-02 21:09:18

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 07/13] android/handsfree: Add support for RFCOMM connection handling

This adds incoming connection handling and initial connection state
tracking. Only one device is allowed to be connected at the same time.
---
android/handsfree.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 165 insertions(+), 2 deletions(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index d2dc543..ad4c0ff 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -25,24 +25,162 @@
#include <config.h>
#endif

+#include <stdlib.h>
#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
#include <glib.h>

#include "lib/bluetooth.h"
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
+#include "lib/uuid.h"
+#include "src/sdp-client.h"
+#include "src/uuid-helper.h"
+#include "btio/btio.h"
#include "handsfree.h"
#include "bluetooth.h"
#include "src/log.h"
#include "hal-msg.h"
#include "ipc.h"
+#include "utils.h"

#define HFP_AG_CHANNEL 13
#define HFP_AG_FEATURES 0

+static struct {
+ bdaddr_t bdaddr;
+ uint8_t state;
+ GIOChannel *io;
+ guint watch;
+} device;
+
static bdaddr_t adapter_addr;
static uint32_t record_id = 0;

+static GIOChannel *server = NULL;
+
+static void device_set_state(uint8_t state)
+{
+ struct hal_ev_handsfree_conn_state ev;
+ char address[18];
+
+ if (device.state == state)
+ return;
+
+ device.state = state;
+
+ ba2str(&device.bdaddr, address);
+ DBG("device %s state %u", address, state);
+
+ bdaddr2android(&device.bdaddr, ev.bdaddr);
+ ev.state = state;
+
+ ipc_send_notif(HAL_SERVICE_ID_HANDSFREE, HAL_EV_HANDSFREE_CONN_STATE,
+ sizeof(ev), &ev);
+}
+
+static void device_init(const bdaddr_t *bdaddr)
+{
+ bacpy(&device.bdaddr, bdaddr);
+
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTING);
+}
+
+static void device_cleanup(void)
+{
+ if (device.watch) {
+ g_source_remove(device.watch);
+ device.watch = 0;
+ }
+
+ if (device.io) {
+ g_io_channel_unref(device.io);
+ device.io = NULL;
+ }
+
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED);
+
+ memset(&device, 0, sizeof(device));
+}
+
+static gboolean watch_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ DBG("");
+
+ device.watch = 0;
+
+ device_cleanup();
+
+ return FALSE;
+}
+
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+ DBG("");
+
+ if (err) {
+ error("handsfree: connect failed (%s)", err->message);
+ goto failed;
+ }
+
+ g_io_channel_set_close_on_unref(chan, TRUE);
+
+ device.watch = g_io_add_watch(chan,
+ G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ watch_cb, NULL);
+ if (device.watch == 0)
+ goto failed;
+
+ device.io = g_io_channel_ref(chan);
+
+ device_set_state(HAL_EV_HANDSFREE_CONNECTION_STATE_CONNECTED);
+
+ return;
+
+failed:
+ g_io_channel_shutdown(chan, TRUE, NULL);
+ device_cleanup();
+}
+
+static void confirm_cb(GIOChannel *chan, gpointer data)
+{
+ char address[18];
+ bdaddr_t bdaddr;
+ GError *err = NULL;
+
+ bt_io_get(chan, &err,
+ BT_IO_OPT_DEST, address,
+ BT_IO_OPT_DEST_BDADDR, &bdaddr,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ error("handsfree: confirm failed (%s)", err->message);
+ g_error_free(err);
+ goto drop;
+ }
+
+ DBG("incoming connect from %s", address);
+
+ if (device.state != HAL_EV_HANDSFREE_CONNECTION_STATE_DISCONNECTED) {
+ info("handsfree: refusing connection from %s", address);
+ goto drop;
+ }
+
+ device_init(&bdaddr);
+
+ if (!bt_io_accept(chan, connect_cb, NULL, NULL, NULL)) {
+ error("handsfree: failed to accept connection");
+ device_cleanup();
+ goto drop;
+ }
+
+ return;
+
+drop:
+ g_io_channel_shutdown(chan, TRUE, NULL);
+}
+
static void handle_connect(const void *buf, uint16_t len)
{
DBG("");
@@ -271,21 +409,33 @@ static sdp_record_t *handsfree_ag_record(void)
bool bt_handsfree_register(const bdaddr_t *addr)
{
sdp_record_t *rec;
+ GError *err = NULL;

DBG("");

bacpy(&adapter_addr, addr);

+ server = bt_io_listen( NULL, confirm_cb, NULL, 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,
+ BT_IO_OPT_INVALID);
+ if (!server) {
+ error("Failed to listen on Handsfree rfcomm: %s", err->message);
+ g_error_free(err);
+ return false;
+ }
+
rec = handsfree_ag_record();
if (!rec) {
error("Failed to allocate Handsfree record");
- return false;
+ goto failed;
}

if (bt_adapter_add_record(rec, 0) < 0) {
error("Failed to register Handsfree record");
sdp_record_free(rec);
- return false;
+ goto failed;
}
record_id = rec->handle;

@@ -293,6 +443,13 @@ bool bt_handsfree_register(const bdaddr_t *addr)
G_N_ELEMENTS(cmd_handlers));

return true;
+
+failed:
+ g_io_channel_shutdown(server, TRUE, NULL);
+ g_io_channel_unref(server);
+ server = NULL;
+
+ return false;
}

void bt_handsfree_unregister(void)
@@ -301,6 +458,12 @@ void bt_handsfree_unregister(void)

ipc_unregister(HAL_SERVICE_ID_HANDSFREE);

+ if (server) {
+ g_io_channel_shutdown(server, TRUE, NULL);
+ g_io_channel_unref(server);
+ server = NULL;
+ }
+
bt_adapter_remove_record(record_id);
record_id = 0;
}
--
1.8.5.3


2014-02-02 21:09:13

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 02/13] android/handsfree: Add commands and events definition to IPC header

---
android/hal-msg.h | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 208 insertions(+)

diff --git a/android/hal-msg.h b/android/hal-msg.h
index d46b428..56e1116 100644
--- a/android/hal-msg.h
+++ b/android/hal-msg.h
@@ -389,6 +389,130 @@ struct hal_cmd_pan_disconnect {
uint8_t bdaddr[6];
} __attribute__((packed));

+/* Handsfree HAL API */
+
+#define HAL_OP_HANDSFREE_CONNECT 0x01
+struct hal_cmd_handsfree_connect {
+ uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_DISCONNECT 0x02
+struct hal_cmd_handsfree_disconnect {
+ uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_CONNECT_AUDIO 0x03
+struct hal_cmd_handsfree_connect_audio {
+ uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_DISCONNECT_AUDIO 0x04
+struct hal_cmd_handsfree_disconnect_audio {
+ uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_START_VR 0x05
+
+#define HAL_OP_HANDSFREE_STOP_VR 0x06
+
+#define HAL_HANDSFREE_VOLUME_TYPE_SPEAKER 0x00
+#define HAL_HANDSFREE_VOLUME_TYPE_MIC 0x01
+
+#define HAL_OP_HANDSFREE_VOLUME_CONTROL 0x07
+struct hal_cmd_handsfree_volume_control {
+ uint8_t type;
+ uint32_t volume;
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_NETWORK_STATE_NOT_AVAILABLE 0x00
+#define HAL_HANDSFREE_NETWORK_STATE_AVAILABLE 0x01
+
+#define HAL_HANDSFREE_SERVICE_TYPE_HOME 0x00
+#define HAL_HANDSFREE_SERVICE_TYPE_ROAMING 0x01
+
+#define HAL_OP_HANDSFREE_DEVICE_STATUS_NOTIF 0x08
+struct hal_cmd_handsfree_device_status_notif {
+ uint8_t state;
+ uint8_t type;
+ uint32_t signal;
+ uint32_t battery;
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_COPS_RESPONSE 0x09
+struct hal_cmd_handsfree_cops_response {
+ uint32_t len;
+ uint8_t buf[0];
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_CALL_STATE_ACTIVE 0x00
+#define HAL_HANDSFREE_CALL_STATE_HELD 0x01
+#define HAL_HANDSFREE_CALL_STATE_DIALING 0x02
+#define HAL_HANDSFREE_CALL_STATE_ALERTING 0x03
+#define HAL_HANDSFREE_CALL_STATE_INCOMING 0x04
+#define HAL_HANDSFREE_CALL_STATE_WAITING 0x05
+#define HAL_HANDSFREE_CALL_STATE_IDLE 0x06
+
+#define HAL_OP_HANDSFREE_CIND_RESPONSE 0x0A
+struct hal_cmd_handsfree_cind_response {
+ uint32_t svc;
+ uint32_t num_active;
+ uint32_t num_held;
+ uint8_t state;
+ uint32_t signal;
+ uint32_t roam;
+ uint32_t batt_chg;
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_FORMATTED_AT_RESPONSE 0x0B
+struct hal_cmd_handsfree_formatted_at_response {
+ uint32_t len;
+ uint8_t buf[0];
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_AT_RESPONSE_ERROR 0x00
+#define HAL_HANDSFREE_AT_RESPONSE_OK 0x01
+
+#define HAL_OP_HANDSFREE_AT_RESPONSE 0x0C
+struct hal_cmd_handsfree_at_response {
+ uint8_t response;
+ uint32_t error;
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_CALL_DIRECTION_OUTGOING 0x00
+#define HAL_HANDSFREE_CALL_DIRECTION_INCOMING 0x01
+
+#define HAL_HANDSFREE_CALL_TYPE_VOICE 0x00
+#define HAL_HANDSFREE_CALL_TYPE_DATA 0x01
+#define HAL_HANDSFREE_CALL_TYPE_FAX 0x02
+
+#define HAL_HANDSFREE_CALL_MPTY_TYPE_SINGLE 0x00
+#define HAL_HANDSFREE_CALL_MPTY_TYPE_MULTI 0x01
+
+#define HAL_HANDSFREE_CALL_ADDRTYPE_UNKNOWN 0x81
+#define HAL_HANDSFREE_CALL_ADDRTYPE_INTERNATIONAL 0x91
+
+#define HAL_OP_HANDSFREE_CLCC_RESPONSE 0x0D
+struct hal_cmd_handsfree_clcc_response {
+ uint32_t index;
+ uint8_t dir;
+ uint8_t state;
+ uint8_t mode;
+ uint8_t mpty;
+ uint8_t type;
+ uint32_t number_len;
+ uint8_t number[0];
+} __attribute__((packed));
+
+#define HAL_OP_HANDSFREE_PHONE_STATE_CHANGE 0x0E
+struct hal_cmd_handsfree_phone_state_change {
+ uint32_t num_active;
+ uint32_t num_held;
+ uint8_t state;
+ uint8_t type;
+ uint32_t number_len;
+ uint8_t number[0];
+} __attribute__((packed));
+
/* Notifications and confirmations */

#define HAL_POWER_OFF 0x00
@@ -572,3 +696,87 @@ struct hal_ev_a2dp_audio_state {
uint8_t 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 0x81
+struct hal_ev_handsfree_conn_state {
+ uint8_t state;
+ uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_AUDIO_STATE_DISCONNECTED 0x00
+#define HAL_EV_HANDSFREE_AUDIO_STATE_CONNECTING 0x01
+#define HAL_EV_HANDSFREE_AUDIO_STATE_CONNECTED 0x02
+#define HAL_EV_HANDSFREE_AUDIO_STATE_DISCONNECTING 0x03
+
+#define HAL_EV_HANDSFREE_AUDIO_STATE 0x82
+struct hal_ev_handsfree_audio_state {
+ uint8_t state;
+ uint8_t bdaddr[6];
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_VR 0x83
+struct hal_ev_handsfree_vr_state {
+ uint8_t state;
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_ANSWER 0x84
+
+#define HAL_EV_HANDSFREE_HANGUP 0x85
+
+#define HAL_EV_HANDSFREE_VOLUME 0x86
+struct hal_ev_handsfree_volume {
+ uint8_t type;
+ uint32_t volume;
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_DIAL 0x87
+struct hal_ev_handsfree_dial {
+ uint32_t number_len;
+ uint8_t number[0];
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_DTMF 0x88
+struct hal_ev_handsfree_dtmf {
+ uint8_t tone;
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_NREC_STOP 0x00
+#define HAL_HANDSFREE_NREC_STart 0x01
+
+#define HAL_EV_HANDSFREE_NREC 0x89
+struct hal_ev_handsfree_nrec {
+ uint8_t nrec;
+} __attribute__((packed));
+
+#define HAL_HANDSFREE_CHLD_TYPE_RELEASEHELD 0x00
+#define HAL_HANDSFREE_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD 0x01
+#define HAL_HANDSFREE_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD 0x02
+#define HAL_HANDSFREE_CHLD_TYPE_ADDHELDTOCONF 0x03
+
+#define HAL_EV_HANDSFREE_CHLD 0x8A
+struct hal_ev_handsfree_chld {
+ uint8_t chld;
+} __attribute__((packed));
+
+
+#define HAL_EV_HANDSFREE_CNUM 0x8B
+
+#define HAL_EV_HANDSFREE_CIND 0x8C
+
+#define HAL_EV_HANDSFREE_COPS 0x8D
+
+#define HAL_EV_HANDSFREE_CLCC 0x8E
+
+#define HAL_EV_HANDSFREE_UNKNOWN_AT 0x8F
+struct hal_ev_handsfree_unknown_at {
+ uint32_t len;
+ uint8_t buf[0];
+} __attribute__((packed));
+
+#define HAL_EV_HANDSFREE_HSP_KEY_PRESS 0x90
--
1.8.5.3


2014-02-02 21:09:16

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 05/13] android/hal-handsfree: Implement sending commands

This implements HAL interface methods and pass commands over IPC.
---
android/hal-handsfree.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 344 insertions(+)

diff --git a/android/hal-handsfree.c b/android/hal-handsfree.c
index 6e11367..601c14f 100644
--- a/android/hal-handsfree.c
+++ b/android/hal-handsfree.c
@@ -223,6 +223,336 @@ static bt_status_t init(bthf_callbacks_t *callbacks)
return ret;
}

+static bt_status_t handsfree_connect(bt_bdaddr_t *bd_addr)
+{
+ struct hal_cmd_handsfree_connect cmd;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ if (!bd_addr)
+ return BT_STATUS_PARM_INVALID;
+
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CONNECT,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
+{
+ struct hal_cmd_handsfree_disconnect cmd;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ if (!bd_addr)
+ return BT_STATUS_PARM_INVALID;
+
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_DISCONNECT, sizeof(cmd), &cmd,
+ 0, NULL, NULL);
+}
+
+static bt_status_t connect_audio(bt_bdaddr_t *bd_addr)
+{
+ struct hal_cmd_handsfree_connect_audio cmd;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ if (!bd_addr)
+ return BT_STATUS_PARM_INVALID;
+
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_CONNECT_AUDIO, sizeof(cmd),
+ &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t disconnect_audio(bt_bdaddr_t *bd_addr)
+{
+ struct hal_cmd_handsfree_disconnect_audio cmd;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ if (!bd_addr)
+ return BT_STATUS_PARM_INVALID;
+
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_DISCONNECT_AUDIO, sizeof(cmd),
+ &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t start_voice_recognition(void)
+{
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_START_VR,
+ 0, NULL, 0, NULL, NULL);
+}
+
+static bt_status_t stop_voice_recognition(void)
+{
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_STOP_VR,
+ 0, NULL, 0, NULL, NULL);
+}
+
+static bt_status_t volume_control(bthf_volume_type_t type, int volume)
+{
+ struct hal_cmd_handsfree_volume_control cmd;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ cmd.type = type;
+ cmd.volume = volume;
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_VOLUME_CONTROL, sizeof(cmd),
+ &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t device_status_notification(bthf_network_state_t state,
+ bthf_service_type_t type,
+ int signal, int battery)
+{
+ struct hal_cmd_handsfree_device_status_notif cmd;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ cmd.state = state;
+ cmd.type = type;
+ cmd.signal = signal;
+ cmd.battery = battery;
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_DEVICE_STATUS_NOTIF,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t cops_response(const char *cops)
+{
+ struct hal_cmd_handsfree_cops_response *cmd;
+ bt_status_t status;
+ int len;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ if (!cops)
+ return BT_STATUS_PARM_INVALID;
+
+ len = sizeof(*cmd) + strlen(cops);
+
+ cmd = malloc(len);
+ if (!cmd)
+ return BT_STATUS_NOMEM;
+
+ cmd->len = strlen(cops);
+ memcpy(cmd->buf, cops, cmd->len);
+
+ status = hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_COPS_RESPONSE, len, cmd, 0,
+ NULL, NULL);
+
+ free(cmd);
+
+ return status;
+}
+
+static bt_status_t cind_response(int svc, int num_active, int num_held,
+ bthf_call_state_t state, int signal,
+ int roam, int batt_chg)
+{
+ struct hal_cmd_handsfree_cind_response cmd;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ cmd.svc = svc;
+ cmd.num_active = num_active;
+ cmd.num_held = num_held;
+ cmd.state = state;
+ cmd.signal = signal;
+ cmd.roam = roam;
+ cmd.batt_chg = batt_chg;
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_CIND_RESPONSE,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t formatted_at_response(const char *rsp)
+{
+ struct hal_cmd_handsfree_formatted_at_response *cmd;
+ bt_status_t status;
+ int len;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ if (!rsp)
+ return BT_STATUS_PARM_INVALID;
+
+ len = sizeof(*cmd) + strlen(rsp);
+
+ cmd = malloc(len);
+ if (!cmd)
+ return BT_STATUS_NOMEM;
+
+ cmd->len = strlen(rsp);
+ memcpy(cmd->buf, rsp, cmd->len);
+
+ status = hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_FORMATTED_AT_RESPONSE, len,
+ cmd, 0, NULL, NULL);
+
+ free(cmd);
+
+ return status;
+}
+
+static bt_status_t at_response(bthf_at_response_t response, int error)
+{
+ struct hal_cmd_handsfree_at_response cmd;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ cmd.response = response;
+ cmd.error = error;
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_AT_RESPONSE,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
+}
+
+static bt_status_t clcc_response(int index, bthf_call_direction_t dir,
+ bthf_call_state_t state,
+ bthf_call_mode_t mode,
+ bthf_call_mpty_type_t mpty,
+ const char *number,
+ bthf_call_addrtype_t type)
+{
+ struct hal_cmd_handsfree_clcc_response *cmd;
+ bt_status_t status;
+ int len;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ len = sizeof(*cmd);
+ if (number)
+ len += strlen(number);
+
+ cmd = malloc(len);
+ if (!cmd)
+ return BT_STATUS_NOMEM;
+
+ cmd->index = index;
+ cmd->dir = dir;
+ cmd->state = state;
+ cmd->mode = mode;
+ cmd->mpty = mpty;
+ cmd->type = type;
+
+ if (number) {
+ cmd->number_len = strlen(number);
+ memcpy(cmd->number, number, cmd->number_len);
+ } else {
+ cmd->number_len = 0;
+ }
+
+ status = hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_CLCC_RESPONSE, len,
+ cmd, 0, NULL, NULL);
+
+ free(cmd);
+
+ return status;
+}
+
+static bt_status_t phone_state_change(int num_active, int num_held,
+ bthf_call_state_t state,
+ const char *number,
+ bthf_call_addrtype_t type)
+{
+ struct hal_cmd_handsfree_phone_state_change *cmd;
+ bt_status_t status;
+ int len;
+
+ DBG("");
+
+ if (!interface_ready())
+ return BT_STATUS_NOT_READY;
+
+ len = sizeof(*cmd);
+ if (number)
+ len += strlen(number);
+
+ cmd = malloc(len);
+ if (!cmd)
+ return BT_STATUS_NOMEM;
+
+ cmd->num_active = num_active;
+ cmd->num_held = num_held;
+ cmd->state = state;
+ cmd->type = type;
+
+ if (number) {
+ cmd->number_len = strlen(number);
+ memcpy(cmd->number, number, cmd->number_len);
+ } else {
+ cmd->number_len = 0;
+ }
+
+ status = hal_ipc_cmd(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_PHONE_STATE_CHANGE,
+ len, cmd, 0, NULL, NULL);
+
+ free(cmd);
+
+ return status;
+}
+
static void cleanup(void)
{
struct hal_cmd_unregister_module cmd;
@@ -245,6 +575,20 @@ static void cleanup(void)
static bthf_interface_t iface = {
.size = sizeof(iface),
.init = init,
+ .connect = handsfree_connect,
+ .disconnect = disconnect,
+ .connect_audio = connect_audio,
+ .disconnect_audio = disconnect_audio,
+ .start_voice_recognition = start_voice_recognition,
+ .stop_voice_recognition = stop_voice_recognition,
+ .volume_control = volume_control,
+ .device_status_notification = device_status_notification,
+ .cops_response = cops_response,
+ .cind_response = cind_response,
+ .formatted_at_response = formatted_at_response,
+ .at_response = at_response,
+ .clcc_response = clcc_response,
+ .phone_state_change = phone_state_change,
.cleanup = cleanup
};

--
1.8.5.3


2014-02-02 21:09:14

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 03/13] android/handsfree: Add stubs for commands handlers

Add empty handlers for all IPC commands.
---
android/handsfree.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 169 insertions(+), 1 deletion(-)

diff --git a/android/handsfree.c b/android/handsfree.c
index fb48ff1..3c0d52b 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -26,16 +26,184 @@
#endif

#include <stdbool.h>
+#include <glib.h>

#include "lib/bluetooth.h"
#include "handsfree.h"
+#include "src/log.h"
+#include "hal-msg.h"
+#include "ipc.h"
+
+static bdaddr_t adapter_addr;
+
+static void handle_connect(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CONNECT,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_disconnect(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_DISCONNECT,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_connect_audio(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CONNECT_AUDIO,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_disconnect_audio(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_DISCONNECT_AUDIO, HAL_STATUS_FAILED);
+}
+
+static void handle_start_vr(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_START_VR,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_stop_vr(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_STOP_VR,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_volume_control(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_VOLUME_CONTROL,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_device_status_notif(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_DEVICE_STATUS_NOTIF,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_cops(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_COPS_RESPONSE,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_cind(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CIND_RESPONSE,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_formatted_at_resp(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_FORMATTED_AT_RESPONSE,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_at_resp(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_AT_RESPONSE,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_clcc_resp(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE, HAL_OP_HANDSFREE_CLCC_RESPONSE,
+ HAL_STATUS_FAILED);
+}
+
+static void handle_phone_state_change(const void *buf, uint16_t len)
+{
+ DBG("");
+
+ ipc_send_rsp(HAL_SERVICE_ID_HANDSFREE,
+ HAL_OP_HANDSFREE_PHONE_STATE_CHANGE,
+ HAL_STATUS_FAILED);
+}
+
+static const struct ipc_handler cmd_handlers[] = {
+ /* HAL_OP_HANDSFREE_CONNECT */
+ { handle_connect, false, sizeof(struct hal_cmd_handsfree_connect)},
+ /* HAL_OP_HANDSFREE_DISCONNECT */
+ {handle_disconnect, false, sizeof(struct hal_cmd_handsfree_disconnect)},
+ /*HAL_OP_HANDSFREE_CONNECT_AUDIO*/
+ {handle_connect_audio, false,
+ sizeof(struct hal_cmd_handsfree_connect_audio)},
+ /*HAL_OP_HANDSFREE_DISCONNECT_AUDIO*/
+ {handle_disconnect_audio, false,
+ sizeof(struct hal_cmd_handsfree_disconnect_audio)},
+ /* define HAL_OP_HANDSFREE_START_VR */
+ {handle_start_vr, false, 0 },
+ /* define HAL_OP_HANDSFREE_STOP_VR */
+ {handle_stop_vr, false, 0 },
+ /* HAL_OP_HANDSFREE_VOLUME_CONTROL */
+ {handle_volume_control, false,
+ sizeof(struct hal_cmd_handsfree_volume_control)},
+ /* HAL_OP_HANDSFREE_DEVICE_STATUS_NOTIF */
+ {handle_device_status_notif, false,
+ sizeof(struct hal_cmd_handsfree_device_status_notif)},
+ /* HAL_OP_HANDSFREE_COPS_RESPONSE */
+ {handle_cops, true, sizeof(struct hal_cmd_handsfree_cops_response)},
+ /* HAL_OP_HANDSFREE_CIND_RESPONSE */
+ { handle_cind, false, sizeof(struct hal_cmd_handsfree_cind_response)},
+ /* HAL_OP_HANDSFREE_FORMATTED_AT_RESPONSE */
+ {handle_formatted_at_resp, true,
+ sizeof(struct hal_cmd_handsfree_formatted_at_response)},
+ /* HAL_OP_HANDSFREE_AT_RESPONSE */
+ {handle_at_resp, false, sizeof(struct hal_cmd_handsfree_at_response)},
+ /* HAL_OP_HANDSFREE_CLCC_RESPONSE */
+ {handle_clcc_resp, true,
+ sizeof(struct hal_cmd_handsfree_clcc_response)},
+ /* HAL_OP_HANDSFREE_PHONE_STATE_CHANGE */
+ {handle_phone_state_change, true,
+ sizeof(struct hal_cmd_handsfree_phone_state_change)},
+};

bool bt_handsfree_register(const bdaddr_t *addr)
{
- return false;
+ DBG("");
+
+ bacpy(&adapter_addr, addr);
+
+ ipc_register(HAL_SERVICE_ID_HANDSFREE, cmd_handlers,
+ G_N_ELEMENTS(cmd_handlers));
+
+ return true;
}

void bt_handsfree_unregister(void)
{
+ DBG("");

+ ipc_unregister(HAL_SERVICE_ID_HANDSFREE);
}
--
1.8.5.3


2014-02-02 21:09:15

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 04/13] android/hal-handsfree: Implement notifications handling

This implements all notifications handlers and call proper HAL
callbacks.
---
android/hal-handsfree.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 159 insertions(+), 1 deletion(-)

diff --git a/android/hal-handsfree.c b/android/hal-handsfree.c
index 181e05f..6e11367 100644
--- a/android/hal-handsfree.c
+++ b/android/hal-handsfree.c
@@ -18,6 +18,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
+#include <stdlib.h>

#include "hal-log.h"
#include "hal.h"
@@ -31,10 +32,167 @@ static bool interface_ready(void)
return cbs != NULL;
}

+static void handle_conn_state(void *buf, uint16_t len)
+{
+ struct hal_ev_handsfree_conn_state *ev = buf;
+
+ if (cbs->connection_state_cb)
+ cbs->connection_state_cb(ev->state,
+ (bt_bdaddr_t *) (ev->bdaddr));
+}
+
+static void handle_audio_state(void *buf, uint16_t len)
+{
+ struct hal_ev_handsfree_audio_state *ev = buf;
+
+ if (cbs->audio_state_cb)
+ cbs->audio_state_cb(ev->state, (bt_bdaddr_t *) (ev->bdaddr));
+}
+
+static void handle_vr_state(void *buf, uint16_t len)
+{
+ struct hal_ev_handsfree_vr_state *ev = buf;
+
+ if (cbs->vr_cmd_cb)
+ cbs->vr_cmd_cb(ev->state);
+}
+
+static void handle_answer(void *buf, uint16_t len)
+{
+ if (cbs->answer_call_cmd_cb)
+ cbs->answer_call_cmd_cb();
+}
+
+static void handle_hangup(void *buf, uint16_t len)
+{
+ if (cbs->hangup_call_cmd_cb)
+ cbs->hangup_call_cmd_cb();
+}
+
+static void handle_volume(void *buf, uint16_t len)
+{
+ struct hal_ev_handsfree_volume *ev = buf;
+
+ if (cbs->volume_cmd_cb)
+ cbs->volume_cmd_cb(ev->type, ev->volume);
+}
+
+static void handle_dial(void *buf, uint16_t len)
+{
+ struct hal_ev_handsfree_dial *ev = buf;
+
+ if (len != sizeof(*ev) + ev->number_len) {
+ error("invalid dial event, aborting");
+ exit(EXIT_FAILURE);
+ }
+
+ if (cbs->dial_call_cmd_cb)
+ cbs->dial_call_cmd_cb((char *) ev->number);
+}
+
+static void handle_dtmf(void *buf, uint16_t len)
+{
+ struct hal_ev_handsfree_dtmf *ev = buf;
+
+ if (cbs->dtmf_cmd_cb)
+ cbs->dtmf_cmd_cb(ev->tone);
+}
+
+static void handle_nrec(void *buf, uint16_t len)
+{
+ struct hal_ev_handsfree_nrec *ev = buf;
+
+ if (cbs->nrec_cmd_cb)
+ cbs->nrec_cmd_cb(ev->nrec);
+}
+
+static void handle_chld(void *buf, uint16_t len)
+{
+ struct hal_ev_handsfree_chld *ev = buf;
+
+ if (cbs->chld_cmd_cb)
+ cbs->chld_cmd_cb(ev->chld);
+}
+
+static void handle_cnum(void *buf, uint16_t len)
+{
+ if (cbs->cnum_cmd_cb)
+ cbs->cnum_cmd_cb();
+}
+
+static void handle_cind(void *buf, uint16_t len)
+{
+ if (cbs->cind_cmd_cb)
+ cbs->cind_cmd_cb();
+}
+
+static void handle_cops(void *buf, uint16_t len)
+{
+ if (cbs->cops_cmd_cb)
+ cbs->cops_cmd_cb();
+}
+
+static void handle_clcc(void *buf, uint16_t len)
+{
+ if (cbs->clcc_cmd_cb)
+ cbs->clcc_cmd_cb();
+}
+
+static void handle_unknown_at(void *buf, uint16_t len)
+{
+ struct hal_ev_handsfree_unknown_at *ev = buf;
+
+ if (len != sizeof(*ev) + ev->len) {
+ error("invalid dial event, aborting");
+ exit(EXIT_FAILURE);
+ }
+
+ if (cbs->unknown_at_cmd_cb)
+ cbs->unknown_at_cmd_cb((char *) ev->buf);
+}
+
+static void handle_hsp_key_press(void *buf, uint16_t len)
+{
+ if (cbs->key_pressed_cmd_cb)
+ cbs->key_pressed_cmd_cb();
+}
+
/* handlers will be called from notification thread context,
* index in table equals to 'opcode - HAL_MINIMUM_EVENT' */
static const struct hal_ipc_handler ev_handlers[] = {
-
+ /* HAL_EV_HANDSFREE_CONN_STATE */
+ {handle_conn_state, false, sizeof(struct hal_ev_handsfree_conn_state)},
+ /* HAL_EV_HANDSFREE_AUDIO_STATE */
+ {handle_audio_state, false,
+ sizeof(struct hal_ev_handsfree_audio_state)},
+ /* HAL_EV_HANDSFREE_VR */
+ {handle_vr_state, false, sizeof(struct hal_ev_handsfree_vr_state)},
+ /*HAL_EV_HANDSFREE_ANSWER */
+ {handle_answer, false, 0},
+ /*HAL_EV_HANDSFREE_HANGUP */
+ {handle_hangup, false, 0},
+ /* HAL_EV_HANDSFREE_VOLUME */
+ {handle_volume, false, sizeof(struct hal_ev_handsfree_volume)},
+ /* HAL_EV_HANDSFREE_DIAL */
+ {handle_dial, true, sizeof(struct hal_ev_handsfree_dial)},
+ /* HAL_EV_HANDSFREE_DTMF */
+ {handle_dtmf, false, sizeof(struct hal_ev_handsfree_dtmf)},
+ /* HAL_EV_HANDSFREE_NREC */
+ {handle_nrec, false, sizeof(struct hal_ev_handsfree_nrec)},
+ /* HAL_EV_HANDSFREE_CHLD */
+ {handle_chld, false, sizeof(struct hal_ev_handsfree_chld)},
+ /* HAL_EV_HANDSFREE_CNUM */
+ {handle_cnum, false, 0},
+ /* HAL_EV_HANDSFREE_CIND */
+ {handle_cind, false, 0},
+ /* HAL_EV_HANDSFREE_COPS */
+ {handle_cops, false, 0},
+ /* HAL_EV_HANDSFREE_CLCC */
+ {handle_clcc, false, 0},
+ /* HAL_EV_HANDSFREE_UNKNOWN_AT */
+ {handle_unknown_at, true, sizeof(struct hal_ev_handsfree_unknown_at)},
+ /* HAL_EV_HANDSFREE_HSP_KEY_PRESS */
+ {handle_hsp_key_press, false, 0},
};

static bt_status_t init(bthf_callbacks_t *callbacks)
--
1.8.5.3


2014-02-02 21:09:12

by Szymon Janc

[permalink] [raw]
Subject: [PATCH 01/13] android/handsfree: Add initial files

This adds initial HAL and daemon code for Handsfree profile.
---
android/Android.mk | 2 ++
android/Makefile.am | 2 ++
android/hal-bluetooth.c | 3 ++
android/hal-handsfree.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++
android/hal.h | 2 ++
android/handsfree.c | 41 +++++++++++++++++++++
android/handsfree.h | 25 +++++++++++++
android/main.c | 14 ++++++++
8 files changed, 185 insertions(+)
create mode 100644 android/hal-handsfree.c
create mode 100644 android/handsfree.c
create mode 100644 android/handsfree.h

diff --git a/android/Android.mk b/android/Android.mk
index 03f2d8b..c16f29a 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -32,6 +32,7 @@ LOCAL_SRC_FILES := \
bluez/android/avctp.c \
bluez/android/avrcp.c \
bluez/android/pan.c \
+ bluez/android/handsfree.c \
bluez/src/log.c \
bluez/src/shared/mgmt.c \
bluez/src/shared/util.c \
@@ -108,6 +109,7 @@ LOCAL_SRC_FILES := \
bluez/android/hal-pan.c \
bluez/android/hal-a2dp.c \
bluez/android/hal-avrcp.c \
+ bluez/android/hal-handsfree.c \
bluez/android/hal-utils.c \

LOCAL_C_INCLUDES += \
diff --git a/android/Makefile.am b/android/Makefile.am
index e065c0c..23e30c9 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -37,6 +37,7 @@ android_bluetoothd_SOURCES = android/main.c \
android/avrcp.h android/avrcp.c \
android/socket.h android/socket.c \
android/pan.h android/pan.c \
+ android/handsfree.h android/handsfree.c \
btio/btio.h btio/btio.c \
src/sdp-client.h src/sdp-client.c \
profiles/network/bnep.h profiles/network/bnep.c
@@ -51,6 +52,7 @@ android_bluetooth_default_la_SOURCES = android/hal.h android/hal-bluetooth.c \
android/hal-pan.c \
android/hal-a2dp.c \
android/hal-avrcp.c \
+ android/hal-handsfree.c \
android/hardware/bluetooth.h \
android/hardware/bt_av.h \
android/hardware/bt_gatt.h \
diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c
index 0dac158..67c91e4 100644
--- a/android/hal-bluetooth.c
+++ b/android/hal-bluetooth.c
@@ -765,6 +765,9 @@ static const void *get_profile_interface(const char *profile_id)
if (!strcmp(profile_id, BT_PROFILE_AV_RC_ID))
return bt_get_avrcp_interface();

+ if (!strcmp(profile_id, BT_PROFILE_HANDSFREE_ID))
+ return bt_get_handsfree_interface();
+
return NULL;
}

diff --git a/android/hal-handsfree.c b/android/hal-handsfree.c
new file mode 100644
index 0000000..181e05f
--- /dev/null
+++ b/android/hal-handsfree.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "hal-log.h"
+#include "hal.h"
+#include "hal-msg.h"
+#include "hal-ipc.h"
+
+static const bthf_callbacks_t *cbs = NULL;
+
+static bool interface_ready(void)
+{
+ return cbs != NULL;
+}
+
+/* handlers will be called from notification thread context,
+ * index in table equals to 'opcode - HAL_MINIMUM_EVENT' */
+static const struct hal_ipc_handler ev_handlers[] = {
+
+};
+
+static bt_status_t init(bthf_callbacks_t *callbacks)
+{
+ struct hal_cmd_register_module cmd;
+ int ret;
+
+ DBG("");
+
+ if (interface_ready())
+ return BT_STATUS_DONE;
+
+ cbs = callbacks;
+
+ hal_ipc_register(HAL_SERVICE_ID_HANDSFREE, ev_handlers,
+ sizeof(ev_handlers)/sizeof(ev_handlers[0]));
+
+ cmd.service_id = HAL_SERVICE_ID_HANDSFREE;
+
+ ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
+
+ if (ret != BT_STATUS_SUCCESS) {
+ cbs = NULL;
+ hal_ipc_unregister(HAL_SERVICE_ID_HANDSFREE);
+ }
+
+ return ret;
+}
+
+static void cleanup(void)
+{
+ struct hal_cmd_unregister_module cmd;
+
+ DBG("");
+
+ if (!interface_ready())
+ return;
+
+ cbs = NULL;
+
+ cmd.service_id = HAL_SERVICE_ID_HANDSFREE;
+
+ hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
+
+ hal_ipc_unregister(HAL_SERVICE_ID_HANDSFREE);
+}
+
+static bthf_interface_t iface = {
+ .size = sizeof(iface),
+ .init = init,
+ .cleanup = cleanup
+};
+
+bthf_interface_t *bt_get_handsfree_interface(void)
+{
+ return &iface;
+}
diff --git a/android/hal.h b/android/hal.h
index 1ff4fbd..5005b49 100644
--- a/android/hal.h
+++ b/android/hal.h
@@ -21,12 +21,14 @@
#include <hardware/bt_pan.h>
#include <hardware/bt_av.h>
#include <hardware/bt_rc.h>
+#include <hardware/bt_hf.h>

btsock_interface_t *bt_get_sock_interface(void);
bthh_interface_t *bt_get_hidhost_interface(void);
btpan_interface_t *bt_get_pan_interface(void);
btav_interface_t *bt_get_a2dp_interface(void);
btrc_interface_t *bt_get_avrcp_interface(void);
+bthf_interface_t *bt_get_handsfree_interface(void);

void bt_thread_associate(void);
void bt_thread_disassociate(void);
diff --git a/android/handsfree.c b/android/handsfree.c
new file mode 100644
index 0000000..fb48ff1
--- /dev/null
+++ b/android/handsfree.c
@@ -0,0 +1,41 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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 <stdbool.h>
+
+#include "lib/bluetooth.h"
+#include "handsfree.h"
+
+bool bt_handsfree_register(const bdaddr_t *addr)
+{
+ return false;
+}
+
+void bt_handsfree_unregister(void)
+{
+
+}
diff --git a/android/handsfree.h b/android/handsfree.h
new file mode 100644
index 0000000..799fcb6
--- /dev/null
+++ b/android/handsfree.h
@@ -0,0 +1,25 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ *
+ * 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
+ *
+ */
+
+bool bt_handsfree_register(const bdaddr_t *addr);
+void bt_handsfree_unregister(void);
diff --git a/android/main.c b/android/main.c
index 417dbc3..d9d0572 100644
--- a/android/main.c
+++ b/android/main.c
@@ -56,6 +56,7 @@
#include "a2dp.h"
#include "pan.h"
#include "avrcp.h"
+#include "handsfree.h"

#define STARTUP_GRACE_SECONDS 5
#define SHUTDOWN_GRACE_SECONDS 10
@@ -115,6 +116,13 @@ static void service_register(const void *buf, uint16_t len)
}

break;
+ case HAL_SERVICE_ID_HANDSFREE:
+ if (!bt_handsfree_register(&adapter_bdaddr)) {
+ status = HAL_STATUS_FAILED;
+ goto failed;
+ }
+
+ break;
default:
DBG("service %u not supported", m->service_id);
status = HAL_STATUS_FAILED;
@@ -160,6 +168,9 @@ static void service_unregister(const void *buf, uint16_t len)
case HAL_SERVICE_ID_AVRCP:
bt_avrcp_unregister();
break;
+ case HAL_SERVICE_ID_HANDSFREE:
+ bt_handsfree_unregister();
+ break;
default:
/* This would indicate bug in HAL, as unregister should not be
* called in init failed */
@@ -338,6 +349,9 @@ static void cleanup_services(void)
case HAL_SERVICE_ID_PAN:
bt_pan_unregister();
break;
+ case HAL_SERVICE_ID_HANDSFREE:
+ bt_handsfree_unregister();
+ break;
}

services[i] = false;
--
1.8.5.3