* [PATCHv4 03/14] shared/gatt: Discover included services 128 bit UUIDS
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
If included services has 128 bit UUID, it won't be returned in
READ_BY_TYPE_RSP. To get UUID READ_REQUEST is used.
This procedure is described in CORE SPEC 4.5.1 "Find Included Services".
---
src/shared/gatt-helpers.c | 170 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 169 insertions(+), 1 deletion(-)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index dcb2a2f..c18f738 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -692,6 +692,160 @@ bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid,
destroy, false);
}
+struct read_incl_data {
+ struct discovery_op *op;
+ struct bt_gatt_result *result;
+ int pos;
+ int ref_count;
+};
+
+static struct read_incl_data *new_read_included(struct bt_gatt_result *res)
+{
+ struct read_incl_data *data;
+
+ data = new0(struct read_incl_data, 1);
+ if (!data)
+ return NULL;
+
+ data->op = discovery_op_ref(res->op);
+ data->result = res;
+
+ return data;
+};
+
+static struct read_incl_data *read_included_ref(struct read_incl_data *data)
+{
+ __sync_fetch_and_add(&data->ref_count, 1);
+
+ return data;
+}
+
+static void read_included_unref(void *data)
+{
+ struct read_incl_data *read_data = data;
+
+ if (__sync_sub_and_fetch(&read_data->ref_count, 1))
+ return;
+
+ discovery_op_unref(read_data->op);
+
+ free(read_data);
+}
+
+static void discover_included_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data);
+
+static void read_included_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ struct read_incl_data *data = user_data;
+ struct bt_gatt_result *final_result = NULL;
+ struct discovery_op *op = data->op;
+ struct bt_gatt_result *cur_result;
+ uint8_t att_ecode = 0;
+ uint16_t handle;
+ uint8_t read_pdu[2];
+ bool success;
+
+ if (opcode == BT_ATT_OP_ERROR_RSP) {
+ success = false;
+ att_ecode = process_error(pdu, length);
+ goto done;
+ }
+
+ if (opcode != BT_ATT_OP_READ_RSP || (!pdu && length)) {
+ success = false;
+ goto done;
+ }
+
+ if (length != 16) {
+ success = false;
+ goto done;
+ }
+ cur_result = result_create(opcode, pdu, length, length, op);
+ if (!cur_result) {
+ success = false;
+ goto done;
+ }
+
+ if (!op->result_head)
+ op->result_head = op->result_tail = cur_result;
+ else {
+ op->result_tail->next = cur_result;
+ op->result_tail = cur_result;
+ }
+
+ if (data->pos == data->result->pdu_len) {
+ uint16_t last_handle, data_len;
+ uint8_t pdu[6];
+
+ data_len = data->result->data_len;
+ last_handle = get_le16(data->result->pdu + data->pos -
+ data_len);
+ if (last_handle == op->end_handle) {
+ final_result = op->result_head;
+ success = true;
+ goto done;
+ }
+
+ put_le16(last_handle + 1, pdu);
+ put_le16(op->end_handle, pdu + 2);
+ put_le16(GATT_INCLUDE_UUID, pdu + 4);
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
+ pdu, sizeof(pdu),
+ discover_included_cb,
+ discovery_op_ref(op),
+ discovery_op_unref))
+ return;
+
+ discovery_op_unref(op);
+ success = false;
+ goto done;
+ }
+
+ handle = get_le16(data->result->pdu + data->pos + 2);
+ put_le16(handle, read_pdu);
+
+ data->pos += data->result->data_len;
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_REQ, read_pdu, sizeof(read_pdu),
+ read_included_cb,
+ read_included_ref(data),
+ read_included_unref))
+ return;
+
+ read_included_unref(data);
+ success = false;
+
+done:
+ if (op->callback)
+ op->callback(success, att_ecode, final_result, op->user_data);
+}
+
+static void read_included(struct read_incl_data *data)
+{
+ struct discovery_op *op = data->op;
+ uint16_t handle;
+ uint8_t pdu[2];
+
+ handle = get_le16(data->result->pdu + 2);
+ put_le16(handle, pdu);
+
+ data->pos += data->result->data_len;
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_REQ, pdu, sizeof(pdu),
+ read_included_cb,
+ read_included_ref(data),
+ read_included_unref))
+ return;
+
+ read_included_unref(data);
+
+ if (op->callback)
+ op->callback(false, 0, NULL, data->op->user_data);
+}
+
static void discover_included_cb(uint8_t opcode, const void *pdu,
uint16_t length, void *user_data)
{
@@ -721,7 +875,8 @@ static void discover_included_cb(uint8_t opcode, const void *pdu,
data_length = ((uint8_t *) pdu)[0];
- if ((length - 1) % data_length || data_length != 8) {
+ if (((length - 1) % data_length) ||
+ (data_length != 8 && data_length != 6)) {
success = false;
goto done;
}
@@ -740,6 +895,19 @@ static void discover_included_cb(uint8_t opcode, const void *pdu,
op->result_tail = cur_result;
}
+ if (data_length == 6) {
+ struct read_incl_data *data;
+
+ data = new_read_included(cur_result);
+ if (!data) {
+ success = false;
+ goto done;
+ }
+
+ read_included(data);
+ return;
+ }
+
last_handle = get_le16(pdu + length - data_length);
if (last_handle != op->end_handle) {
uint8_t pdu[6];
--
1.9.3
^ permalink raw reply related
* [PATCHv4 02/14] shared/gatt: Add initial implementation of discover_included_services
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
Current implementation allow to discover included services with
16 bit UUID only.
---
src/shared/gatt-helpers.c | 108 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 2 deletions(-)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index 4dc787f..dcb2a2f 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -692,6 +692,82 @@ bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid,
destroy, false);
}
+static void discover_included_cb(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data)
+{
+ struct bt_gatt_result *final_result = NULL;
+ struct discovery_op *op = user_data;
+ struct bt_gatt_result *cur_result;
+ uint8_t att_ecode = 0;
+ uint16_t last_handle;
+ size_t data_length;
+ bool success;
+
+ if (opcode == BT_ATT_OP_ERROR_RSP) {
+ success = false;
+ att_ecode = process_error(pdu, length);
+
+ if (att_ecode == BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND &&
+ op->result_head)
+ goto success;
+
+ goto done;
+ }
+
+ if (opcode != BT_ATT_OP_READ_BY_TYPE_RSP || !pdu || length < 6) {
+ success = false;
+ goto done;
+ }
+
+ data_length = ((uint8_t *) pdu)[0];
+
+ if ((length - 1) % data_length || data_length != 8) {
+ success = false;
+ goto done;
+ }
+
+ cur_result = result_create(opcode, pdu + 1, length - 1,
+ data_length, op);
+ if (!cur_result) {
+ success = false;
+ goto done;
+ }
+
+ if (!op->result_head)
+ op->result_head = op->result_tail = cur_result;
+ else {
+ op->result_tail->next = cur_result;
+ op->result_tail = cur_result;
+ }
+
+ last_handle = get_le16(pdu + length - data_length);
+ if (last_handle != op->end_handle) {
+ uint8_t pdu[6];
+
+ put_le16(last_handle + 1, pdu);
+ put_le16(op->end_handle, pdu + 2);
+ put_le16(GATT_INCLUDE_UUID, pdu + 4);
+
+ if (bt_att_send(op->att, BT_ATT_OP_READ_BY_TYPE_REQ,
+ pdu, sizeof(pdu),
+ discover_included_cb,
+ discovery_op_ref(op),
+ discovery_op_unref))
+ return;
+
+ discovery_op_unref(op);
+ success = false;
+ }
+
+success:
+ success = true;
+ final_result = op->result_head;
+
+done:
+ if (op->callback)
+ op->callback(success, att_ecode, final_result, op->user_data);
+}
+
bool bt_gatt_discover_included_services(struct bt_att *att,
uint16_t start, uint16_t end,
bt_uuid_t *uuid,
@@ -699,8 +775,36 @@ bool bt_gatt_discover_included_services(struct bt_att *att,
void *user_data,
bt_gatt_destroy_func_t destroy)
{
- /* TODO */
- return false;
+ struct discovery_op *op;
+ uint8_t pdu[6];
+
+ if (!att)
+ return false;
+
+ op = new0(struct discovery_op, 1);
+ if (!op)
+ return false;
+
+ op->att = att;
+ op->callback = callback;
+ op->user_data = user_data;
+ op->destroy = destroy;
+ op->end_handle = end;
+
+ put_le16(start, pdu);
+ put_le16(end, pdu + 2);
+ put_le16(GATT_INCLUDE_UUID, pdu + 4);
+
+ if (!bt_att_send(att, BT_ATT_OP_READ_BY_TYPE_REQ,
+ pdu, sizeof(pdu),
+ discover_included_cb,
+ discovery_op_ref(op),
+ discovery_op_unref)) {
+ free(op);
+ return false;
+ }
+
+ return true;
}
static void discover_chrcs_cb(uint8_t opcode, const void *pdu,
--
1.9.3
^ permalink raw reply related
* [PATCHv4 01/14] shared/gatt: Add discover_secondary_services()
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412932548-28363-1-git-send-email-marcin.kraglak@tieto.com>
This pach implements searching Secondary Services in given range.
---
src/shared/gatt-helpers.c | 56 +++++++++++++++++++++++++++++++++--------------
src/shared/gatt-helpers.h | 5 +++++
2 files changed, 45 insertions(+), 16 deletions(-)
diff --git a/src/shared/gatt-helpers.c b/src/shared/gatt-helpers.c
index 55e6992..4dc787f 100644
--- a/src/shared/gatt-helpers.c
+++ b/src/shared/gatt-helpers.c
@@ -175,6 +175,7 @@ struct discovery_op {
uint16_t end_handle;
int ref_count;
bt_uuid_t uuid;
+ uint16_t service_type;
struct bt_gatt_result *result_head;
struct bt_gatt_result *result_tail;
bt_gatt_discovery_callback_t callback;
@@ -487,7 +488,7 @@ static void read_by_grp_type_cb(uint8_t opcode, const void *pdu,
put_le16(last_end + 1, pdu);
put_le16(op->end_handle, pdu + 2);
- put_le16(GATT_PRIM_SVC_UUID, pdu + 4);
+ put_le16(op->service_type, pdu + 4);
if (bt_att_send(op->att, BT_ATT_OP_READ_BY_GRP_TYPE_REQ,
pdu, sizeof(pdu),
@@ -569,7 +570,7 @@ static void find_by_type_val_cb(uint8_t opcode, const void *pdu,
put_le16(last_end + 1, pdu);
put_le16(op->end_handle, pdu + 2);
- put_le16(GATT_PRIM_SVC_UUID, pdu + 4);
+ put_le16(op->service_type, pdu + 4);
put_uuid_le(&op->uuid, pdu + 6);
if (bt_att_send(op->att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
@@ -594,21 +595,12 @@ done:
op->callback(success, att_ecode, final_result, op->user_data);
}
-bool bt_gatt_discover_all_primary_services(struct bt_att *att, bt_uuid_t *uuid,
- bt_gatt_discovery_callback_t callback,
- void *user_data,
- bt_gatt_destroy_func_t destroy)
-{
- return bt_gatt_discover_primary_services(att, uuid, 0x0001, 0xffff,
- callback, user_data,
- destroy);
-}
-
-bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
+static bool discover_services(struct bt_att *att, bt_uuid_t *uuid,
uint16_t start, uint16_t end,
bt_gatt_discovery_callback_t callback,
void *user_data,
- bt_gatt_destroy_func_t destroy)
+ bt_gatt_destroy_func_t destroy,
+ bool primary)
{
struct discovery_op *op;
bool result;
@@ -625,6 +617,8 @@ bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
op->callback = callback;
op->user_data = user_data;
op->destroy = destroy;
+ /* set service uuid to primary or secondary */
+ op->service_type = primary ? GATT_PRIM_SVC_UUID : GATT_SND_SVC_UUID;
/* If UUID is NULL, then discover all primary services */
if (!uuid) {
@@ -632,7 +626,7 @@ bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
put_le16(start, pdu);
put_le16(end, pdu + 2);
- put_le16(GATT_PRIM_SVC_UUID, pdu + 4);
+ put_le16(op->service_type, pdu + 4);
result = bt_att_send(att, BT_ATT_OP_READ_BY_GRP_TYPE_REQ,
pdu, sizeof(pdu),
@@ -652,7 +646,7 @@ bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
put_le16(start, pdu);
put_le16(end, pdu + 2);
- put_le16(GATT_PRIM_SVC_UUID, pdu + 4);
+ put_le16(op->service_type, pdu + 4);
put_uuid_le(&op->uuid, pdu + 6);
result = bt_att_send(att, BT_ATT_OP_FIND_BY_TYPE_VAL_REQ,
@@ -668,6 +662,36 @@ bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
return result;
}
+bool bt_gatt_discover_all_primary_services(struct bt_att *att, bt_uuid_t *uuid,
+ bt_gatt_discovery_callback_t callback,
+ void *user_data,
+ bt_gatt_destroy_func_t destroy)
+{
+ return bt_gatt_discover_primary_services(att, uuid, 0x0001, 0xffff,
+ callback, user_data,
+ destroy);
+}
+
+bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
+ uint16_t start, uint16_t end,
+ bt_gatt_discovery_callback_t callback,
+ void *user_data,
+ bt_gatt_destroy_func_t destroy)
+{
+ return discover_services(att, uuid, start, end, callback, user_data,
+ destroy, true);
+}
+
+bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid,
+ uint16_t start, uint16_t end,
+ bt_gatt_discovery_callback_t callback,
+ void *user_data,
+ bt_gatt_destroy_func_t destroy)
+{
+ return discover_services(att, uuid, start, end, callback, user_data,
+ destroy, false);
+}
+
bool bt_gatt_discover_included_services(struct bt_att *att,
uint16_t start, uint16_t end,
bt_uuid_t *uuid,
diff --git a/src/shared/gatt-helpers.h b/src/shared/gatt-helpers.h
index f6f4b62..8a25dea 100644
--- a/src/shared/gatt-helpers.h
+++ b/src/shared/gatt-helpers.h
@@ -72,6 +72,11 @@ bool bt_gatt_discover_primary_services(struct bt_att *att, bt_uuid_t *uuid,
bt_gatt_discovery_callback_t callback,
void *user_data,
bt_gatt_destroy_func_t destroy);
+bool bt_gatt_discover_secondary_services(struct bt_att *att, bt_uuid_t *uuid,
+ uint16_t start, uint16_t end,
+ bt_gatt_discovery_callback_t callback,
+ void *user_data,
+ bt_gatt_destroy_func_t destroy);
bool bt_gatt_discover_included_services(struct bt_att *att,
uint16_t start, uint16_t end,
bt_uuid_t *uuid,
--
1.9.3
^ permalink raw reply related
* [PATCHv4 00/14] Included service discovery
From: Marcin Kraglak @ 2014-10-10 9:15 UTC (permalink / raw)
To: linux-bluetooth
Current implementation was tested with PTS GATT test case
TC_GAD_CL_BV_03_C.
v3:
In this version after primary service discovery,
secondary services are discovered. Next included
services are resolved. With this approach we
don't have recursively search for included service,
like it was TODO in previous proposal.
There is also small coding style fix suggested by Arman.
v4:
If no secondary services found, continue include services search (fixed
in gatt-client.c).
Fixed wrong debug logs (primary->secondary).
Fixed searching descriptors
Marcin Kraglak (14):
shared/gatt: Add discover_secondary_services()
shared/gatt: Add initial implementation of discover_included_services
shared/gatt: Discover included services 128 bit UUIDS
shared/gatt: Add extra check in characteristic iterator
shared/gatt: Add included service iterator
shared/gatt: Remove not needed function parameter
shared/gatt: Add function bt_gatt_result_included_count()
shared/gatt: Distinguish Primary from Secondary services
tools/btgatt-client: Print type of service
shared/gatt: Discover secondary services
shared/gatt: Discover included services
shared/gatt: Add gatt-client include service iterator
tools/btgatt-client: Print found include services
shared/gatt: Fix searching descriptors
src/shared/gatt-client.c | 259 ++++++++++++++++++++++++++--
src/shared/gatt-client.h | 18 ++
src/shared/gatt-helpers.c | 418 +++++++++++++++++++++++++++++++++++++++++++---
src/shared/gatt-helpers.h | 10 +-
tools/btgatt-client.c | 17 +-
5 files changed, 686 insertions(+), 36 deletions(-)
--
1.9.3
^ permalink raw reply
* Re: [PATCH 1/3] android/tester: Add GATT server start service test cases
From: Szymon Janc @ 2014-10-10 9:08 UTC (permalink / raw)
To: Grzegorz Kolodziejczyk; +Cc: linux-bluetooth
In-Reply-To: <1412605665-13527-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>
Hi Grzegorz,
On Monday 06 of October 2014 16:27:43 Grzegorz Kolodziejczyk wrote:
> This adds start service by server test cases.
> ---
> android/tester-gatt.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++
> android/tester-main.c | 16 +++++++-
> android/tester-main.h | 7 ++++
> 3 files changed, 122 insertions(+), 1 deletion(-)
>
> diff --git a/android/tester-gatt.c b/android/tester-gatt.c
> index e86e929..19ba703 100644
> --- a/android/tester-gatt.c
> +++ b/android/tester-gatt.c
> @@ -37,6 +37,10 @@
> #define CONN1_ID 1
> #define CONN2_ID 2
>
> +#define GATT_SERVER_TRANSPORT_LE 0x00
> +#define GATT_SERVER_TRANSPORT_BREDR 0x01
> +#define GATT_SERVER_TRANSPORT_LE_BREDR 0x02
> +
> static struct queue *list; /* List of gatt test cases */
>
> static int srvc1_handle;
> @@ -138,6 +142,12 @@ struct add_desc_data {
> int permissions;
> };
>
> +struct start_srvc_data {
> + int app_id;
> + int *srvc_handle;
> + int transport;
> +};
> +
> static bt_bdaddr_t emu_remote_bdaddr_val = {
> .address = { 0x00, 0xaa, 0x01, 0x01, 0x00, 0x00 },
> };
> @@ -459,6 +469,30 @@ static struct add_desc_data add_desc_data_1 = {
> .permissions = 0
> };
>
> +static struct start_srvc_data start_srvc_data_1 = {
> + .app_id = APP1_ID,
> + .srvc_handle = &srvc1_handle,
> + .transport = GATT_SERVER_TRANSPORT_LE_BREDR
> +};
> +
> +static struct start_srvc_data start_srvc_data_2 = {
> + .app_id = APP1_ID,
> + .srvc_handle = &srvc1_handle,
> + .transport = GATT_SERVER_TRANSPORT_LE
> +};
> +
> +static struct start_srvc_data start_bad_srvc_data_1 = {
> + .app_id = APP1_ID,
> + .srvc_handle = &srvc_bad_handle,
> + .transport = GATT_SERVER_TRANSPORT_LE
> +};
> +
> +static struct start_srvc_data start_bad_srvc_data_2 = {
> + .app_id = APP1_ID,
> + .srvc_handle = &srvc1_handle,
> + .transport = -1
> +};
> +
> struct set_read_params {
> btgatt_read_params_t *params;
> btgatt_srvc_id_t *srvc_id;
> @@ -1222,6 +1256,21 @@ static void gatt_server_add_desc_action(void)
> schedule_action_verification(step);
> }
>
> +static void gatt_server_start_srvc_action(void)
> +{
> + struct test_data *data = tester_get_data();
> + struct step *current_data_step = queue_peek_head(data->steps);
> + struct start_srvc_data *start_srvc_data = current_data_step->set_data;
> + struct step *step = g_new0(struct step, 1);
> +
> + step->action_status = data->if_gatt->server->start_service(
> + start_srvc_data->app_id,
> + *start_srvc_data->srvc_handle,
> + start_srvc_data->transport);
> +
> + schedule_action_verification(step);
> +}
> +
> static void gatt_cid_hook_cb(const void *data, uint16_t len, void *user_data)
> {
> struct test_data *t_data = tester_get_data();
> @@ -2645,6 +2694,57 @@ static struct test_case test_cases[] = {
> CALLBACK_GATTS_DESCRIPTOR_ADDED(GATT_STATUS_FAILURE, APP2_ID,
> &app2_uuid, NULL, NULL, NULL),
> ),
> + TEST_CASE_BREDRLE("Gatt Server - Start Service Successful BREDRLE",
> + ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
> + CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
> + ACTION_SUCCESS(gatt_server_add_service_action,
> + &add_service_data_1),
> + CALLBACK_GATTS_SERVICE_ADDED(GATT_STATUS_SUCCESS, APP1_ID,
> + &service_add_1, NULL,
> + &srvc1_handle),
> + ACTION_SUCCESS(gatt_server_start_srvc_action,
> + &start_srvc_data_1),
> + CALLBACK_GATTS_SERVICE_STARTED(GATT_STATUS_SUCCESS, APP1_ID,
> + &srvc1_handle),
> + ),
> + TEST_CASE_BREDRLE("Gatt Server - Start Service Successful LE",
> + ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
> + CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
> + ACTION_SUCCESS(gatt_server_add_service_action,
> + &add_service_data_1),
> + CALLBACK_GATTS_SERVICE_ADDED(GATT_STATUS_SUCCESS, APP1_ID,
> + &service_add_1, NULL,
> + &srvc1_handle),
> + ACTION_SUCCESS(gatt_server_start_srvc_action,
> + &start_srvc_data_2),
> + CALLBACK_GATTS_SERVICE_STARTED(GATT_STATUS_SUCCESS, APP1_ID,
> + &srvc1_handle),
> + ),
> + TEST_CASE_BREDRLE("Gatt Server - Start Service wrong service handle",
> + ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
> + CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
> + ACTION_SUCCESS(gatt_server_add_service_action,
> + &add_service_data_1),
> + CALLBACK_GATTS_SERVICE_ADDED(GATT_STATUS_SUCCESS, APP1_ID,
> + &service_add_1, NULL, NULL),
> + ACTION_FAIL(gatt_server_start_srvc_action,
> + &start_bad_srvc_data_1),
> + CALLBACK_GATTS_SERVICE_STARTED(GATT_STATUS_FAILURE, APP1_ID,
> + NULL),
> + ),
> + TEST_CASE_BREDRLE("Gatt Server - Start Service wrong server transport",
> + ACTION_SUCCESS(gatt_server_register_action, &app1_uuid),
> + CALLBACK_STATUS(CB_GATTS_REGISTER_SERVER, BT_STATUS_SUCCESS),
> + ACTION_SUCCESS(gatt_server_add_service_action,
> + &add_service_data_1),
> + CALLBACK_GATTS_SERVICE_ADDED(GATT_STATUS_SUCCESS, APP1_ID,
> + &service_add_1, NULL,
> + &srvc1_handle),
> + ACTION_FAIL(gatt_server_start_srvc_action,
> + &start_bad_srvc_data_2),
> + CALLBACK_GATTS_SERVICE_STARTED(GATT_STATUS_FAILURE, APP1_ID,
> + &srvc1_handle),
> + ),
> };
>
> struct queue *get_gatt_tests(void)
> diff --git a/android/tester-main.c b/android/tester-main.c
> index 30e1c59..4ffa3c1 100644
> --- a/android/tester-main.c
> +++ b/android/tester-main.c
> @@ -1608,6 +1608,20 @@ static void gatts_descriptor_added_cb(int status, int server_if,
> schedule_callback_verification(step);
> }
>
> +static void gatts_service_started_cb(int status, int server_if, int srvc_handle)
> +{
> + struct step *step = g_new0(struct step, 1);
> +
> + step->callback = CB_GATTS_SERVICE_STARTED;
> +
> + step->callback_result.status = status;
> + step->callback_result.gatt_app_id = server_if;
> + step->callback_result.srvc_handle = g_memdup(&srvc_handle,
> + sizeof(srvc_handle));
> +
> + schedule_callback_verification(step);
> +}
> +
> static void pan_control_state_cb(btpan_control_state_t state,
> bt_status_t error, int local_role,
> const char *ifname)
> @@ -1735,7 +1749,7 @@ static const btgatt_server_callbacks_t btgatt_server_callbacks = {
> .included_service_added_cb = gatts_included_service_added_cb,
> .characteristic_added_cb = gatts_characteristic_added_cb,
> .descriptor_added_cb = gatts_descriptor_added_cb,
> - .service_started_cb = NULL,
> + .service_started_cb = gatts_service_started_cb,
> .service_stopped_cb = NULL,
> .service_deleted_cb = NULL,
> .request_read_cb = NULL,
> diff --git a/android/tester-main.h b/android/tester-main.h
> index 17a6eb3..1906a8d 100644
> --- a/android/tester-main.h
> +++ b/android/tester-main.h
> @@ -297,6 +297,13 @@ struct pdu_set {
> .store_desc_handle = cb_store_desc_handle, \
> }
>
> +#define CALLBACK_GATTS_SERVICE_STARTED(cb_res, cb_server_id, cb_srvc_handle) { \
> + .callback = CB_GATTS_SERVICE_STARTED, \
> + .callback_result.status = cb_res, \
> + .callback_result.gatt_app_id = cb_server_id, \
> + .callback_result.srvc_handle = cb_srvc_handle, \
> + }
> +
> #define CALLBACK_PAN_CTRL_STATE(cb, cb_res, cb_state, cb_local_role) { \
> .callback = cb, \
> .callback_result.status = cb_res, \
>
All patches applied. Thanks.
--
Best regards,
Szymon Janc
^ permalink raw reply
* Re: [PATCH] android/pts: RFCOMM PTS 5.3 update
From: Szymon Janc @ 2014-10-10 8:36 UTC (permalink / raw)
To: Sebastian Chlad; +Cc: linux-bluetooth
In-Reply-To: <1412867744-11403-1-git-send-email-sebastian.chlad@tieto.com>
Hi Sebastian,
On Thursday 09 of October 2014 17:15:44 Sebastian Chlad wrote:
> PTS tests results for RFCOMM on PTS 5.3.
> PICS' and PIXITs checked against PTS 5.3.
> ---
> android/pics-rfcomm.txt | 2 +-
> android/pixit-rfcomm.txt | 2 +-
> android/pts-rfcomm.txt | 22 ++++++++--------------
> 3 files changed, 10 insertions(+), 16 deletions(-)
>
> diff --git a/android/pics-rfcomm.txt b/android/pics-rfcomm.txt
> index 9dfb32e..c970363 100644
> --- a/android/pics-rfcomm.txt
> +++ b/android/pics-rfcomm.txt
> @@ -1,6 +1,6 @@
> RFCOMM PICS for the PTS tool.
>
> -PTS version: 5.2
> +PTS version: 5.3
>
> * - different than PTS defaults
> # - not yet implemented/supported
> diff --git a/android/pixit-rfcomm.txt b/android/pixit-rfcomm.txt
> index 07810d2..187f3b4 100644
> --- a/android/pixit-rfcomm.txt
> +++ b/android/pixit-rfcomm.txt
> @@ -1,6 +1,6 @@
> RFCOMM PIXIT for the PTS tool.
>
> -PTS version: 5.2
> +PTS version: 5.3
>
> * - different than PTS defaults
> & - should be set to IUT Bluetooth address
> diff --git a/android/pts-rfcomm.txt b/android/pts-rfcomm.txt
> index 9bfc7a2..d869ee0 100644
> --- a/android/pts-rfcomm.txt
> +++ b/android/pts-rfcomm.txt
> @@ -1,7 +1,7 @@
> PTS test results for RFCOMM
>
> -PTS version: 5.2
> -Tested: 17-July-2014
> +PTS version: 5.3
> +Tested: 08-October-2014
> Android version: 4.4.4
>
> Results:
> @@ -17,29 +17,23 @@ Test Name Result Notes
> TC_RFC_BV_01_C PASS rctest -n -P 1 <btaddr>
> TC_RFC_BV_02_C PASS rctest -r -P 1
> TC_RFC_BV_03_C PASS rctest -r -P 1
> -TC_RFC_BV_04_C FAIL PTS issue #12421
> - PTS issue #12414
> - NOTE: DISC on DLC is expected; IUT disconnects
> - rfcomm session (close)
> +TC_RFC_BV_04_C PASS NOTE: use ets provided in PTS issue #12414
> TC_RFC_BV_05_C PASS rctest -n -P 4 <btaddr>
> Note: test requires IUT to connect on the given
> channel. sdptool browse <btaddr> to check the
> channel.
> TC_RFC_BV_06_C PASS rctest -r -P 1
> TC_RFC_BV_07_C PASS rctest -r -P 1
> -TC_RFC_BV_08_C INC PTS issue #12397
> - NOTE: Incorrect frame type sent in response to
> - the DISC command
> +TC_RFC_BV_08_C PASS rctest -r -P 1
> + Note: use ets provided in PTS issue #12397
> TC_RFC_BV_11_C PASS rctest -r -P 1
> -TC_RFC_BV_13_C FAIL PTS issue #12397
> - NOTE: IUT sent the correct frame type (UIH)
> - but the parameters did not match the
> - requirements
> +TC_RFC_BV_13_C PASS rctest -r -P 1
> + Note: use ets provided in PTS issue #12397
> TC_RFC_BV_14_C N/A
> TC_RFC_BV_15_C PASS rctest -r -P 1
> TC_RFC_BV_17_C PASS rctest -d -P 1
> TC_RFC_BV_19_C PASS
> TC_RFC_BV_21_C INC PTS issue #12421
> TC_RFC_BV_22_C INC PTS issue #12421
> -TC_RFC_BV_25_C INC PTS issue #12421
> +TC_RFC_BV_25_C INC PTS issue #12621
> -------------------------------------------------------------------------------
>
Applied (after moving PTS issues into same line as affected test name). Thanks.
--
Best regards,
Szymon Janc
^ permalink raw reply
* Re: [PATCH] Bluetooth: Defer connection-parameter removal when unpairing without disconnecting
From: Alfonso Acosta @ 2014-10-10 8:14 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: BlueZ development
In-Reply-To: <B2B9E083-A86D-426A-9E79-5F168A8FA017@holtmann.org>
Hi Marcel,
> don't we also need to clear the flag when the new pairing succeed?
Yep, in fact that's the whole point of the flag .... which I missed.
Thanks for your patience :)
> If we destroy hci_conn anyway, there is pretty much no point in test_and_clear_bit and we could just use test_bit here.
Fair point, I will change them to test_bit.
--
Alfonso Acosta
Embedded Systems Engineer at Spotify
Birger Jarlsgatan 61, Stockholm, Sweden
http://www.spotify.com
^ permalink raw reply
* Re: [PATCH v2 01/12] android/handsfree: Define proper type for device structure
From: Szymon Janc @ 2014-10-10 7:49 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1412763314-12871-1-git-send-email-szymon.janc@tieto.com>
On Wednesday 08 of October 2014 12:15:03 Szymon Janc wrote:
> ---
> android/handsfree.c | 36 +++++++++++++++++++-----------------
> 1 file changed, 19 insertions(+), 17 deletions(-)
>
> diff --git a/android/handsfree.c b/android/handsfree.c
> index a815d3b..0b82223 100644
> --- a/android/handsfree.c
> +++ b/android/handsfree.c
> @@ -110,22 +110,7 @@ struct hfp_codec {
> bool remote_supported;
> };
>
> -static const struct indicator inds_defaults[] = {
> - { "service", 0, 1, 0, false, true },
> - { "call", 0, 1, 0, true, true },
> - { "callsetup", 0, 3, 0, true, true },
> - { "callheld", 0, 2, 0, true, true },
> - { "signal", 0, 5, 0, false, true },
> - { "roam", 0, 1, 0, false, true },
> - { "battchg", 0, 5, 0, false, true },
> -};
> -
> -static const struct hfp_codec codecs_defaults[] = {
> - { CODEC_ID_CVSD, true, false},
> - { CODEC_ID_MSBC, false, false},
> -};
> -
> -static struct {
> +struct hf_device {
> bdaddr_t bdaddr;
> uint8_t state;
> uint8_t audio_state;
> @@ -152,7 +137,24 @@ static struct {
>
> GIOChannel *sco;
> guint sco_watch;
> -} device;
> +};
> +
> +static const struct indicator inds_defaults[] = {
> + { "service", 0, 1, 0, false, true },
> + { "call", 0, 1, 0, true, true },
> + { "callsetup", 0, 3, 0, true, true },
> + { "callheld", 0, 2, 0, true, true },
> + { "signal", 0, 5, 0, false, true },
> + { "roam", 0, 1, 0, false, true },
> + { "battchg", 0, 5, 0, false, true },
> +};
> +
> +static const struct hfp_codec codecs_defaults[] = {
> + { CODEC_ID_CVSD, true, false},
> + { CODEC_ID_MSBC, false, false},
> +};
> +
> +static struct hf_device device;
>
> static uint32_t hfp_ag_features = 0;
>
>
Pushed.
--
Best regards,
Szymon Janc
^ permalink raw reply
* Re: [PATCH] Bluetooth: Defer connection-parameter removal when unpairing without disconnecting
From: Marcel Holtmann @ 2014-10-10 7:36 UTC (permalink / raw)
To: Alfonso Acosta; +Cc: BlueZ development
In-Reply-To: <CAHF=Y4pJOC3gA1g-+o1e4HRJraFqpCGOAUuqNiS7b0CvAqEBJg@mail.gmail.com>
Hi Alfonso,
>>> +
>>> + if (test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags))
>>> + hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);
>>> }
>>>
>>> /* Enter sniff mode */
>>> @@ -544,6 +547,9 @@ int hci_conn_del(struct hci_conn *conn)
>>>
>>> hci_conn_del_sysfs(conn);
>>>
>>> + if (test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags))
>>> + hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);
>> I suppose the above two test_and_clear_bit() calls should be operating
>> on HCI_CONN_PARAM_REMOVAL_PEND and not HCI_CONN_MODE_CHANGE_PEND?
>
> Darn. Yes, my bad.
don't we also need to clear the flag when the new pairing succeed?
If we destroy hci_conn anyway, there is pretty much no point in test_and_clear_bit and we could just use test_bit here.
Regards
Marcel
^ permalink raw reply
* [PATCHv2] bnep: Add extra debug information for bnep_up
From: Andrei Emeltchenko @ 2014-10-10 7:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1448347.mpMmb7OWnU@uw000953>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Adding extra debug information helps to investigate failing cases
Return meaningful error code.
---
profiles/network/bnep.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index 136709d..070c22e 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -195,7 +195,7 @@ static int bnep_connadd(int sk, uint16_t role, char *dev)
static int bnep_if_up(const char *devname)
{
struct ifreq ifr;
- int sk, err;
+ int sk, err = 0;
sk = socket(AF_INET, SOCK_DGRAM, 0);
@@ -205,16 +205,15 @@ static int bnep_if_up(const char *devname)
ifr.ifr_flags |= IFF_UP;
ifr.ifr_flags |= IFF_MULTICAST;
- err = ioctl(sk, SIOCSIFFLAGS, (void *) &ifr);
+ if (ioctl(sk, SIOCSIFFLAGS, (void *) &ifr) < 0) {
+ err = -errno;
+ error("Could not bring up %s: %s(%d)", devname, strerror(-err),
+ -err);
+ }
close(sk);
- if (err < 0) {
- error("Could not bring up %s", devname);
- return err;
- }
-
- return 0;
+ return err;
}
static int bnep_if_down(const char *devname)
--
1.9.1
^ permalink raw reply related
* Re: [PATCHv3 00/13] Included service discovery
From: Marcin Kraglak @ 2014-10-10 5:20 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1412757110-3509-1-git-send-email-marcin.kraglak@tieto.com>
On 8 October 2014 10:31, Marcin Kraglak <marcin.kraglak@tieto.com> wrote:
> In this version after primary service discovery,
> secondary services are discovered. Next included
> services are resolved. With this approach we
> don't have recursively search for included service,
> like it was TODO in previous proposal.
> There is also small coding style fix suggested by Arman.
> Comments are welcome
>
> BR
> Marcin
>
> Marcin Kraglak (13):
> shared/gatt: Add discover_secondary_services()
> shared/gatt: Add initial implementation of discover_included_services
> shared/gatt: Discover included services 128 bit UUIDS
> shared/gatt: Add extra check in characteristic iterator
> shared/gatt: Add included service iterator
> shared/gatt: Remove not needed function parameter
> shared/gatt: Add function bt_gatt_result_included_count()
> shared/gatt: Distinguish Primary from Secondary services
> tools/btgatt-client: Print type of service
> shared/gatt: Discover secondary services
> shared/gatt: Discover included services
> shared/gatt: Add gatt-client include service iterator
> tools/btgatt-client: Print found include services
>
> src/shared/gatt-client.c | 249 +++++++++++++++++++++++++--
> src/shared/gatt-client.h | 18 ++
> src/shared/gatt-helpers.c | 418 +++++++++++++++++++++++++++++++++++++++++++---
> src/shared/gatt-helpers.h | 10 +-
> tools/btgatt-client.c | 17 +-
> 5 files changed, 678 insertions(+), 34 deletions(-)
>
> --
> 1.9.3
>
ping
^ permalink raw reply
* [PATCH 8/8] unit/hfp: Add test for +CME ERROR: response
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898652-12281-1-git-send-email-lukasz.rymanowski@tieto.com>
---
unit/test-hfp.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 9c71ee9..ff5532e 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -487,6 +487,19 @@ static void hf_response_with_data(const char *prefix, enum hfp_result res,
hfp_hf_disconnect(context->hfp_hf);
}
+static void hf_cme_error_response_cb(const char *prefix,
+ enum hfp_result res,
+ enum hfp_error cme_err,
+ void *user_data)
+{
+ struct context *context = user_data;
+
+ g_assert_cmpstr(prefix, ==, "AT+CHLD");
+ g_assert_cmpint(res, ==, HFP_RESULT_CME_ERROR);
+ g_assert_cmpint(cme_err, ==, 30);
+
+ hfp_hf_disconnect(context->hfp_hf);
+}
static void hf_brsf_response_cb(const char *prefix, enum hfp_result res,
enum hfp_error cme_err,
void *user_data)
@@ -721,6 +734,14 @@ int main(int argc, char *argv[])
frg_pdu('\r', '\n', 'O', 'k', '\r', '\n'),
data_end());
+ define_hf_test("/hfp/test_send_command_3", test_hf_send_command, NULL,
+ hf_cme_error_response_cb,
+ raw_pdu('A', 'T', '+', 'C', 'H', 'L', 'D', '=',
+ '1', '\0'),
+ frg_pdu('\r', '\n', '+', 'C', 'M', 'E', ' ', 'E'),
+ frg_pdu('R', 'R', 'O', 'R', ':', '3', '0', '\r', '\n'),
+ data_end());
+
define_hf_test("/hfp/test_unsolicited_1", test_hf_unsolicited,
hf_result_handler, NULL,
raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
--
1.8.4
^ permalink raw reply related
* [PATCH 7/8] unit/hfp: Add unit tests for parsing hfp_context
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898652-12281-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds:
/hfp/test_hf_context_parser_1
/hfp/test_hf_context_parser_2
---
unit/test-hfp.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index bc05086..9c71ee9 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -531,6 +531,54 @@ static void test_hf_send_command(gconstpointer data)
execute_context(context);
}
+static void hf_chld_result_handler(struct hfp_context *hf_context,
+ void *user_data)
+{
+ struct context *context = user_data;
+ char str[3];
+
+ g_assert(hf_context);
+ g_assert(hfp_context_get_unquoted_string(hf_context, str,
+ sizeof(str)));
+ g_assert_cmpstr(str, ==, "1");
+ g_assert(hfp_context_get_unquoted_string(hf_context, str,
+ sizeof(str)));
+ g_assert_cmpstr(str, ==, "2x");
+
+ hfp_hf_disconnect(context->hfp_hf);
+}
+
+static void hf_clcc_result_handler(struct hfp_context *hf_context,
+ void *user_data)
+{
+ struct context *context = user_data;
+ char name[10];
+ uint32_t val1, val2;
+
+ g_assert(hf_context);
+ g_assert(hfp_context_open_container(hf_context));
+ g_assert(hfp_context_get_string(hf_context, name, sizeof(name)));
+ g_assert_cmpstr(name, ==, "call");
+ g_assert(hfp_context_open_container(hf_context));
+ g_assert(hfp_context_get_number(hf_context, &val1));
+ g_assert_cmpint(val1, ==, 0);
+ g_assert(hfp_context_get_number(hf_context, &val1));
+ g_assert_cmpint(val1, ==, 1);
+ g_assert(hfp_context_close_container(hf_context));
+ g_assert(hfp_context_close_container(hf_context));
+
+ g_assert(hfp_context_open_container(hf_context));
+ g_assert(hfp_context_get_string(hf_context, name, sizeof(name)));
+ g_assert_cmpstr(name, ==, "callsetup");
+ g_assert(hfp_context_open_container(hf_context));
+ g_assert(hfp_context_get_range(hf_context, &val1, &val2));
+ g_assert_cmpint(val1, ==, 0);
+ g_assert_cmpint(val2, ==, 3);
+ g_assert(hfp_context_close_container(hf_context));
+ g_assert(hfp_context_close_container(hf_context));
+
+ hfp_hf_disconnect(context->hfp_hf);
+}
static void hf_result_handler(struct hfp_context *result,
void *user_data)
@@ -718,5 +766,23 @@ int main(int argc, char *argv[])
raw_pdu('\r', '\n', 'B', 'R', '\r', '\n'),
data_end());
+ define_hf_test("/hfp/test_hf_context_parser_1", test_hf_unsolicited,
+ hf_clcc_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ frg_pdu('+', 'C', 'L', 'C', 'C', ':'),
+ frg_pdu('(', '\"', 'c', 'a', 'l', 'l', '\"'),
+ frg_pdu('(', '0', ',', '1', ')', ')', ','),
+ frg_pdu('(', '\"', 'c', 'a', 'l', 'l', 's', 'e', 't'),
+ frg_pdu('u', 'p', '\"', ',', '(', '0', '-', '3', ')'),
+ frg_pdu(')', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp/test_hf_context_parser_2", test_hf_unsolicited,
+ hf_chld_result_handler, NULL,
+ raw_pdu('+', 'C', 'H', 'L', 'D', '\0'),
+ frg_pdu('+', 'C', 'H', 'L', 'D', ':'),
+ frg_pdu('1', ',', '2', 'x', '\r', '\n'),
+ data_end());
+
return g_test_run();
}
--
1.8.4
^ permalink raw reply related
* [PATCH 6/8] shared/hfp: Add hfp_context_get_range function
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898652-12281-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds hfp_contex_get_range function which is useful in parsing
response like this : +CIND: ("battchr",(1-5))
---
src/shared/hfp.c | 31 +++++++++++++++++++++++++++++++
src/shared/hfp.h | 2 ++
2 files changed, 33 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 1ccbd16..fe9f1c0 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -419,6 +419,37 @@ bool hfp_context_has_next(struct hfp_context *result)
return result->data[result->offset] != '\0';
}
+bool hfp_context_get_range(struct hfp_context *context, uint32_t *min,
+ uint32_t *max)
+{
+ uint32_t l, h;
+ uint32_t start;
+
+ start = context->offset;
+
+ if (!hfp_context_get_number(context, &l))
+ goto failed;
+
+ if (context->data[context->offset] != '-')
+ goto failed;
+
+ context->offset++;
+
+ if (!hfp_context_get_number(context, &h))
+ goto failed;
+
+ *min = l;
+ *max = h;
+
+ next_field(context);
+
+ return true;
+
+failed:
+ context->offset = start;
+ return false;
+}
+
static void process_input(struct hfp_gw *hfp)
{
char *str, *ptr;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index e4a70e0..c2153a8 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -137,6 +137,8 @@ bool hfp_context_get_string(struct hfp_context *context, char *buf,
uint8_t len);
bool hfp_context_get_unquoted_string(struct hfp_context *context,
char *buf, uint8_t len);
+bool hfp_context_get_range(struct hfp_context *context, unsigned int *min,
+ unsigned int *max);
bool hfp_context_has_next(struct hfp_context *context);
struct hfp_hf *hfp_hf_new(int fd);
--
1.8.4
^ permalink raw reply related
* [PATCH 5/8] shared/hfp: Minor fix in container close function
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898652-12281-1-git-send-email-lukasz.rymanowski@tieto.com>
When closing container of hfp_context, we should try to move to next
field so offset is set correctly to next data.
Needed in case of parsing for example:
.+CIND: ("call",(0,1)),("callsetup",(0-3))")
---
src/shared/hfp.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 6f2d28a..1ccbd16 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -331,6 +331,8 @@ bool hfp_context_close_container(struct hfp_context *context)
context->offset++;
+ next_field(context);
+
return true;
}
--
1.8.4
^ permalink raw reply related
* [PATCH 4/8] shared/hfp: Add handling +CME ERROR to parser
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898652-12281-1-git-send-email-lukasz.rymanowski@tieto.com>
---
src/shared/hfp.c | 22 +++++++++++++++++++---
src/shared/hfp.h | 2 ++
unit/test-hfp.c | 2 ++
3 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 87e4017..6f2d28a 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -903,7 +903,9 @@ static void hf_skip_whitespace(struct hfp_context *context)
context->offset++;
}
-static bool is_response(const char *prefix, enum hfp_result *result)
+static bool is_response(const char *prefix, enum hfp_result *result,
+ enum hfp_error *cme_err,
+ struct hfp_context *context)
{
if (strcmp(prefix, "OK") == 0) {
*result = HFP_RESULT_OK;
@@ -940,6 +942,19 @@ static bool is_response(const char *prefix, enum hfp_result *result)
return true;
}
+ if (strcmp(prefix, "+CME ERROR") == 0) {
+ uint32_t val;
+
+ *result = HFP_RESULT_CME_ERROR;
+
+ if (hfp_context_get_number(context, &val))
+ *cme_err = val;
+ else
+ *cme_err = HFP_ERROR_AG_FAILURE;
+
+ return true;
+ }
+
return false;
}
@@ -972,6 +987,7 @@ static void hf_call_prefix_handler(struct hfp_hf *hfp, const char *data)
const char *separators = ";:\0";
struct hfp_context context;
enum hfp_result result;
+ enum hfp_error cme_err = 0;
char lookup_prefix[18];
uint8_t pref_len = 0;
const char *prefix;
@@ -997,14 +1013,14 @@ static void hf_call_prefix_handler(struct hfp_hf *hfp, const char *data)
lookup_prefix[pref_len] = '\0';
context.offset += pref_len + 1;
- if (is_response(lookup_prefix, &result)) {
+ if (is_response(lookup_prefix, &result, &cme_err, &context)) {
struct cmd_response *cmd;
cmd = queue_peek_head(hfp->cmd_queue);
if (!cmd)
return;
- cmd->resp_cb(cmd->prefix, result, cmd->user_data);
+ cmd->resp_cb(cmd->prefix, result, cme_err, cmd->user_data);
queue_remove(hfp->cmd_queue, cmd);
destroy_cmd_response(cmd);
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 27c26a2..e4a70e0 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -34,6 +34,7 @@ enum hfp_result {
HFP_RESULT_NO_ANSWER = 8,
HFP_RESULT_DELAYED = 9,
HFP_RESULT_BLACKLISTED = 10,
+ HFP_RESULT_CME_ERROR = 11,
};
enum hfp_error {
@@ -86,6 +87,7 @@ typedef void (*hfp_disconnect_func_t)(void *user_data);
typedef void (*hfp_response_func_t)(const char *prefix,
enum hfp_result result,
+ enum hfp_error cme_err,
void *user_data);
struct hfp_gw;
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index c597fd0..bc05086 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -476,6 +476,7 @@ static void hf_unsolicited_resp_cb(struct hfp_context *context,
}
static void hf_response_with_data(const char *prefix, enum hfp_result res,
+ enum hfp_error cme_err,
void *user_data)
{
struct context *context = user_data;
@@ -487,6 +488,7 @@ static void hf_response_with_data(const char *prefix, enum hfp_result res,
}
static void hf_brsf_response_cb(const char *prefix, enum hfp_result res,
+ enum hfp_error cme_err,
void *user_data)
{
struct context *context = user_data;
--
1.8.4
^ permalink raw reply related
* [PATCH 3/8] shared/hfp: Rename functions operating on context
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898652-12281-1-git-send-email-lukasz.rymanowski@tieto.com>
---
android/handsfree.c | 91 ++++++++++++++++++++++++++---------------------------
src/shared/hfp.c | 16 +++++-----
src/shared/hfp.h | 14 ++++-----
unit/test-hfp.c | 8 ++---
4 files changed, 64 insertions(+), 65 deletions(-)
diff --git a/android/handsfree.c b/android/handsfree.c
index 2bff183..6abc99b 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -301,10 +301,10 @@ static void at_cmd_vgm(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(context, &val) || val > 15)
+ if (!hfp_context_get_number(context, &val) || val > 15)
break;
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
ev.type = HAL_HANDSFREE_VOLUME_TYPE_MIC;
@@ -335,10 +335,10 @@ static void at_cmd_vgs(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(context, &val) || val > 15)
+ if (!hfp_context_get_number(context, &val) || val > 15)
break;
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
ev.type = HAL_HANDSFREE_VOLUME_TYPE_SPEAKER;
@@ -366,13 +366,13 @@ static void at_cmd_cops(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(context, &val) || val != 3)
+ if (!hfp_context_get_number(context, &val) || val != 3)
break;
- if (!hfp_gw_result_get_number(context, &val) || val != 0)
+ if (!hfp_context_get_number(context, &val) || val != 0)
break;
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
hfp_gw_send_result(device.gw, HFP_RESULT_OK);
@@ -407,8 +407,7 @@ static void at_cmd_bia(struct hfp_context *context,
do {
def = (i < IND_COUNT) ? device.inds[i].active : 0;
- if (!hfp_gw_result_get_number_default(context, &val,
- def))
+ if (!hfp_context_get_number_default(context, &val, def))
goto failed;
if (val > 1)
@@ -418,7 +417,7 @@ static void at_cmd_bia(struct hfp_context *context,
tmp[i] = val || device.inds[i].always_active;
i++;
}
- } while (hfp_gw_result_has_next(context));
+ } while (hfp_context_has_next(context));
for (i = 0; i < IND_COUNT; i++)
device.inds[i].active = tmp[i];
@@ -442,7 +441,7 @@ static void at_cmd_a(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
@@ -471,7 +470,7 @@ static void at_cmd_d(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_unquoted_string(context,
+ if (!hfp_context_get_unquoted_string(context,
(char *) ev->number, 255))
break;
@@ -512,10 +511,10 @@ static void at_cmd_ccwa(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(context, &val) || val > 1)
+ if (!hfp_context_get_number(context, &val) || val > 1)
break;
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
device.ccwa_enabled = val;
@@ -538,7 +537,7 @@ static void at_cmd_chup(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
@@ -563,7 +562,7 @@ static void at_cmd_clcc(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
@@ -587,10 +586,10 @@ static void at_cmd_cmee(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(context, &val) || val > 1)
+ if (!hfp_context_get_number(context, &val) || val > 1)
break;
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
device.cmee_enabled = val;
@@ -615,10 +614,10 @@ static void at_cmd_clip(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(context, &val) || val > 1)
+ if (!hfp_context_get_number(context, &val) || val > 1)
break;
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
device.clip_enabled = val;
@@ -644,7 +643,7 @@ static void at_cmd_vts(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_unquoted_string(context, str, 2))
+ if (!hfp_context_get_unquoted_string(context, str, 2))
break;
if (!((str[0] >= '0' && str[0] <= '9') ||
@@ -652,7 +651,7 @@ static void at_cmd_vts(struct hfp_context *context,
str[0] == '*' || str[0] == '#'))
break;
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
ev.tone = str[0];
@@ -679,7 +678,7 @@ static void at_cmd_cnum(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
@@ -713,7 +712,7 @@ static void at_cmd_bldn(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
ev.number_len = 0;
@@ -740,10 +739,10 @@ static void at_cmd_bvra(struct hfp_context *context,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(context, &val) || val > 1)
+ if (!hfp_context_get_number(context, &val) || val > 1)
break;
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
if (val)
@@ -778,10 +777,10 @@ static void at_cmd_nrec(struct hfp_context *context,
* callback, but spec allows HF to only disable AG's NREC
* feature for SLC duration. Follow spec here.
*/
- if (!hfp_gw_result_get_number(context, &val) || val != 0)
+ if (!hfp_context_get_number(context, &val) || val != 0)
break;
- if (hfp_gw_result_has_next(context))
+ if (hfp_context_has_next(context))
break;
ev.nrec = HAL_HANDSFREE_NREC_STOP;
@@ -940,7 +939,7 @@ static void at_cmd_bcc(struct hfp_context *result, enum hfp_gw_cmd_type type,
if (!(device.features & HFP_HF_FEAT_CODEC))
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_context_has_next(result))
break;
hfp_gw_send_result(device.gw, HFP_RESULT_OK);
@@ -976,10 +975,10 @@ static void at_cmd_bcs(struct hfp_context *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val))
+ if (!hfp_context_get_number(result, &val))
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_context_has_next(result))
break;
/* Remote replied with other codec. Reply with error */
@@ -1014,10 +1013,10 @@ static void at_cmd_ckpd(struct hfp_context *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val) || val != 200)
+ if (!hfp_context_get_number(result, &val) || val != 200)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_context_has_next(result))
break;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
@@ -1074,22 +1073,22 @@ static void at_cmd_cmer(struct hfp_context *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
/* mode must be =3 */
- if (!hfp_gw_result_get_number(result, &val) || val != 3)
+ if (!hfp_context_get_number(result, &val) || val != 3)
break;
/* keyp is don't care */
- if (!hfp_gw_result_get_number(result, &val))
+ if (!hfp_context_get_number(result, &val))
break;
/* disp is don't care */
- if (!hfp_gw_result_get_number(result, &val))
+ if (!hfp_context_get_number(result, &val))
break;
/* ind must be 0 or 1 */
- if (!hfp_gw_result_get_number(result, &val) || val > 1)
+ if (!hfp_context_get_number(result, &val) || val > 1)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_context_has_next(result))
break;
device.indicators_enabled = val;
@@ -1175,10 +1174,10 @@ static void at_cmd_brsf(struct hfp_context *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &feat))
+ if (!hfp_context_get_number(result, &feat))
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_context_has_next(result))
break;
/* TODO verify features */
@@ -1206,11 +1205,11 @@ static void at_cmd_chld(struct hfp_context *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val) || val > 3)
+ if (!hfp_context_get_number(result, &val) || val > 3)
break;
/* No ECC support */
- if (hfp_gw_result_has_next(result))
+ if (hfp_context_has_next(result))
break;
/* value match HAL type */
@@ -1265,23 +1264,23 @@ static void at_cmd_bac(struct hfp_context *result, enum hfp_gw_cmd_type type,
* At least CVSD mandatory codec must exist
* HFP V1.6 4.34.1
*/
- if (!hfp_gw_result_get_number(result, &val) ||
+ if (!hfp_context_get_number(result, &val) ||
val != CODEC_ID_CVSD)
goto failed;
device.codecs[CVSD_OFFSET].remote_supported = true;
- if (hfp_gw_result_get_number(result, &val)) {
+ if (hfp_context_get_number(result, &val)) {
if (val != CODEC_ID_MSBC)
goto failed;
device.codecs[MSBC_OFFSET].remote_supported = true;
}
- while (hfp_gw_result_has_next(result)) {
+ while (hfp_context_has_next(result)) {
struct hfp_codec *codec;
- if (!hfp_gw_result_get_number(result, &val))
+ if (!hfp_context_get_number(result, &val))
goto failed;
codec = find_codec_by_type(val);
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 8170a16..87e4017 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -265,7 +265,7 @@ static void next_field(struct hfp_context *context)
context->offset++;
}
-bool hfp_gw_result_get_number_default(struct hfp_context *context,
+bool hfp_context_get_number_default(struct hfp_context *context,
unsigned int *val,
unsigned int default_val)
{
@@ -279,10 +279,10 @@ bool hfp_gw_result_get_number_default(struct hfp_context *context,
return true;
}
- return hfp_gw_result_get_number(context, val);
+ return hfp_context_get_number(context, val);
}
-bool hfp_gw_result_get_number(struct hfp_context *context,
+bool hfp_context_get_number(struct hfp_context *context,
unsigned int *val)
{
unsigned int i;
@@ -308,7 +308,7 @@ bool hfp_gw_result_get_number(struct hfp_context *context,
return true;
}
-bool hfp_gw_result_open_container(struct hfp_context *context)
+bool hfp_context_open_container(struct hfp_context *context)
{
skip_whitespace(context);
@@ -321,7 +321,7 @@ bool hfp_gw_result_open_container(struct hfp_context *context)
return true;
}
-bool hfp_gw_result_close_container(struct hfp_context *context)
+bool hfp_context_close_container(struct hfp_context *context)
{
skip_whitespace(context);
@@ -334,7 +334,7 @@ bool hfp_gw_result_close_container(struct hfp_context *context)
return true;
}
-bool hfp_gw_result_get_string(struct hfp_context *context, char *buf,
+bool hfp_context_get_string(struct hfp_context *context, char *buf,
uint8_t len)
{
int i = 0;
@@ -375,7 +375,7 @@ bool hfp_gw_result_get_string(struct hfp_context *context, char *buf,
return true;
}
-bool hfp_gw_result_get_unquoted_string(struct hfp_context *context,
+bool hfp_context_get_unquoted_string(struct hfp_context *context,
char *buf, uint8_t len)
{
const char *data = context->data;
@@ -412,7 +412,7 @@ bool hfp_gw_result_get_unquoted_string(struct hfp_context *context,
return true;
}
-bool hfp_gw_result_has_next(struct hfp_context *result)
+bool hfp_context_has_next(struct hfp_context *result)
{
return result->data[result->offset] != '\0';
}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 02df713..27c26a2 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -124,18 +124,18 @@ bool hfp_gw_register(struct hfp_gw *hfp, hfp_result_func_t callback,
hfp_destroy_func_t destroy);
bool hfp_gw_unregister(struct hfp_gw *hfp, const char *prefix);
-bool hfp_gw_result_get_number(struct hfp_context *context,
+bool hfp_context_get_number(struct hfp_context *context,
unsigned int *val);
-bool hfp_gw_result_get_number_default(struct hfp_context *context,
+bool hfp_context_get_number_default(struct hfp_context *context,
unsigned int *val,
unsigned int default_val);
-bool hfp_gw_result_open_container(struct hfp_context *context);
-bool hfp_gw_result_close_container(struct hfp_context *context);
-bool hfp_gw_result_get_string(struct hfp_context *context, char *buf,
+bool hfp_context_open_container(struct hfp_context *context);
+bool hfp_context_close_container(struct hfp_context *context);
+bool hfp_context_get_string(struct hfp_context *context, char *buf,
uint8_t len);
-bool hfp_gw_result_get_unquoted_string(struct hfp_context *context,
+bool hfp_context_get_unquoted_string(struct hfp_context *context,
char *buf, uint8_t len);
-bool hfp_gw_result_has_next(struct hfp_context *context);
+bool hfp_context_has_next(struct hfp_context *context);
struct hfp_hf *hfp_hf_new(int fd);
struct hfp_hf *hfp_hf_ref(struct hfp_hf *hfp);
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 7dd3b33..c597fd0 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -371,7 +371,7 @@ static void check_ustring_1(struct hfp_context *result,
g_assert(type == pdu->type);
- g_assert(hfp_gw_result_get_unquoted_string(result, str, sizeof(str)));
+ g_assert(hfp_context_get_unquoted_string(result, str, sizeof(str)));
while (context->data->pdu_list[1].data[i] != '\r') {
g_assert(j < sizeof(str));
@@ -399,7 +399,7 @@ static void check_ustring_2(struct hfp_context *result,
g_assert(type == pdu->type);
- g_assert(!hfp_gw_result_get_unquoted_string(result, str, 3));
+ g_assert(!hfp_context_get_unquoted_string(result, str, 3));
g_assert(str[3] == 'X');
@@ -418,7 +418,7 @@ static void check_string_1(struct hfp_context *result,
g_assert(type == pdu->type);
- g_assert(hfp_gw_result_get_string(result, str, sizeof(str)));
+ g_assert(hfp_context_get_string(result, str, sizeof(str)));
while (context->data->pdu_list[1].data[i] != '\"') {
g_assert(j < sizeof(str));
@@ -447,7 +447,7 @@ static void check_string_2(struct hfp_context *result,
g_assert(type == pdu->type);
- g_assert(!hfp_gw_result_get_string(result, str, 3));
+ g_assert(!hfp_context_get_string(result, str, 3));
g_assert(str[3] == 'X');
--
1.8.4
^ permalink raw reply related
* [PATCH 2/8] shared/hfp: Rename hfp_hf_result to common hfp_context
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898652-12281-1-git-send-email-lukasz.rymanowski@tieto.com>
---
src/shared/hfp.c | 29 ++++++++++++-----------------
src/shared/hfp.h | 3 +--
unit/test-hfp.c | 4 ++--
3 files changed, 15 insertions(+), 21 deletions(-)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 1b15da6..8170a16 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -99,15 +99,10 @@ struct hfp_context {
unsigned int offset;
};
-struct hfp_hf_result {
- const char *data;
- unsigned int offset;
-};
-
struct cmd_response {
char *prefix;
hfp_response_func_t resp_cb;
- struct hfp_hf_result *response;
+ struct hfp_context *response;
char *resp_data;
void *user_data;
};
@@ -902,10 +897,10 @@ static void hf_write_watch_destroy(void *user_data)
hfp->writer_active = false;
}
-static void hf_skip_whitespace(struct hfp_hf_result *result)
+static void hf_skip_whitespace(struct hfp_context *context)
{
- while (result->data[result->offset] == ' ')
- result->offset++;
+ while (context->data[context->offset] == ' ')
+ context->offset++;
}
static bool is_response(const char *prefix, enum hfp_result *result)
@@ -975,22 +970,22 @@ static void hf_call_prefix_handler(struct hfp_hf *hfp, const char *data)
{
struct event_handler *handler;
const char *separators = ";:\0";
- struct hfp_hf_result result_data;
+ struct hfp_context context;
enum hfp_result result;
char lookup_prefix[18];
uint8_t pref_len = 0;
const char *prefix;
int i;
- result_data.offset = 0;
- result_data.data = data;
+ context.offset = 0;
+ context.data = data;
- hf_skip_whitespace(&result_data);
+ hf_skip_whitespace(&context);
- if (strlen(data + result_data.offset) < 2)
+ if (strlen(data + context.offset) < 2)
return;
- prefix = data + result_data.offset;
+ prefix = data + context.offset;
pref_len = strcspn(prefix, separators);
if (pref_len > 17 || pref_len < 2)
@@ -1000,7 +995,7 @@ static void hf_call_prefix_handler(struct hfp_hf *hfp, const char *data)
lookup_prefix[i] = toupper(prefix[i]);
lookup_prefix[pref_len] = '\0';
- result_data.offset += pref_len + 1;
+ context.offset += pref_len + 1;
if (is_response(lookup_prefix, &result)) {
struct cmd_response *cmd;
@@ -1023,7 +1018,7 @@ static void hf_call_prefix_handler(struct hfp_hf *hfp, const char *data)
if (!handler)
return;
- handler->callback(&result_data, handler->user_data);
+ handler->callback(&context, handler->user_data);
}
static char *find_cr_lf(char *str, size_t len)
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index e57306a..02df713 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -70,12 +70,11 @@ enum hfp_gw_cmd_type {
};
struct hfp_context;
-struct hfp_hf_result;
typedef void (*hfp_result_func_t)(struct hfp_context *context,
enum hfp_gw_cmd_type type, void *user_data);
-typedef void (*hfp_hf_result_func_t)(struct hfp_hf_result *result,
+typedef void (*hfp_hf_result_func_t)(struct hfp_context *context,
void *user_data);
typedef void (*hfp_destroy_func_t)(void *user_data);
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index da8a5c9..7dd3b33 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -470,7 +470,7 @@ static void test_hf_init(gconstpointer data)
static bool unsolicited_resp = false;
-static void hf_unsolicited_resp_cb(struct hfp_hf_result *result,
+static void hf_unsolicited_resp_cb(struct hfp_context *context,
void *user_data) {
unsolicited_resp = true;
}
@@ -530,7 +530,7 @@ static void test_hf_send_command(gconstpointer data)
execute_context(context);
}
-static void hf_result_handler(struct hfp_hf_result *result,
+static void hf_result_handler(struct hfp_context *result,
void *user_data)
{
struct context *context = user_data;
--
1.8.4
^ permalink raw reply related
* [PATCH 1/8] shared/hfp: Rename hfp_gw_result to hfp_context
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898652-12281-1-git-send-email-lukasz.rymanowski@tieto.com>
hfp_context seems to be better name for data we get in the result of HFP
GW. Especially that we want to use same for HFP HF response data.
---
android/handsfree.c | 149 ++++++++++++++++++++++++++--------------------------
src/shared/hfp.c | 123 ++++++++++++++++++++++---------------------
src/shared/hfp.h | 21 ++++----
unit/test-hfp.c | 10 ++--
4 files changed, 153 insertions(+), 150 deletions(-)
diff --git a/android/handsfree.c b/android/handsfree.c
index a815d3b..2bff183 100644
--- a/android/handsfree.c
+++ b/android/handsfree.c
@@ -291,8 +291,8 @@ static void at_cmd_unknown(const char *command, void *user_data)
HAL_EV_HANDSFREE_UNKNOWN_AT, sizeof(*ev) + ev->len, ev);
}
-static void at_cmd_vgm(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_vgm(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
struct hal_ev_handsfree_volume ev;
unsigned int val;
@@ -301,10 +301,10 @@ static void at_cmd_vgm(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val) || val > 15)
+ if (!hfp_gw_result_get_number(context, &val) || val > 15)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
ev.type = HAL_HANDSFREE_VOLUME_TYPE_MIC;
@@ -325,8 +325,8 @@ static void at_cmd_vgm(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_vgs(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_vgs(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
struct hal_ev_handsfree_volume ev;
unsigned int val;
@@ -335,10 +335,10 @@ static void at_cmd_vgs(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val) || val > 15)
+ if (!hfp_gw_result_get_number(context, &val) || val > 15)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
ev.type = HAL_HANDSFREE_VOLUME_TYPE_SPEAKER;
@@ -359,20 +359,20 @@ static void at_cmd_vgs(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_cops(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_cops(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
unsigned int val;
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val) || val != 3)
+ if (!hfp_gw_result_get_number(context, &val) || val != 3)
break;
- if (!hfp_gw_result_get_number(result, &val) || val != 0)
+ if (!hfp_gw_result_get_number(context, &val) || val != 0)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
hfp_gw_send_result(device.gw, HFP_RESULT_OK);
@@ -389,8 +389,8 @@ static void at_cmd_cops(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_bia(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_bia(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
unsigned int val, i, def;
bool tmp[IND_COUNT];
@@ -407,7 +407,8 @@ static void at_cmd_bia(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
do {
def = (i < IND_COUNT) ? device.inds[i].active : 0;
- if (!hfp_gw_result_get_number_default(result, &val, def))
+ if (!hfp_gw_result_get_number_default(context, &val,
+ def))
goto failed;
if (val > 1)
@@ -417,7 +418,7 @@ static void at_cmd_bia(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
tmp[i] = val || device.inds[i].always_active;
i++;
}
- } while (hfp_gw_result_has_next(result));
+ } while (hfp_gw_result_has_next(context));
for (i = 0; i < IND_COUNT; i++)
device.inds[i].active = tmp[i];
@@ -434,14 +435,14 @@ failed:
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_a(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_a(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
DBG("");
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
@@ -459,8 +460,8 @@ static void at_cmd_a(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_d(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_d(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
char buf[IPC_MTU];
struct hal_ev_handsfree_dial *ev = (void *) buf;
@@ -470,7 +471,7 @@ static void at_cmd_d(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_unquoted_string(result,
+ if (!hfp_gw_result_get_unquoted_string(context,
(char *) ev->number, 255))
break;
@@ -502,8 +503,8 @@ static void at_cmd_d(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_ccwa(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_ccwa(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
unsigned int val;
@@ -511,10 +512,10 @@ static void at_cmd_ccwa(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val) || val > 1)
+ if (!hfp_gw_result_get_number(context, &val) || val > 1)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
device.ccwa_enabled = val;
@@ -530,14 +531,14 @@ static void at_cmd_ccwa(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_chup(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_chup(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
DBG("");
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
@@ -555,14 +556,14 @@ static void at_cmd_chup(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_clcc(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_clcc(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
DBG("");
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
@@ -577,8 +578,8 @@ static void at_cmd_clcc(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_cmee(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_cmee(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
unsigned int val;
@@ -586,10 +587,10 @@ static void at_cmd_cmee(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val) || val > 1)
+ if (!hfp_gw_result_get_number(context, &val) || val > 1)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
device.cmee_enabled = val;
@@ -605,8 +606,8 @@ static void at_cmd_cmee(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_clip(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_clip(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
unsigned int val;
@@ -614,10 +615,10 @@ static void at_cmd_clip(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val) || val > 1)
+ if (!hfp_gw_result_get_number(context, &val) || val > 1)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
device.clip_enabled = val;
@@ -633,8 +634,8 @@ static void at_cmd_clip(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_vts(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_vts(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
struct hal_ev_handsfree_dtmf ev;
char str[2];
@@ -643,7 +644,7 @@ static void at_cmd_vts(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_unquoted_string(result, str, 2))
+ if (!hfp_gw_result_get_unquoted_string(context, str, 2))
break;
if (!((str[0] >= '0' && str[0] <= '9') ||
@@ -651,7 +652,7 @@ static void at_cmd_vts(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
str[0] == '*' || str[0] == '#'))
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
ev.tone = str[0];
@@ -671,14 +672,14 @@ static void at_cmd_vts(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_cnum(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_cnum(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
DBG("");
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
@@ -693,8 +694,8 @@ static void at_cmd_cnum(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_binp(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_binp(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
DBG("");
@@ -703,8 +704,8 @@ static void at_cmd_binp(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_bldn(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_bldn(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
struct hal_ev_handsfree_dial ev;
@@ -712,7 +713,7 @@ static void at_cmd_bldn(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_COMMAND:
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
ev.number_len = 0;
@@ -729,8 +730,8 @@ static void at_cmd_bldn(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_bvra(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_bvra(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
struct hal_ev_handsfree_vr_state ev;
unsigned int val;
@@ -739,10 +740,10 @@ static void at_cmd_bvra(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
switch (type) {
case HFP_GW_CMD_TYPE_SET:
- if (!hfp_gw_result_get_number(result, &val) || val > 1)
+ if (!hfp_gw_result_get_number(context, &val) || val > 1)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
if (val)
@@ -762,8 +763,8 @@ static void at_cmd_bvra(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_nrec(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_nrec(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
struct hal_ev_handsfree_nrec ev;
unsigned int val;
@@ -777,10 +778,10 @@ static void at_cmd_nrec(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
* callback, but spec allows HF to only disable AG's NREC
* feature for SLC duration. Follow spec here.
*/
- if (!hfp_gw_result_get_number(result, &val) || val != 0)
+ if (!hfp_gw_result_get_number(context, &val) || val != 0)
break;
- if (hfp_gw_result_has_next(result))
+ if (hfp_gw_result_has_next(context))
break;
ev.nrec = HAL_HANDSFREE_NREC_STOP;
@@ -788,7 +789,7 @@ static void at_cmd_nrec(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
ipc_send_notif(hal_ipc, HAL_SERVICE_ID_HANDSFREE,
HAL_EV_HANDSFREE_NREC, sizeof(ev), &ev);
- /* Framework is not replying with result for AT+NREC */
+ /* Framework is not replying with context for AT+NREC */
hfp_gw_send_result(device.gw, HFP_RESULT_OK);
return;
case HFP_GW_CMD_TYPE_READ:
@@ -800,8 +801,8 @@ static void at_cmd_nrec(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_bsir(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_bsir(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
DBG("");
@@ -810,8 +811,8 @@ static void at_cmd_bsir(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_btrh(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
- void *user_data)
+static void at_cmd_btrh(struct hfp_context *context,
+ enum hfp_gw_cmd_type type, void *user_data)
{
DBG("");
@@ -929,7 +930,7 @@ static bool connect_sco(void)
return true;
}
-static void at_cmd_bcc(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+static void at_cmd_bcc(struct hfp_context *result, enum hfp_gw_cmd_type type,
void *user_data)
{
DBG("");
@@ -966,7 +967,7 @@ static void at_cmd_bcc(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_bcs(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+static void at_cmd_bcs(struct hfp_context *result, enum hfp_gw_cmd_type type,
void *user_data)
{
unsigned int val;
@@ -1004,7 +1005,7 @@ static void at_cmd_bcs(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
hfp_gw_send_result(device.gw, HFP_RESULT_ERROR);
}
-static void at_cmd_ckpd(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+static void at_cmd_ckpd(struct hfp_context *result, enum hfp_gw_cmd_type type,
void *user_data)
{
unsigned int val;
@@ -1065,7 +1066,7 @@ static void register_post_slc_at(void)
hfp_gw_register(device.gw, at_cmd_bcs, "+BCS", NULL, NULL);
}
-static void at_cmd_cmer(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+static void at_cmd_cmer(struct hfp_context *result, enum hfp_gw_cmd_type type,
void *user_data)
{
unsigned int val;
@@ -1110,7 +1111,7 @@ static void at_cmd_cmer(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
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,
+static void at_cmd_cind(struct hfp_context *result, enum hfp_gw_cmd_type type,
void *user_data)
{
char *buf, *ptr;
@@ -1167,7 +1168,7 @@ static void at_cmd_cind(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
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,
+static void at_cmd_brsf(struct hfp_context *result, enum hfp_gw_cmd_type type,
void *user_data)
{
unsigned int feat;
@@ -1195,7 +1196,7 @@ 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 at_cmd_chld(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+static void at_cmd_chld(struct hfp_context *result, enum hfp_gw_cmd_type type,
void *user_data)
{
struct hal_ev_handsfree_chld ev;
@@ -1244,7 +1245,7 @@ static struct hfp_codec *find_codec_by_type(uint8_t type)
return NULL;
}
-static void at_cmd_bac(struct hfp_gw_result *result, enum hfp_gw_cmd_type type,
+static void at_cmd_bac(struct hfp_context *result, enum hfp_gw_cmd_type type,
void *user_data)
{
unsigned int val;
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 8bebe97..1b15da6 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -94,7 +94,7 @@ struct cmd_handler {
hfp_result_func_t callback;
};
-struct hfp_gw_result {
+struct hfp_context {
const char *data;
unsigned int offset;
};
@@ -182,7 +182,7 @@ static void wakeup_writer(struct hfp_gw *hfp)
hfp->writer_active = true;
}
-static void skip_whitespace(struct hfp_gw_result *result)
+static void skip_whitespace(struct hfp_context *result)
{
while (result->data[result->offset] == ' ')
result->offset++;
@@ -192,27 +192,27 @@ static bool call_prefix_handler(struct hfp_gw *hfp, const char *data)
{
struct cmd_handler *handler;
const char *separators = ";?=\0";
- struct hfp_gw_result result;
+ struct hfp_context context;
enum hfp_gw_cmd_type type;
char lookup_prefix[18];
uint8_t pref_len = 0;
const char *prefix;
int i;
- result.offset = 0;
- result.data = data;
+ context.offset = 0;
+ context.data = data;
- skip_whitespace(&result);
+ skip_whitespace(&context);
- if (strlen(data + result.offset) < 3)
+ if (strlen(data + context.offset) < 3)
return false;
- if (strncmp(data + result.offset, "AT", 2))
- if (strncmp(data + result.offset, "at", 2))
+ if (strncmp(data + context.offset, "AT", 2))
+ if (strncmp(data + context.offset, "at", 2))
return false;
- result.offset += 2;
- prefix = data + result.offset;
+ context.offset += 2;
+ prefix = data + context.offset;
if (isalpha(prefix[0])) {
lookup_prefix[pref_len++] = toupper(prefix[0]);
@@ -226,17 +226,17 @@ static bool call_prefix_handler(struct hfp_gw *hfp, const char *data)
}
lookup_prefix[pref_len] = '\0';
- result.offset += pref_len;
+ context.offset += pref_len;
if (lookup_prefix[0] == 'D') {
type = HFP_GW_CMD_TYPE_SET;
goto done;
}
- if (data[result.offset] == '=') {
- result.offset++;
- if (data[result.offset] == '?') {
- result.offset++;
+ if (data[context.offset] == '=') {
+ context.offset++;
+ if (data[context.offset] == '?') {
+ context.offset++;
type = HFP_GW_CMD_TYPE_TEST;
} else {
type = HFP_GW_CMD_TYPE_SET;
@@ -244,8 +244,8 @@ static bool call_prefix_handler(struct hfp_gw *hfp, const char *data)
goto done;
}
- if (data[result.offset] == '?') {
- result.offset++;
+ if (data[context.offset] == '?') {
+ context.offset++;
type = HFP_GW_CMD_TYPE_READ;
goto done;
}
@@ -259,98 +259,99 @@ done:
if (!handler)
return false;
- handler->callback(&result, type, handler->user_data);
+ handler->callback(&context, type, handler->user_data);
return true;
}
-static void next_field(struct hfp_gw_result *result)
+static void next_field(struct hfp_context *context)
{
- if (result->data[result->offset] == ',')
- result->offset++;
+ if (context->data[context->offset] == ',')
+ context->offset++;
}
-bool hfp_gw_result_get_number_default(struct hfp_gw_result *result,
+bool hfp_gw_result_get_number_default(struct hfp_context *context,
unsigned int *val,
unsigned int default_val)
{
- skip_whitespace(result);
+ skip_whitespace(context);
- if (result->data[result->offset] == ',') {
+ if (context->data[context->offset] == ',') {
if (val)
*val = default_val;
- result->offset++;
+ context->offset++;
return true;
}
- return hfp_gw_result_get_number(result, val);
+ return hfp_gw_result_get_number(context, val);
}
-bool hfp_gw_result_get_number(struct hfp_gw_result *result, unsigned int *val)
+bool hfp_gw_result_get_number(struct hfp_context *context,
+ unsigned int *val)
{
unsigned int i;
int tmp = 0;
- skip_whitespace(result);
+ skip_whitespace(context);
- i = result->offset;
+ i = context->offset;
- while (result->data[i] >= '0' && result->data[i] <= '9')
- tmp = tmp * 10 + result->data[i++] - '0';
+ while (context->data[i] >= '0' && context->data[i] <= '9')
+ tmp = tmp * 10 + context->data[i++] - '0';
- if (i == result->offset)
+ if (i == context->offset)
return false;
if (val)
*val = tmp;
- result->offset = i;
+ context->offset = i;
- skip_whitespace(result);
- next_field(result);
+ skip_whitespace(context);
+ next_field(context);
return true;
}
-bool hfp_gw_result_open_container(struct hfp_gw_result *result)
+bool hfp_gw_result_open_container(struct hfp_context *context)
{
- skip_whitespace(result);
+ skip_whitespace(context);
/* The list shall be preceded by a left parenthesis "(") */
- if (result->data[result->offset] != '(')
+ if (context->data[context->offset] != '(')
return false;
- result->offset++;
+ context->offset++;
return true;
}
-bool hfp_gw_result_close_container(struct hfp_gw_result *result)
+bool hfp_gw_result_close_container(struct hfp_context *context)
{
- skip_whitespace(result);
+ skip_whitespace(context);
/* The list shall be followed by a right parenthesis (")" V250 5.7.3.1*/
- if (result->data[result->offset] != ')')
+ if (context->data[context->offset] != ')')
return false;
- result->offset++;
+ context->offset++;
return true;
}
-bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
+bool hfp_gw_result_get_string(struct hfp_context *context, char *buf,
uint8_t len)
{
int i = 0;
- const char *data = result->data;
+ const char *data = context->data;
unsigned int offset;
- skip_whitespace(result);
+ skip_whitespace(context);
- if (data[result->offset] != '"')
+ if (data[context->offset] != '"')
return false;
- offset = result->offset;
+ offset = context->offset;
offset++;
while (data[offset] != '\0' && data[offset] != '"') {
@@ -371,29 +372,29 @@ bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
else
return false;
- result->offset = offset;
+ context->offset = offset;
- skip_whitespace(result);
- next_field(result);
+ skip_whitespace(context);
+ next_field(context);
return true;
}
-bool hfp_gw_result_get_unquoted_string(struct hfp_gw_result *result, char *buf,
- uint8_t len)
+bool hfp_gw_result_get_unquoted_string(struct hfp_context *context,
+ char *buf, uint8_t len)
{
- const char *data = result->data;
+ const char *data = context->data;
unsigned int offset;
int i = 0;
char c;
- skip_whitespace(result);
+ skip_whitespace(context);
- c = data[result->offset];
+ c = data[context->offset];
if (c == '"' || c == ')' || c == '(')
return false;
- offset = result->offset;
+ offset = context->offset;
while (data[offset] != '\0' && data[offset] != ',' &&
data[offset] != ')') {
@@ -409,14 +410,14 @@ bool hfp_gw_result_get_unquoted_string(struct hfp_gw_result *result, char *buf,
buf[i] = '\0';
- result->offset = offset;
+ context->offset = offset;
- next_field(result);
+ next_field(context);
return true;
}
-bool hfp_gw_result_has_next(struct hfp_gw_result *result)
+bool hfp_gw_result_has_next(struct hfp_context *result)
{
return result->data[result->offset] != '\0';
}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 5ee3017..e57306a 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -69,10 +69,10 @@ enum hfp_gw_cmd_type {
HFP_GW_CMD_TYPE_COMMAND
};
-struct hfp_gw_result;
+struct hfp_context;
struct hfp_hf_result;
-typedef void (*hfp_result_func_t)(struct hfp_gw_result *result,
+typedef void (*hfp_result_func_t)(struct hfp_context *context,
enum hfp_gw_cmd_type type, void *user_data);
typedef void (*hfp_hf_result_func_t)(struct hfp_hf_result *result,
@@ -125,17 +125,18 @@ bool hfp_gw_register(struct hfp_gw *hfp, hfp_result_func_t callback,
hfp_destroy_func_t destroy);
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,
+bool hfp_gw_result_get_number(struct hfp_context *context,
+ unsigned int *val);
+bool hfp_gw_result_get_number_default(struct hfp_context *context,
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,
+bool hfp_gw_result_open_container(struct hfp_context *context);
+bool hfp_gw_result_close_container(struct hfp_context *context);
+bool hfp_gw_result_get_string(struct hfp_context *context, 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);
+bool hfp_gw_result_get_unquoted_string(struct hfp_context *context,
+ char *buf, uint8_t len);
+bool hfp_gw_result_has_next(struct hfp_context *context);
struct hfp_hf *hfp_hf_new(int fd);
struct hfp_hf *hfp_hf_ref(struct hfp_hf *hfp);
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 2515f26..da8a5c9 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -207,7 +207,7 @@ static void cmd_handler(const char *command, void *user_data)
hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
}
-static void prefix_handler(struct hfp_gw_result *result,
+static void prefix_handler(struct hfp_context *result,
enum hfp_gw_cmd_type type, void *user_data)
{
struct context *context = user_data;
@@ -359,7 +359,7 @@ static void test_fragmented(gconstpointer data)
execute_context(context);
}
-static void check_ustring_1(struct hfp_gw_result *result,
+static void check_ustring_1(struct hfp_context *result,
enum hfp_gw_cmd_type type, void *user_data)
{
struct context *context = user_data;
@@ -386,7 +386,7 @@ static void check_ustring_1(struct hfp_gw_result *result,
hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
}
-static void check_ustring_2(struct hfp_gw_result *result,
+static void check_ustring_2(struct hfp_context *result,
enum hfp_gw_cmd_type type, void *user_data)
{
struct context *context = user_data;
@@ -406,7 +406,7 @@ static void check_ustring_2(struct hfp_gw_result *result,
hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
}
-static void check_string_1(struct hfp_gw_result *result,
+static void check_string_1(struct hfp_context *result,
enum hfp_gw_cmd_type type, void *user_data)
{
struct context *context = user_data;
@@ -434,7 +434,7 @@ static void check_string_1(struct hfp_gw_result *result,
hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
}
-static void check_string_2(struct hfp_gw_result *result,
+static void check_string_2(struct hfp_context *result,
enum hfp_gw_cmd_type type, void *user_data)
{
struct context *context = user_data;
--
1.8.4
^ permalink raw reply related
* [PATCH 0/8] shared/hfp: Add support for HFP HF - part 2
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
Following patches applies on:
[PATCH v4 00/11] shared/hfp: Add support for HFP HF
This is last part of patches for HFP HF in shared code. Next ones
will be done in android part.
This set mostly affects functions which help to parse hfp response.
This has been unified so it can be used by hfp gw and hf.
Also handling of +CME ERROR has been added and couple of unit tests.
Sending it now as I want to get early comments on approach. Future work
depends on it very much so I want to avoid too much rebasing.
Lukasz Rymanowski (8):
shared/hfp: Rename hfp_gw_result to hfp_context
shared/hfp: Rename hfp_hf_result to common hfp_context
shared/hfp: Rename functions operating on context
shared/hfp: Add handling +CME ERROR to parser
shared/hfp: Minor fix in container close function
shared/hfp: Add hfp_context_get_range function
unit/hfp: Add unit tests for parsing hfp_context
unit/hfp: Add test for +CME ERROR: response
android/handsfree.c | 184 +++++++++++++++++++++++-----------------------
src/shared/hfp.c | 207 ++++++++++++++++++++++++++++++++--------------------
src/shared/hfp.h | 28 ++++---
unit/test-hfp.c | 111 +++++++++++++++++++++++++---
4 files changed, 334 insertions(+), 196 deletions(-)
--
1.8.4
^ permalink raw reply
* [PATCH v4 11/11] unit/test-hfp: Add some robustness tests for HFP HF
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898611-12199-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds folowing tests:
/hfp/test_hf_corrupted_1
/hfp/test_hf_corrupted_2
/hfp/test_hf_empty
/hfp/test_hf_unknown
---
unit/test-hfp.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 266f8cd..2515f26 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -566,6 +566,25 @@ static void test_hf_unsolicited(gconstpointer data)
execute_context(context);
}
+static void test_hf_robustness(gconstpointer data)
+{
+ struct context *context = create_context(data);
+ bool ret;
+
+ context->hfp_hf = hfp_hf_new(context->fd_client);
+ g_assert(context->hfp_hf);
+
+ ret = hfp_hf_set_close_on_unref(context->hfp_hf, true);
+ g_assert(ret);
+
+ send_pdu(context);
+
+ hfp_hf_unref(context->hfp_hf);
+ context->hfp_hf = NULL;
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -676,5 +695,26 @@ int main(int argc, char *argv[])
frg_pdu('\n'),
data_end());
+ define_hf_test("/hfp/test_hf_corrupted_1", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ frg_pdu('\r', 'X', '\r', '\n'),
+ frg_pdu('+', 'C', 'L', 'C', 'C', ':', '1', ',', '3'),
+ frg_pdu(',', '0', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp/test_hf_corrupted_2", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp/test_hf_empty", test_hf_robustness, NULL, NULL,
+ raw_pdu('\r'), data_end());
+
+ define_hf_test("/hfp/test_hf_unknown", test_hf_robustness, NULL, NULL,
+ raw_pdu('\r', '\n', 'B', 'R', '\r', '\n'),
+ data_end());
+
return g_test_run();
}
--
1.8.4
^ permalink raw reply related
* [PATCH v4 10/11] unit/test-hfp: Add tests for unsolicited results for HFP HF
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898611-12199-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds three test case:
/hfp/test_unsolicited_1
/hfp/test_unsolicited_2
/hfp/test_unsolicited_3
---
unit/test-hfp.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 34273d5..266f8cd 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -530,6 +530,42 @@ static void test_hf_send_command(gconstpointer data)
execute_context(context);
}
+static void hf_result_handler(struct hfp_hf_result *result,
+ void *user_data)
+{
+ struct context *context = user_data;
+
+ hfp_hf_disconnect(context->hfp_hf);
+}
+
+static void test_hf_unsolicited(gconstpointer data)
+{
+ struct context *context = create_context(data);
+ bool ret;
+
+ context->hfp_hf = hfp_hf_new(context->fd_client);
+ g_assert(context->hfp_hf);
+
+ ret = hfp_hf_set_close_on_unref(context->hfp_hf, true);
+ g_assert(ret);
+
+ if (context->data->hf_result_func) {
+ const struct test_pdu *pdu;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ ret = hfp_hf_register(context->hfp_hf,
+ context->data->hf_result_func,
+ (char *)pdu->data, context,
+ NULL);
+ g_assert(ret);
+ }
+
+ send_pdu(context);
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -616,5 +652,29 @@ int main(int argc, char *argv[])
frg_pdu('\r', '\n', 'O', 'k', '\r', '\n'),
data_end());
+ define_hf_test("/hfp/test_unsolicited_1", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ frg_pdu('\r', '\n', '+', 'C', 'L', 'C'),
+ frg_pdu('C', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp/test_unsolicited_2", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ frg_pdu('\r', '\n', '+', 'C', 'L', 'C', 'C', ':', '1'),
+ frg_pdu(',', '3', ',', '0', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp/test_unsolicited_3", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ frg_pdu('\r'), frg_pdu('\n'), frg_pdu('+'),
+ frg_pdu('C'), frg_pdu('L'), frg_pdu('C'), frg_pdu('C'),
+ frg_pdu(':'), frg_pdu('1'), frg_pdu(','), frg_pdu('3'),
+ frg_pdu(','), frg_pdu('0'), frg_pdu('\r'),
+ frg_pdu('\n'),
+ data_end());
+
return g_test_run();
}
--
1.8.4
^ permalink raw reply related
* [PATCH v4 09/11] unit/test-hfp: Add send command tests for HFP HF
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898611-12199-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds following tests:
/hfp/test_send_command_1
/hfp/test_send_command_2
---
unit/test-hfp.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 274ee55..34273d5 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -468,6 +468,68 @@ static void test_hf_init(gconstpointer data)
execute_context(context);
}
+static bool unsolicited_resp = false;
+
+static void hf_unsolicited_resp_cb(struct hfp_hf_result *result,
+ void *user_data) {
+ unsolicited_resp = true;
+}
+
+static void hf_response_with_data(const char *prefix, enum hfp_result res,
+ void *user_data)
+{
+ struct context *context = user_data;
+
+ g_assert(unsolicited_resp);
+ unsolicited_resp = false;
+
+ hfp_hf_disconnect(context->hfp_hf);
+}
+
+static void hf_brsf_response_cb(const char *prefix, enum hfp_result res,
+ void *user_data)
+{
+ struct context *context = user_data;
+
+ g_assert_cmpstr(prefix, ==, "AT+BRSF");
+
+ hfp_hf_disconnect(context->hfp_hf);
+}
+
+static void test_hf_send_command(gconstpointer data)
+{
+ struct context *context = create_context(data);
+ const struct test_pdu *pdu;
+ bool ret;
+
+ context->hfp_hf = hfp_hf_new(context->fd_client);
+ g_assert(context->hfp_hf);
+
+ ret = hfp_hf_set_close_on_unref(context->hfp_hf, true);
+ g_assert(ret);
+
+ if (context->data->response_func) {
+ if (context->data->hf_result_func) {
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ ret = hfp_hf_register(context->hfp_hf,
+ context->data->hf_result_func,
+ (char *)pdu->data,
+ NULL, NULL);
+ g_assert(ret);
+ }
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ ret = hfp_hf_send_command(context->hfp_hf,
+ context->data->response_func,
+ context, (char *)pdu->data);
+ g_assert(ret);
+ }
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -538,6 +600,21 @@ int main(int argc, char *argv[])
data_end());
define_hf_test("/hfp/test_init", test_hf_init, NULL, NULL, data_end());
+ define_hf_test("/hfp/test_send_command_1", test_hf_send_command, NULL,
+ hf_brsf_response_cb,
+ raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '\0'),
+ raw_pdu('\r', '\n', 'O', 'k', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp/test_send_command_2", test_hf_send_command,
+ hf_unsolicited_resp_cb,
+ hf_response_with_data,
+ raw_pdu('+', 'B', 'R', 'S', 'F', '\0'),
+ raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '\0'),
+ frg_pdu('\r', '\n', '+', 'B', 'R', 'S', 'F', '\r',
+ '\n'),
+ frg_pdu('\r', '\n', 'O', 'k', '\r', '\n'),
+ data_end());
return g_test_run();
}
--
1.8.4
^ permalink raw reply related
* [PATCH v4 08/11] unit/test-hfp: Add init test for HFP HF
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898611-12199-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds basic infrastruction for HFP HF test plus
init test.
It also moves send_pdu function in the file so it can be used by
test_hf_handler
---
unit/test-hfp.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 84 insertions(+), 18 deletions(-)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 4b3473b..274ee55 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -36,6 +36,7 @@ struct context {
int fd_server;
int fd_client;
struct hfp_gw *hfp;
+ struct hfp_hf *hfp_hf;
const struct test_data *data;
unsigned int pdu_offset;
};
@@ -52,6 +53,8 @@ struct test_data {
char *test_name;
struct test_pdu *pdu_list;
hfp_result_func_t result_func;
+ hfp_response_func_t response_func;
+ hfp_hf_result_func_t hf_result_func;
GIOFunc test_handler;
};
@@ -99,6 +102,22 @@ struct test_data {
data.test_handler = test_handler; \
} while (0)
+#define define_hf_test(name, function, result_func, response_function, \
+ args...)\
+ do { \
+ const struct test_pdu pdus[] = { \
+ args, { } \
+ }; \
+ static struct test_data data; \
+ data.test_name = g_strdup(name); \
+ data.pdu_list = g_malloc(sizeof(pdus)); \
+ data.hf_result_func = result_func; \
+ data.response_func = response_function; \
+ memcpy(data.pdu_list, pdus, sizeof(pdus)); \
+ g_test_add_data_func(name, &data, function); \
+ data.test_handler = test_hf_handler; \
+ } while (0)
+
static void context_quit(struct context *context)
{
g_main_loop_quit(context->main_loop);
@@ -128,6 +147,52 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
return FALSE;
}
+static gboolean send_pdu(gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ ssize_t len;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ if (pdu && !pdu->valid)
+ return FALSE;
+
+ len = write(context->fd_server, pdu->data, pdu->size);
+ g_assert_cmpint(len, ==, pdu->size);
+
+ pdu = &context->data->pdu_list[context->pdu_offset];
+ if (pdu->fragmented)
+ g_idle_add(send_pdu, context);
+
+ return FALSE;
+}
+
+static gboolean test_hf_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ gchar buf[60];
+ gsize bytes_read;
+ GError *error = NULL;
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+ goto done;
+
+ /* dummy read */
+ g_io_channel_read_chars(channel, buf, 60, &bytes_read, &error);
+
+ send_pdu(context);
+
+ return TRUE;
+
+done:
+ context_quit(context);
+ context->watch_id = 0;
+
+ return FALSE;
+}
+
static void cmd_handler(const char *command, void *user_data)
{
struct context *context = user_data;
@@ -203,6 +268,9 @@ static void execute_context(struct context *context)
if (context->hfp)
hfp_gw_unref(context->hfp);
+ if (context->hfp_hf)
+ hfp_hf_unref(context->hfp_hf);
+
g_free(context);
}
@@ -275,24 +343,6 @@ static void test_register(gconstpointer data)
execute_context(context);
}
-static gboolean send_pdu(gpointer user_data)
-{
- struct context *context = user_data;
- const struct test_pdu *pdu;
- ssize_t len;
-
- pdu = &context->data->pdu_list[context->pdu_offset++];
-
- len = write(context->fd_server, pdu->data, pdu->size);
- g_assert_cmpint(len, ==, pdu->size);
-
- pdu = &context->data->pdu_list[context->pdu_offset];
- if (pdu->fragmented)
- g_idle_add(send_pdu, context);
-
- return FALSE;
-}
-
static void test_fragmented(gconstpointer data)
{
struct context *context = create_context(data);
@@ -404,6 +454,20 @@ static void check_string_2(struct hfp_gw_result *result,
hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
}
+static void test_hf_init(gconstpointer data)
+{
+ struct context *context = create_context(data);
+
+ context->hfp_hf = hfp_hf_new(context->fd_client);
+ g_assert(context->hfp_hf);
+ g_assert(hfp_hf_set_close_on_unref(context->hfp_hf, true));
+
+ hfp_hf_unref(context->hfp_hf);
+ context->hfp_hf = NULL;
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -473,5 +537,7 @@ int main(int argc, char *argv[])
raw_pdu('\r'),
data_end());
+ define_hf_test("/hfp/test_init", test_hf_init, NULL, NULL, data_end());
+
return g_test_run();
}
--
1.8.4
^ permalink raw reply related
* [PATCH v4 07/11] unit/test-hfp: Provide test_handler function via struct data
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1412898611-12199-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch allows us to use user defined test handler depends on needs.
Will use it in following patches which implements tests for HFP HF.
---
unit/test-hfp.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index a8801b0..4b3473b 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -52,6 +52,7 @@ struct test_data {
char *test_name;
struct test_pdu *pdu_list;
hfp_result_func_t result_func;
+ GIOFunc test_handler;
};
#define data(args...) ((const unsigned char[]) { args })
@@ -95,6 +96,7 @@ struct test_data {
data.result_func = result_function; \
memcpy(data.pdu_list, pdus, sizeof(pdus)); \
g_test_add_data_func(name, &data, function); \
+ data.test_handler = test_handler; \
} while (0)
static void context_quit(struct context *context)
@@ -158,6 +160,7 @@ static struct context *create_context(gconstpointer data)
struct context *context = g_new0(struct context, 1);
GIOChannel *channel;
int err, sv[2];
+ const struct test_data *d = data;
context->main_loop = g_main_loop_new(NULL, FALSE);
g_assert(context->main_loop);
@@ -173,7 +176,8 @@ static struct context *create_context(gconstpointer data)
context->watch_id = g_io_add_watch(channel,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- test_handler, context);
+ d->test_handler, context);
+
g_assert(context->watch_id > 0);
g_io_channel_unref(channel);
--
1.8.4
^ 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