Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH] Bluetooth: Defer connection-parameter removal when unpairing without disconnecting
From: Alfonso Acosta @ 2014-10-09 13:26 UTC (permalink / raw)
  To: BlueZ development
In-Reply-To: <1412859828-6224-1-git-send-email-fons@spotify.com>

Hi,

As an alternative to this patch, I am thinking that it may be worth
considering two other options:

1. Adding an additional repairing operation: MGMT_OP_REPAIR_DEVICE.
Making the repairing semantics explicit  would allow us to keep the connection
parameters even if we choose to disconnect when unpairing.  On the
other hand, one could argue that it clutters the API with an extra
operation which is the composite of two already existing operations.

2. Make MGMT_OP_PAIR_DEVICE behave like the repairing operation in (1)
if the device was already paired. If I recall properly, Johan suggested
this on IRC.

Comments?

Thanks,

Fons

On Thu, Oct 9, 2014 at 3:03 PM, Alfonso Acosta <fons@spotify.com> wrote:
> Systematically removing the LE connection parameters and autoconnect
> action is inconvenient for rebonding without disconnecting from
> userland (i.e. unpairing followed by repairing without
> disconnecting). The parameters will be lost after unparing and
> userland needs to take care of book-keeping them and re-adding them.
>
> This patch allows userland to forget about parameter management when
> rebonding without disconnecting. It defers clearing the connection
> parameters when unparing without disconnecting, giving a chance of
> keeping the parameters if a repairing happens before the connection is
> closed.
>
> Signed-off-by: Alfonso Acosta <fons@spotify.com>
> ---
>  include/net/bluetooth/hci_core.h |  1 +
>  net/bluetooth/hci_conn.c         |  6 ++++++
>  net/bluetooth/mgmt.c             | 16 +++++++++++++---
>  3 files changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 07ddeed62..b8685a7 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -555,6 +555,7 @@ enum {
>         HCI_CONN_STK_ENCRYPT,
>         HCI_CONN_AUTH_INITIATOR,
>         HCI_CONN_DROP,
> +       HCI_CONN_PARAM_REMOVAL_PEND,
>  };
>
>  static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index b9517bd..d106f29 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -356,6 +356,9 @@ static void hci_conn_timeout(struct work_struct *work)
>                 conn->state = BT_CLOSED;
>                 break;
>         }
> +
> +       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);
> +
>         hci_dev_put(hdev);
>
>         hci_conn_put(conn);
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 3fd88b0..0f2c0e9 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -2700,6 +2700,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
>         struct hci_cp_disconnect dc;
>         struct pending_cmd *cmd;
>         struct hci_conn *conn;
> +       struct hci_conn *le_conn = NULL;
>         int err;
>
>         memset(&rp, 0, sizeof(rp));
> @@ -2736,7 +2737,17 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
>
>                 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
>
> -               hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
> +               le_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
> +                                                 &cp->addr.bdaddr);
> +
> +               /* If the BLE connection is being used, defer clearing up
> +                * the connection parameters until closing to give a
> +                * chance of keeping them if a repairing happens.
> +                */
> +               if (le_conn && !cp->disconnect)
> +                       set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &le_conn->flags);
> +               else
> +                       hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
>
>                 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
>         }
> @@ -2752,8 +2763,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
>                         conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
>                                                        &cp->addr.bdaddr);
>                 else
> -                       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
> -                                                      &cp->addr.bdaddr);
> +                       conn = le_conn;
>         } else {
>                 conn = NULL;
>         }
> --
> 1.9.1
>



-- 
Alfonso Acosta

Embedded Systems Engineer at Spotify
Birger Jarlsgatan 61, Stockholm, Sweden
http://www.spotify.com

^ permalink raw reply

* Re: [PATCH] Bluetooth: Defer connection-parameter removal when unpairing without disconnecting
From: Johan Hedberg @ 2014-10-09 14:14 UTC (permalink / raw)
  To: Alfonso Acosta; +Cc: linux-bluetooth
In-Reply-To: <1412859828-6224-1-git-send-email-fons@spotify.com>

Hi Alfonso,

On Thu, Oct 09, 2014, Alfonso Acosta wrote:
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -555,6 +555,7 @@ enum {
>  	HCI_CONN_STK_ENCRYPT,
>  	HCI_CONN_AUTH_INITIATOR,
>  	HCI_CONN_DROP,
> +	HCI_CONN_PARAM_REMOVAL_PEND,
>  };
>  
>  static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index b9517bd..d106f29 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -356,6 +356,9 @@ static void hci_conn_timeout(struct work_struct *work)
>  		conn->state = BT_CLOSED;
>  		break;
>  	}
> +
> +	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?

Johan


>  	hci_dev_put(hdev);
>  
>  	hci_conn_put(conn);
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 3fd88b0..0f2c0e9 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -2700,6 +2700,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
>  	struct hci_cp_disconnect dc;
>  	struct pending_cmd *cmd;
>  	struct hci_conn *conn;
> +	struct hci_conn *le_conn = NULL;

I don't think you need to initialize this here since it's
unconditionally set in the first LE addr type branch and only touched
again in the second LE branch. Actually do you even need this second
variable if you simply assign to conn when you look up the LE
connection?

> @@ -2752,8 +2763,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
>  			conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
>  						       &cp->addr.bdaddr);
>  		else
> -			conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
> -						       &cp->addr.bdaddr);
> +			conn = le_conn;

Here you could then simply remove the "else" branch with a comment that
the conn is already looked up for LE addresses earlier in the function.
Not sure if that makes the code harder to follow though...

Johan

^ permalink raw reply

* Re: btusb_intr_complete returns -EPIPE
From: Alan Stern @ 2014-10-09 14:31 UTC (permalink / raw)
  To: Naveen Kumar Parna
  Cc: Oliver Neukum, linux-bluetooth@vger.kernel.org, linux-usb, acho
In-Reply-To: <CAG0bkvJDLP2tgnzu7H_ZCRCnZwkw1zUd1uqWwoDkmrU_FLts7w@mail.gmail.com>

On Thu, 9 Oct 2014, Naveen Kumar Parna wrote:

> Hi Oliver & Alan,
> 
> 
> 
> Thanks for your inputs.
> 
> 
> 
> I enabled the dynamic debugging for USB HC driver. Please correct me
> if I am wrong.

Debugging the kernel (or doing anything else to the kernel, for that
matter) won't solve the problem if it is caused by a buggy hub.

Alan Stern


^ permalink raw reply

* Re: [PATCH] Bluetooth: Defer connection-parameter removal when unpairing without disconnecting
From: Alfonso Acosta @ 2014-10-09 14:39 UTC (permalink / raw)
  To: Alfonso Acosta, BlueZ development
In-Reply-To: <20141009141430.GA31807@t440s.P-661HNU-F1>

Hi Johan,

>> +
>> +     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.


>> @@ -2700,6 +2700,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
>>       struct hci_cp_disconnect dc;
>>       struct pending_cmd *cmd;
>>       struct hci_conn *conn;
>> +     struct hci_conn *le_conn = NULL;
>
> I don't think you need to initialize this here since it's
> unconditionally set in the first LE addr type branch and only touched
> again in the second LE branch. Actually do you even need this second
> variable if you simply assign to conn when you look up the LE
> connection?

I did it to silence an unitialized-variable warning from gcc  (at least
the 4.8 version I am using is not good enough to conclude that the
variable is initialized).

>> @@ -2752,8 +2763,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
>>                       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
>>                                                      &cp->addr.bdaddr);
>>               else
>> -                     conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
>> -                                                    &cp->addr.bdaddr);
>> +                     conn = le_conn;
>
> Here you could then simply remove the "else" branch with a comment that
> the conn is already looked up for LE addresses earlier in the function.
> Not sure if that makes the code harder to follow though...

My intention was precisely to make it easier to follow by showing that
LE was being taken care of with an explicit assignment.

Buy yeah, I can simply remove le_conn altogether and add a comment instead.

Note that removing the else branch will also cause an
uninitialized-variable compiler warning on conn.

I could use uninitialized_var() instead of using NULL, I simply
decided against it after reading http://lwn.net/Articles/529954/

-- 
Alfonso Acosta

Embedded Systems Engineer at Spotify
Birger Jarlsgatan 61, Stockholm, Sweden
http://www.spotify.com

^ permalink raw reply

* [PATCH] android/pts: RFCOMM PTS 5.3 update
From: Sebastian Chlad @ 2014-10-09 15:15 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sebastian Chlad

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
 -------------------------------------------------------------------------------
-- 
1.8.5.3


^ permalink raw reply related

* linux-firmware: Add firmware patch for Intel Bluetooth 7265 ROM-spin(D0)
From: Tedd Ho-Jeong An @ 2014-10-09 15:56 UTC (permalink / raw)
  To: linux-firmware, Kyle McMartin; +Cc: linux-bluetooth, tedd.an

From: Tedd Ho-Jeong An <tedd.an@intel.com>
Date: Thu, 9 Oct 2014 08:16:05 -0700

This patch adds new firmware patch for
- Intel Wireless 7265 Bluetooth ROM-spin SKU, also known as StP D0

This patch was submitted but reverted due to patch issue.
The original patch's commit id: 935b5557b1485d839748b40f5721539b54d429e1

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
---
 WHENCE                                   |   2 ++
 intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq | Bin 0 -> 8441 bytes
 2 files changed, 2 insertions(+)
 create mode 100755 intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq

diff --git a/WHENCE b/WHENCE
index 3b5f078..b77516d 100644
--- a/WHENCE
+++ b/WHENCE
@@ -2405,6 +2405,8 @@ File: intel/ibt-hw-37.8.bseq
 Version: 1339_02.00
 File: intel/ibt-hw-37.8.10-fw-1.10.2.27.d.bseq
 Version: STP2_C0_1339_02_patch_31.1
+File: intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq
+Version: STP2_D0_1417_04_patch_04.1
 
 Licence: Redistributable. See LICENCE.ibt_firmware for details
 
diff --git a/intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq b/intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq
new file mode 100755
index 0000000000000000000000000000000000000000..95a32a96d863a19726fa0d6faad5b0917cb6adcb
GIT binary patch
literal 8441
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
F_-~X>mv8_8

literal 0
HcmV?d00001

-- 
1.9.1


^ permalink raw reply related

* Re: linux-firmware: Add firmware patch for Intel Bluetooth 7265 ROM-spin(D0)
From: Kyle McMartin @ 2014-10-09 16:00 UTC (permalink / raw)
  To: Tedd Ho-Jeong An; +Cc: linux-firmware, Kyle McMartin, linux-bluetooth
In-Reply-To: <20141009085609.519dbbaa@tedd-ubuntu-vm2>

On Thu, Oct 09, 2014 at 08:56:09AM -0700, Tedd Ho-Jeong An wrote:
> From: Tedd Ho-Jeong An <tedd.an@intel.com>
> Date: Thu, 9 Oct 2014 08:16:05 -0700
> 
> This patch adds new firmware patch for
> - Intel Wireless 7265 Bluetooth ROM-spin SKU, also known as StP D0
> 
> This patch was submitted but reverted due to patch issue.
> The original patch's commit id: 935b5557b1485d839748b40f5721539b54d429e1
> 
> Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>

this one worked without a hitch. :)

thanks! --kyle

> ---
>  WHENCE                                   |   2 ++
>  intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq | Bin 0 -> 8441 bytes
>  2 files changed, 2 insertions(+)
>  create mode 100755 intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq
> 
> diff --git a/WHENCE b/WHENCE
> index 3b5f078..b77516d 100644
> --- a/WHENCE
> +++ b/WHENCE
> @@ -2405,6 +2405,8 @@ File: intel/ibt-hw-37.8.bseq
>  Version: 1339_02.00
>  File: intel/ibt-hw-37.8.10-fw-1.10.2.27.d.bseq
>  Version: STP2_C0_1339_02_patch_31.1
> +File: intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq
> +Version: STP2_D0_1417_04_patch_04.1
>  
>  Licence: Redistributable. See LICENCE.ibt_firmware for details
>  
> diff --git a/intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq b/intel/ibt-hw-37.8.10-fw-1.10.3.11.e.bseq
> new file mode 100755
> index 0000000000000000000000000000000000000000..95a32a96d863a19726fa0d6faad5b0917cb6adcb
> GIT binary patch
> literal 8441
> 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
> F_-~X>mv8_8
> 
> literal 0
> HcmV?d00001
> 
> -- 
> 1.9.1
> 
> 

^ permalink raw reply

* [PATCH v4 00/11] shared/hfp: Add support for HFP HF
From: Lukasz Rymanowski @ 2014-10-09 23:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Lukasz Rymanowski

Following patches extends hfp API with HFP HF functionality.
HFP HF parser has been added and unit test for it.

To consider: how strict we should be when it comes to parsing
AT responses. For example, at the moment, command +CCLC:<cr><lf>
will be recognized as +CCLC: eventhough correct response format
should be <cr><lf>+CCLC:<cr><lf>

Note: As discussed on IRC I did not try to generalize code.

v2:
* minor self review fixes
* response callback on send command, contains now result (OK/ERROR) and
data from unsolicited response if available.

v3:
* Fix some memory leaks found on self review

v4:
* Fallback to approach from v1 in context of response callback for AT command.
Bassically, if AT+X has +X and OK response, response callback contains only OK or
ERROR code (including CME which will be added in following patches). To get +X
response, user need to use hfp_hf_register() API. It is done mostly to keep hfp.c
simple. With this approach we do not have to cache all +X in hfp.c before calling
response callback.

Lukasz Rymanowski (11):
  shared/hfp: Add support for HFP HF
  shared/hfp: Add set_debug and close_on_unref API for HFP HF
  shared/hfp: Add set disconnect handler and disconnect API to HFP HF
  shared/hfp: Add register/unregister event for HFP HF
  shared/hfp: Add HFP HF parser
  shared/hfp: Add send AT command API for HFP HF
  unit/test-hfp: Provide test_handler function via struct data
  unit/test-hfp: Add init test for HFP HF
  unit/test-hfp: Add send command tests for HFP HF
  unit/test-hfp: Add tests for unsolicited results for HFP HF
  unit/test-hfp: Add some robustness tests for HFP HF

 src/shared/hfp.c | 624 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/hfp.h |  30 +++
 unit/test-hfp.c  | 285 +++++++++++++++++++++++--
 3 files changed, 920 insertions(+), 19 deletions(-)

-- 
1.8.4


^ permalink raw reply

* [PATCH v4 01/11] shared/hfp: Add support 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 add struct hfp_hf plus fuctions to create an instance ref and
unref. This code based on existing hfp_gw
---
 src/shared/hfp.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/hfp.h |  6 ++++
 2 files changed, 98 insertions(+)

diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index efc981f..dbd049a 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -62,6 +62,18 @@ struct hfp_gw {
 	bool destroyed;
 };
 
+struct hfp_hf {
+	int ref_count;
+	int fd;
+	bool close_on_unref;
+	struct io *io;
+	struct ringbuf *read_buf;
+	struct ringbuf *write_buf;
+
+	bool in_disconnect;
+	bool destroyed;
+};
+
 struct cmd_handler {
 	char *prefix;
 	void *user_data;
@@ -807,3 +819,83 @@ bool hfp_gw_disconnect(struct hfp_gw *hfp)
 
 	return io_shutdown(hfp->io);
 }
+
+struct hfp_hf *hfp_hf_new(int fd)
+{
+	struct hfp_hf *hfp;
+
+	if (fd < 0)
+		return NULL;
+
+	hfp = new0(struct hfp_hf, 1);
+	if (!hfp)
+		return NULL;
+
+	hfp->fd = fd;
+	hfp->close_on_unref = false;
+
+	hfp->read_buf = ringbuf_new(4096);
+	if (!hfp->read_buf) {
+		free(hfp);
+		return NULL;
+	}
+
+	hfp->write_buf = ringbuf_new(4096);
+	if (!hfp->write_buf) {
+		ringbuf_free(hfp->read_buf);
+		free(hfp);
+		return NULL;
+	}
+
+	hfp->io = io_new(fd);
+	if (!hfp->io) {
+		ringbuf_free(hfp->write_buf);
+		ringbuf_free(hfp->read_buf);
+		free(hfp);
+		return NULL;
+	}
+
+	return hfp_hf_ref(hfp);
+}
+
+struct hfp_hf *hfp_hf_ref(struct hfp_hf *hfp)
+{
+	if (!hfp)
+		return NULL;
+
+	__sync_fetch_and_add(&hfp->ref_count, 1);
+
+	return hfp;
+}
+
+void hfp_hf_unref(struct hfp_hf *hfp)
+{
+	if (!hfp)
+		return;
+
+	if (__sync_sub_and_fetch(&hfp->ref_count, 1))
+		return;
+
+	io_set_write_handler(hfp->io, NULL, NULL, NULL);
+	io_set_read_handler(hfp->io, NULL, NULL, NULL);
+	io_set_disconnect_handler(hfp->io, NULL, NULL, NULL);
+
+	io_destroy(hfp->io);
+	hfp->io = NULL;
+
+	if (hfp->close_on_unref)
+		close(hfp->fd);
+
+	ringbuf_free(hfp->read_buf);
+	hfp->read_buf = NULL;
+
+	ringbuf_free(hfp->write_buf);
+	hfp->write_buf = NULL;
+
+	if (!hfp->in_disconnect) {
+		free(hfp);
+		return;
+	}
+
+	hfp->destroyed = true;
+}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 743db65..50d9c4b 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -76,9 +76,11 @@ typedef void (*hfp_destroy_func_t)(void *user_data);
 typedef void (*hfp_debug_func_t)(const char *str, void *user_data);
 
 typedef void (*hfp_command_func_t)(const char *command, void *user_data);
+
 typedef void (*hfp_disconnect_func_t)(void *user_data);
 
 struct hfp_gw;
+struct hfp_hf;
 
 struct hfp_gw *hfp_gw_new(int fd);
 
@@ -124,3 +126,7 @@ bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
 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);
+
+struct hfp_hf *hfp_hf_new(int fd);
+struct hfp_hf *hfp_hf_ref(struct hfp_hf *hfp);
+void hfp_hf_unref(struct hfp_hf *hfp);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v4 02/11] shared/hfp: Add set_debug and close_on_unref API 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>

---
 src/shared/hfp.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/hfp.h |  3 +++
 2 files changed, 60 insertions(+)

diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index dbd049a..ad2daa2 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -70,6 +70,10 @@ struct hfp_hf {
 	struct ringbuf *read_buf;
 	struct ringbuf *write_buf;
 
+	hfp_debug_func_t debug_callback;
+	hfp_destroy_func_t debug_destroy;
+	void *debug_data;
+
 	bool in_disconnect;
 	bool destroyed;
 };
@@ -886,6 +890,8 @@ void hfp_hf_unref(struct hfp_hf *hfp)
 	if (hfp->close_on_unref)
 		close(hfp->fd);
 
+	hfp_hf_set_debug(hfp, NULL, NULL, NULL);
+
 	ringbuf_free(hfp->read_buf);
 	hfp->read_buf = NULL;
 
@@ -899,3 +905,54 @@ void hfp_hf_unref(struct hfp_hf *hfp)
 
 	hfp->destroyed = true;
 }
+
+static void hf_read_tracing(const void *buf, size_t count,
+							void *user_data)
+{
+	struct hfp_hf *hfp = user_data;
+
+	util_hexdump('>', buf, count, hfp->debug_callback, hfp->debug_data);
+}
+
+static void hf_write_tracing(const void *buf, size_t count,
+							void *user_data)
+{
+	struct hfp_hf *hfp = user_data;
+
+	util_hexdump('<', buf, count, hfp->debug_callback, hfp->debug_data);
+}
+
+bool hfp_hf_set_debug(struct hfp_hf *hfp, hfp_debug_func_t callback,
+				void *user_data, hfp_destroy_func_t destroy)
+{
+	if (!hfp)
+		return false;
+
+	if (hfp->debug_destroy)
+		hfp->debug_destroy(hfp->debug_data);
+
+	hfp->debug_callback = callback;
+	hfp->debug_destroy = destroy;
+	hfp->debug_data = user_data;
+
+	if (hfp->debug_callback) {
+		ringbuf_set_input_tracing(hfp->read_buf, hf_read_tracing, hfp);
+		ringbuf_set_input_tracing(hfp->write_buf, hf_write_tracing,
+									hfp);
+	} else {
+		ringbuf_set_input_tracing(hfp->read_buf, NULL, NULL);
+		ringbuf_set_input_tracing(hfp->write_buf, NULL, NULL);
+	}
+
+	return true;
+}
+
+bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close)
+{
+	if (!hfp)
+		return false;
+
+	hfp->close_on_unref = do_close;
+
+	return true;
+}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 50d9c4b..ae67ac2 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -130,3 +130,6 @@ bool hfp_gw_result_has_next(struct hfp_gw_result *result);
 struct hfp_hf *hfp_hf_new(int fd);
 struct hfp_hf *hfp_hf_ref(struct hfp_hf *hfp);
 void hfp_hf_unref(struct hfp_hf *hfp);
+bool hfp_hf_set_debug(struct hfp_hf *hfp, hfp_debug_func_t callback,
+				void *user_data, hfp_destroy_func_t destroy);
+bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v4 03/11] shared/hfp: Add set disconnect handler and disconnect API to 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>

---
 src/shared/hfp.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/hfp.h |  5 +++++
 2 files changed, 68 insertions(+)

diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index ad2daa2..b7855ed 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -74,6 +74,10 @@ struct hfp_hf {
 	hfp_destroy_func_t debug_destroy;
 	void *debug_data;
 
+	hfp_disconnect_func_t disconnect_callback;
+	hfp_destroy_func_t disconnect_destroy;
+	void *disconnect_data;
+
 	bool in_disconnect;
 	bool destroyed;
 };
@@ -956,3 +960,62 @@ bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close)
 
 	return true;
 }
+
+static void hf_disconnect_watch_destroy(void *user_data)
+{
+	struct hfp_hf *hfp = user_data;
+
+	if (hfp->disconnect_destroy)
+		hfp->disconnect_destroy(hfp->disconnect_data);
+
+	if (hfp->destroyed)
+		free(hfp);
+}
+
+static bool hf_io_disconnected(struct io *io, void *user_data)
+{
+	struct hfp_hf *hfp = user_data;
+
+	hfp->in_disconnect = true;
+
+	if (hfp->disconnect_callback)
+		hfp->disconnect_callback(hfp->disconnect_data);
+
+	hfp->in_disconnect = false;
+
+	return false;
+}
+
+bool hfp_hf_set_disconnect_handler(struct hfp_hf *hfp,
+						hfp_disconnect_func_t callback,
+						void *user_data,
+						hfp_destroy_func_t destroy)
+{
+	if (!hfp)
+		return false;
+
+	if (hfp->disconnect_destroy)
+		hfp->disconnect_destroy(hfp->disconnect_data);
+
+	if (!io_set_disconnect_handler(hfp->io, hf_io_disconnected, hfp,
+						hf_disconnect_watch_destroy)) {
+		hfp->disconnect_callback = NULL;
+		hfp->disconnect_destroy = NULL;
+		hfp->disconnect_data = NULL;
+		return false;
+	}
+
+	hfp->disconnect_callback = callback;
+	hfp->disconnect_destroy = destroy;
+	hfp->disconnect_data = user_data;
+
+	return true;
+}
+
+bool hfp_hf_disconnect(struct hfp_hf *hfp)
+{
+	if (!hfp)
+		return false;
+
+	return io_shutdown(hfp->io);
+}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index ae67ac2..a9a169b 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -133,3 +133,8 @@ void hfp_hf_unref(struct hfp_hf *hfp);
 bool hfp_hf_set_debug(struct hfp_hf *hfp, hfp_debug_func_t callback,
 				void *user_data, hfp_destroy_func_t destroy);
 bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close);
+bool hfp_hf_set_disconnect_handler(struct hfp_hf *hfp,
+					hfp_disconnect_func_t callback,
+					void *user_data,
+					hfp_destroy_func_t destroy);
+bool hfp_hf_disconnect(struct hfp_hf *hfp);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v4 04/11] shared/hfp: Add register/unregister event 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 API which allows to register/unregister for unsolicited
responses.
---
 src/shared/hfp.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/hfp.h |   8 +++++
 2 files changed, 116 insertions(+)

diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index b7855ed..b1cf08e 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -70,6 +70,8 @@ struct hfp_hf {
 	struct ringbuf *read_buf;
 	struct ringbuf *write_buf;
 
+	struct queue *event_handlers;
+
 	hfp_debug_func_t debug_callback;
 	hfp_destroy_func_t debug_destroy;
 	void *debug_data;
@@ -94,6 +96,18 @@ struct hfp_gw_result {
 	unsigned int offset;
 };
 
+struct hfp_hf_result {
+	const char *data;
+	unsigned int offset;
+};
+
+struct event_handler {
+	char *prefix;
+	void *user_data;
+	hfp_destroy_func_t destroy;
+	hfp_hf_result_func_t callback;
+};
+
 static void destroy_cmd_handler(void *data)
 {
 	struct cmd_handler *handler = data;
@@ -828,6 +842,32 @@ bool hfp_gw_disconnect(struct hfp_gw *hfp)
 	return io_shutdown(hfp->io);
 }
 
+static bool match_handler_event_prefix(const void *a, const void *b)
+{
+	const struct event_handler *handler = a;
+	const char *prefix = b;
+
+	if (strlen(handler->prefix) != strlen(prefix))
+		return false;
+
+	if (memcmp(handler->prefix, prefix, strlen(prefix)))
+		return false;
+
+	return true;
+}
+
+static void destroy_event_handler(void *data)
+{
+	struct event_handler *handler = data;
+
+	if (handler->destroy)
+		handler->destroy(handler->user_data);
+
+	free(handler->prefix);
+
+	free(handler);
+}
+
 struct hfp_hf *hfp_hf_new(int fd)
 {
 	struct hfp_hf *hfp;
@@ -863,6 +903,15 @@ struct hfp_hf *hfp_hf_new(int fd)
 		return NULL;
 	}
 
+	hfp->event_handlers = queue_new();
+	if (!hfp->event_handlers) {
+		io_destroy(hfp->io);
+		ringbuf_free(hfp->write_buf);
+		ringbuf_free(hfp->read_buf);
+		free(hfp);
+		return NULL;
+	}
+
 	return hfp_hf_ref(hfp);
 }
 
@@ -902,6 +951,9 @@ void hfp_hf_unref(struct hfp_hf *hfp)
 	ringbuf_free(hfp->write_buf);
 	hfp->write_buf = NULL;
 
+	queue_destroy(hfp->event_handlers, destroy_event_handler);
+	hfp->event_handlers = NULL;
+
 	if (!hfp->in_disconnect) {
 		free(hfp);
 		return;
@@ -961,6 +1013,62 @@ bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close)
 	return true;
 }
 
+bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
+						const char *prefix,
+						void *user_data,
+						hfp_destroy_func_t destroy)
+{
+	struct event_handler *handler;
+
+	if (!callback)
+		return false;
+
+	handler = new0(struct event_handler, 1);
+	if (!handler)
+		return false;
+
+	handler->callback = callback;
+	handler->user_data = user_data;
+
+	handler->prefix = strdup(prefix);
+	if (!handler->prefix) {
+		free(handler);
+		return false;
+	}
+
+	if (queue_find(hfp->event_handlers, match_handler_event_prefix,
+							handler->prefix)) {
+		destroy_event_handler(handler);
+		return false;
+	}
+
+	handler->destroy = destroy;
+
+	return queue_push_tail(hfp->event_handlers, handler);
+}
+
+bool hfp_hf_unregister(struct hfp_hf *hfp, const char *prefix)
+{
+	struct cmd_handler *handler;
+	char *lookup_prefix;
+
+	lookup_prefix = strdup(prefix);
+	if (!lookup_prefix)
+		return false;
+
+	handler = queue_remove_if(hfp->event_handlers,
+						match_handler_event_prefix,
+						lookup_prefix);
+	free(lookup_prefix);
+
+	if (!handler)
+		return false;
+
+	destroy_event_handler(handler);
+
+	return true;
+}
+
 static void hf_disconnect_watch_destroy(void *user_data)
 {
 	struct hfp_hf *hfp = user_data;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index a9a169b..85037b1 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -68,10 +68,14 @@ enum hfp_gw_cmd_type {
 };
 
 struct hfp_gw_result;
+struct hfp_hf_result;
 
 typedef void (*hfp_result_func_t)(struct hfp_gw_result *result,
 				enum hfp_gw_cmd_type type, void *user_data);
 
+typedef void (*hfp_hf_result_func_t)(struct hfp_hf_result *result,
+							void *user_data);
+
 typedef void (*hfp_destroy_func_t)(void *user_data);
 typedef void (*hfp_debug_func_t)(const char *str, void *user_data);
 
@@ -138,3 +142,7 @@ bool hfp_hf_set_disconnect_handler(struct hfp_hf *hfp,
 					void *user_data,
 					hfp_destroy_func_t destroy);
 bool hfp_hf_disconnect(struct hfp_hf *hfp);
+bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
+					const char *prefix, void *user_data,
+					hfp_destroy_func_t destroy);
+bool hfp_hf_unregister(struct hfp_hf *hfp, const char *prefix);
-- 
1.8.4


^ permalink raw reply related

* [PATCH v4 05/11] shared/hfp: Add HFP HF parser
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 parser for AT responses and unsolicited results.
---
 src/shared/hfp.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 129 insertions(+)

diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index b1cf08e..5179092 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -868,6 +868,126 @@ static void destroy_event_handler(void *data)
 	free(handler);
 }
 
+static void hf_skip_whitespace(struct hfp_hf_result *result)
+{
+	while (result->data[result->offset] == ' ')
+		result->offset++;
+}
+
+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;
+	char lookup_prefix[18];
+	uint8_t pref_len = 0;
+	const char *prefix;
+	int i;
+
+	result_data.offset = 0;
+	result_data.data = data;
+
+	hf_skip_whitespace(&result_data);
+
+	if (strlen(data + result_data.offset) < 2)
+		return;
+
+	prefix = data + result_data.offset;
+
+	pref_len = strcspn(prefix, separators);
+	if (pref_len > 17 || pref_len < 2)
+		return;
+
+	for (i = 0; i < pref_len; i++)
+		lookup_prefix[i] = toupper(prefix[i]);
+
+	lookup_prefix[pref_len] = '\0';
+	result_data.offset += pref_len + 1;
+
+	handler = queue_find(hfp->event_handlers, match_handler_event_prefix,
+								lookup_prefix);
+	if (!handler)
+		return;
+
+	handler->callback(&result_data, handler->user_data);
+}
+
+static char *find_cr_lf(char *str, size_t len)
+{
+	char *ptr;
+	int count;
+	int offset;
+
+	offset = 0;
+
+	ptr = memchr(str, '\r', len);
+	while (ptr) {
+		/*
+		 * Check if there is more data after '\r'. If so check for
+		 * '\n'
+		 */
+		count = ptr-str;
+		if ((count < (int) (len - 1)) && *(ptr + 1) == '\n')
+			return ptr;
+
+		/* There is only '\r'? Let's try to find next one */
+		offset += count + 1;
+
+		if (offset >= (int)len)
+			return NULL;
+
+		ptr = memchr(str + offset, '\r', len - offset);
+	}
+
+	return NULL;
+}
+
+static void hf_process_input(struct hfp_hf *hfp)
+{
+	char *str, *ptr;
+	size_t len, count, offset;
+
+	str = ringbuf_peek(hfp->read_buf, 0, &len);
+	if (!str)
+		return;
+
+	offset = 0;
+
+	ptr = find_cr_lf(str, len);
+	while (ptr) {
+		count = ptr - (str + offset);
+		if (count == 0) {
+			/* 2 is for <cr><lf> */
+			offset += 2;
+		} else {
+			*ptr = '\0';
+			hf_call_prefix_handler(hfp, str + offset);
+			offset += count + 2;
+		}
+
+		if (offset >= len)
+			break;
+
+		ptr = find_cr_lf(str + offset, len - offset);
+	}
+
+	ringbuf_drain(hfp->read_buf, offset < len ? offset : len);
+}
+
+static bool hf_can_read_data(struct io *io, void *user_data)
+{
+	struct hfp_hf *hfp = user_data;
+	ssize_t bytes_read;
+
+	bytes_read = ringbuf_read(hfp->read_buf, hfp->fd);
+	if (bytes_read < 0)
+		return false;
+
+	hf_process_input(hfp);
+
+	return true;
+}
+
 struct hfp_hf *hfp_hf_new(int fd)
 {
 	struct hfp_hf *hfp;
@@ -912,6 +1032,15 @@ struct hfp_hf *hfp_hf_new(int fd)
 		return NULL;
 	}
 
+	if (!io_set_read_handler(hfp->io, hf_can_read_data, hfp,
+							read_watch_destroy)) {
+		queue_destroy(hfp->event_handlers,
+						destroy_event_handler);
+		io_destroy(hfp->io);
+		ringbuf_free(hfp->write_buf);
+		ringbuf_free(hfp->read_buf);
+	}
+
 	return hfp_hf_ref(hfp);
 }
 
-- 
1.8.4


^ permalink raw reply related

* [PATCH v4 06/11] shared/hfp: Add send AT command API 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 handling send and response of AT command.
Note that we always wait for AT command response before sending next
command, however user can fill hfp_hf with more than one command.
All the commands are queued and send one by one.
---
 src/shared/hfp.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/hfp.h |   8 +++
 2 files changed, 183 insertions(+)

diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 5179092..8bebe97 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -70,6 +70,9 @@ struct hfp_hf {
 	struct ringbuf *read_buf;
 	struct ringbuf *write_buf;
 
+	bool writer_active;
+	struct queue *cmd_queue;
+
 	struct queue *event_handlers;
 
 	hfp_debug_func_t debug_callback;
@@ -101,6 +104,14 @@ struct hfp_hf_result {
 	unsigned int offset;
 };
 
+struct cmd_response {
+	char *prefix;
+	hfp_response_func_t resp_cb;
+	struct hfp_hf_result *response;
+	char *resp_data;
+	void *user_data;
+};
+
 struct event_handler {
 	char *prefix;
 	void *user_data;
@@ -868,17 +879,103 @@ static void destroy_event_handler(void *data)
 	free(handler);
 }
 
+static bool hf_can_write_data(struct io *io, void *user_data)
+{
+	struct hfp_hf *hfp = user_data;
+	ssize_t bytes_written;
+
+	bytes_written = ringbuf_write(hfp->write_buf, hfp->fd);
+	if (bytes_written < 0)
+		return false;
+
+	if (ringbuf_len(hfp->write_buf) > 0)
+		return true;
+
+	return false;
+}
+
+static void hf_write_watch_destroy(void *user_data)
+{
+	struct hfp_hf *hfp = user_data;
+
+	hfp->writer_active = false;
+}
+
 static void hf_skip_whitespace(struct hfp_hf_result *result)
 {
 	while (result->data[result->offset] == ' ')
 		result->offset++;
 }
 
+static bool is_response(const char *prefix, enum hfp_result *result)
+{
+	if (strcmp(prefix, "OK") == 0) {
+		*result = HFP_RESULT_OK;
+		return true;
+	}
+
+	if (strcmp(prefix, "ERROR") == 0) {
+		*result = HFP_RESULT_ERROR;
+		return true;
+	}
+
+	if (strcmp(prefix, "NO CARRIER") == 0) {
+		*result = HFP_RESULT_NO_CARRIER;
+		return true;
+	}
+
+	if (strcmp(prefix, "CONNECT") == 0) {
+		*result = HFP_RESULT_CONNECT;
+		return true;
+	}
+
+	if (strcmp(prefix, "NO ANSWER") == 0) {
+		*result = HFP_RESULT_NO_ANSWER;
+		return true;
+	}
+
+	if (strcmp(prefix, "DELAYED") == 0) {
+		*result = HFP_RESULT_DELAYED;
+		return true;
+	}
+
+	if (strcmp(prefix, "BLACKLISTED") == 0) {
+		*result = HFP_RESULT_BLACKLISTED;
+		return true;
+	}
+
+	return false;
+}
+
+static void hf_wakeup_writer(struct hfp_hf *hfp)
+{
+	if (hfp->writer_active)
+		return;
+
+	if (!ringbuf_len(hfp->write_buf))
+		return;
+
+	if (!io_set_write_handler(hfp->io, hf_can_write_data,
+					hfp, hf_write_watch_destroy))
+		return;
+
+	hfp->writer_active = true;
+}
+
+static void destroy_cmd_response(void *data)
+{
+	struct cmd_response *cmd = data;
+
+	free(cmd->prefix);
+	free(cmd);
+}
+
 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;
+	enum hfp_result result;
 	char lookup_prefix[18];
 	uint8_t pref_len = 0;
 	const char *prefix;
@@ -904,6 +1001,22 @@ static void hf_call_prefix_handler(struct hfp_hf *hfp, const char *data)
 	lookup_prefix[pref_len] = '\0';
 	result_data.offset += pref_len + 1;
 
+	if (is_response(lookup_prefix, &result)) {
+		struct cmd_response *cmd;
+
+		cmd = queue_peek_head(hfp->cmd_queue);
+		if (!cmd)
+			return;
+
+		cmd->resp_cb(cmd->prefix, result, cmd->user_data);
+
+		queue_remove(hfp->cmd_queue, cmd);
+		destroy_cmd_response(cmd);
+
+		hf_wakeup_writer(hfp);
+		return;
+	}
+
 	handler = queue_find(hfp->event_handlers, match_handler_event_prefix,
 								lookup_prefix);
 	if (!handler)
@@ -1032,6 +1145,18 @@ struct hfp_hf *hfp_hf_new(int fd)
 		return NULL;
 	}
 
+	hfp->cmd_queue = queue_new();
+	if (!hfp->cmd_queue) {
+		io_destroy(hfp->io);
+		ringbuf_free(hfp->write_buf);
+		ringbuf_free(hfp->read_buf);
+		queue_destroy(hfp->event_handlers, NULL);
+		free(hfp);
+		return NULL;
+	}
+
+	hfp->writer_active = false;
+
 	if (!io_set_read_handler(hfp->io, hf_can_read_data, hfp,
 							read_watch_destroy)) {
 		queue_destroy(hfp->event_handlers,
@@ -1083,6 +1208,9 @@ void hfp_hf_unref(struct hfp_hf *hfp)
 	queue_destroy(hfp->event_handlers, destroy_event_handler);
 	hfp->event_handlers = NULL;
 
+	queue_destroy(hfp->cmd_queue, destroy_cmd_response);
+	hfp->cmd_queue = NULL;
+
 	if (!hfp->in_disconnect) {
 		free(hfp);
 		return;
@@ -1142,6 +1270,53 @@ bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close)
 	return true;
 }
 
+bool hfp_hf_send_command(struct hfp_hf *hfp, hfp_response_func_t resp_cb,
+				void *user_data, const char *format, ...)
+{
+	va_list ap;
+	char *fmt;
+	int len;
+	const char *separators = ";?=\0";
+	uint8_t prefix_len;
+	struct cmd_response *cmd;
+
+	if (!hfp || !format || !resp_cb)
+		return false;
+
+	if (asprintf(&fmt, "%s\r", format) < 0)
+		return false;
+
+	cmd = new0(struct cmd_response, 1);
+	if (!cmd)
+		return false;
+
+	va_start(ap, format);
+	len = ringbuf_vprintf(hfp->write_buf, fmt, ap);
+	va_end(ap);
+
+	free(fmt);
+
+	if (len < 0) {
+		free(cmd);
+		return false;
+	}
+
+	prefix_len = strcspn(format, separators);
+	cmd->prefix = strndup(format, prefix_len);
+	cmd->resp_cb = resp_cb;
+	cmd->user_data = user_data;
+
+	if (!queue_push_tail(hfp->cmd_queue, cmd)) {
+		ringbuf_drain(hfp->write_buf, len);
+		free(cmd);
+		return false;
+	}
+
+	hf_wakeup_writer(hfp);
+
+	return true;
+}
+
 bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
 						const char *prefix,
 						void *user_data,
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 85037b1..5ee3017 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -32,6 +32,8 @@ enum hfp_result {
 	HFP_RESULT_NO_DIALTONE	= 6,
 	HFP_RESULT_BUSY		= 7,
 	HFP_RESULT_NO_ANSWER	= 8,
+	HFP_RESULT_DELAYED	= 9,
+	HFP_RESULT_BLACKLISTED	= 10,
 };
 
 enum hfp_error {
@@ -83,6 +85,10 @@ typedef void (*hfp_command_func_t)(const char *command, void *user_data);
 
 typedef void (*hfp_disconnect_func_t)(void *user_data);
 
+typedef void (*hfp_response_func_t)(const char *prefix,
+							enum hfp_result result,
+							void *user_data);
+
 struct hfp_gw;
 struct hfp_hf;
 
@@ -146,3 +152,5 @@ bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
 					const char *prefix, void *user_data,
 					hfp_destroy_func_t destroy);
 bool hfp_hf_unregister(struct hfp_hf *hfp, const char *prefix);
+bool hfp_hf_send_command(struct hfp_hf *hfp, hfp_response_func_t resp_cb,
+				void *user_data, const char *format, ...);
-- 
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

* [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 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 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 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 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 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 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 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 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 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


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox