From c719bfb6897b88220059f24d70eb7be5921e71af Mon Sep 17 00:00:00 2001 From: Sathish Narasimman Date: Thu, 3 Nov 2016 13:07:20 +0530 Subject: [PATCH] Bluetooth: HFP HF: SLC connection-Send/Parse BRSF Service Level Connection(SLC) Initialization part. Sending AT+BRSF and parsing its response. < ACL Data TX: Handle 256 flags 0x00 dlen 20 Channel: 75 len 16 [PSM 3 mode 0] {chan 0} RFCOMM: Unnumbered Info with Header Check (UIH) (0xef) Address: 0x09 cr 0 dlci 0x02 Control: 0xef poll/final 0 Length: 12 FCS: 0x40 41 54 2b 42 52 53 46 3d 31 34 38 0d 40 AT+BRSF=20. . > ACL Data RX: Handle 256 flags 0x02 dlen 23 Channel: 64 len 19 [PSM 3 mode 0] {chan 0} RFCOMM: Unnumbered Info with Header Check (UIH) (0xef) Address: 0x0b cr 1 dlci 0x02 Control: 0xff poll/final 1 Length: 14 FCS: 0x86 Credits: 4 0d 0a 2b 42 52 53 46 3a 20 38 37 31 0d 0a 86 ..+BRSF: 871. > ACL Data RX: Handle 256 flags 0x02 dlen 14 Channel: 64 len 10 [PSM 3 mode 0] {chan 0} RFCOMM: Unnumbered Info with Header Check (UIH) (0xef) Address: 0x0b cr 1 dlci 0x02 Control: 0xef poll/final 0 Length: 6 FCS: 0x9a 0d 0a 4f 4b 0d 0a 9a ..OK... Change-Id: I51581928d479ea4229b32a07cbea86c1f6fe09c8 Signed-off-by: Sathish Narasimman --- subsys/bluetooth/host/hfp_hf.c | 127 ++++++++++++++++++++++++++- subsys/bluetooth/host/hfp_internal.h | 25 +++++- 2 files changed, 145 insertions(+), 7 deletions(-) diff --git a/subsys/bluetooth/host/hfp_hf.c b/subsys/bluetooth/host/hfp_hf.c index 46c52d6e507..dc7422f711c 100644 --- a/subsys/bluetooth/host/hfp_hf.c +++ b/subsys/bluetooth/host/hfp_hf.c @@ -29,6 +29,7 @@ #include "l2cap_internal.h" #include "rfcomm_internal.h" +#include "at.h" #include "hfp_internal.h" #if !defined(CONFIG_BLUETOOTH_DEBUG_HFP_HF) @@ -38,16 +39,126 @@ struct bt_hfp_hf_cb *bt_hf; -static struct nano_fifo hf_buf; +static struct nano_fifo hf_fifo; static NET_BUF_POOL(hf_pool, CONFIG_BLUETOOTH_MAX_CONN + 1, - BT_RFCOMM_BUF_SIZE(BLUETOOTH_HFP_MAX_PDU), - &hf_buf, NULL, BT_BUF_USER_DATA_MIN); + BT_RFCOMM_BUF_SIZE(BLUETOOTH_HF_CLIENT_MAX_PDU), + &hf_fifo, NULL, BT_BUF_USER_DATA_MIN); static struct bt_hfp_hf bt_hfp_hf_pool[CONFIG_BLUETOOTH_MAX_CONN]; +void hf_slc_error(struct at_client *hf_at) +{ + BT_ERR("SLC error: disconnecting"); +} + +int hfp_hf_send_cmd(struct bt_hfp_hf *hf, at_resp_cb_t resp, + at_finish_cb_t finish, const char *format, ...) +{ + struct net_buf *buf; + va_list vargs; + int ret; + + /* register the callbacks */ + at_register(&hf->at, resp, finish); + + buf = bt_rfcomm_create_pdu(&hf_fifo); + if (!buf) { + BT_ERR("No Buffers!"); + return -ENOMEM; + } + + va_start(vargs, format); + ret = vsnprintf(buf->data, (net_buf_tailroom(buf) - 1), format, vargs); + if (ret < 0) { + BT_ERR("Unable to format variable arguments"); + return ret; + } + va_end(vargs); + + net_buf_add(buf, ret); + net_buf_add_u8(buf, '\r'); + + ret = bt_rfcomm_dlc_send(&hf->rfcomm_dlc, buf); + if (ret < 0) { + BT_ERR("Rfcomm send error :(%d)", ret); + return ret; + } + + return 0; +} + +int brsf_handle(struct at_client *hf_at) +{ + struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at); + uint32_t val; + int err; + + err = at_get_number(hf_at->buf, &val); + if (err < 0) { + BT_ERR("Error getting value"); + return err; + } + + hf->ag_features = val; + + return 0; +} + +int brsf_resp(struct at_client *hf_at, struct net_buf *buf) +{ + int err; + + BT_DBG(""); + + err = at_parse_cmd_input(hf_at, buf, "BRSF", brsf_handle); + if (err < 0) { + /* Returning negative value is avoided before SLC connection + * established. + */ + BT_ERR("Error parsing CMD input"); + hf_slc_error(hf_at); + } + + return 0; +} + +int brsf_finish(struct at_client *hf_at, struct net_buf *buf, + enum at_result result) +{ + if (result != AT_RESULT_OK) { + BT_ERR("SLC Connection ERROR in response"); + hf_slc_error(hf_at); + return -EINVAL; + } + + /* Continue with SLC creation */ + return 0; +} + +int hf_slc_establish(struct bt_hfp_hf *hf) +{ + int err; + + BT_DBG(""); + + err = hfp_hf_send_cmd(hf, brsf_resp, brsf_finish, "AT+BRSF=%u", + hf->hf_features); + if (err < 0) { + hf_slc_error(&hf->at); + return err; + } + + return 0; +} + static void hfp_hf_connected(struct bt_rfcomm_dlc *dlc) { + struct bt_hfp_hf *hf = CONTAINER_OF(dlc, struct bt_hfp_hf, rfcomm_dlc); + BT_DBG("hf connected"); + + BT_ASSERT(hf); + hf_slc_establish(hf); } static void hfp_hf_disconnected(struct bt_rfcomm_dlc *dlc) @@ -57,6 +168,11 @@ static void hfp_hf_disconnected(struct bt_rfcomm_dlc *dlc) static void hfp_hf_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf) { + struct bt_hfp_hf *hf = CONTAINER_OF(dlc, struct bt_hfp_hf, rfcomm_dlc); + + if (at_parse_input(&hf->at, buf) < 0) { + BT_ERR("Parsing failed"); + } } static int bt_hfp_hf_accept(struct bt_conn *conn, struct bt_rfcomm_dlc **dlc) @@ -77,8 +193,11 @@ static int bt_hfp_hf_accept(struct bt_conn *conn, struct bt_rfcomm_dlc **dlc) continue; } + hf->at.buf = hf->hf_buffer; + hf->at.buf_max_len = HF_MAX_BUF_LEN; + hf->rfcomm_dlc.ops = &ops; - hf->rfcomm_dlc.mtu = BLUETOOTH_HFP_MAX_PDU; + hf->rfcomm_dlc.mtu = BLUETOOTH_HFP_MAX_MTU; *dlc = &hf->rfcomm_dlc; diff --git a/subsys/bluetooth/host/hfp_internal.h b/subsys/bluetooth/host/hfp_internal.h index d96bbf45c1d..caaa7f78c27 100644 --- a/subsys/bluetooth/host/hfp_internal.h +++ b/subsys/bluetooth/host/hfp_internal.h @@ -18,7 +18,22 @@ * limitations under the License. */ -#define BLUETOOTH_HFP_MAX_PDU 140 +#define BLUETOOTH_HFP_MAX_MTU 140 +#define BLUETOOTH_HF_CLIENT_MAX_PDU 20 + +/* HFP AG Features */ +#define BT_HFP_AG_FEATURE_3WAY_CALL 0x00000001 /* Three-way calling */ +#define BT_HFP_AG_FEATURE_ECNR 0x00000002 /* EC and/or NR function */ +#define BT_HFP_AG_FEATURE_VOICE_RECG 0x00000004 /* Voice recognition */ +#define BT_HFP_AG_INBAND_RING_TONE 0x00000008 /* In-band ring capability */ +#define BT_HFP_AG_VOICE_TAG 0x00000010 /* Attach no. to voice tag */ +#define BT_HFP_AG_FEATURE_REJECT_CALL 0x00000020 /* Ability to reject call */ +#define BT_HFP_AG_FEATURE_ECS 0x00000040 /* Enhanced call status */ +#define BT_HFP_AG_FEATURE_ECC 0x00000080 /* Enhanced call control */ +#define BT_HFP_AG_FEATURE_EXT_ERR 0x00000100 /* Extented error codes */ +#define BT_HFP_AG_FEATURE_CODEC_NEG 0x00000200 /* Codec negotiation */ +#define BT_HFP_AG_FEATURE_HF_IND 0x00000400 /* HF Indicators */ +#define BT_HFP_AG_FEARTURE_ESCO_S4 0x00000800 /* eSCO S4 Settings */ /* HFP HF Features */ #define BT_HFP_HF_FEATURE_ECNR 0x00000001 /* EC and/or NR */ @@ -34,10 +49,14 @@ /* HFP HF Supported features */ #define BT_HFP_HF_SUPPORTED_FEATURES (BT_HFP_HF_FEATURE_CLI | \ - BT_HFP_HF_FEATURE_VOLUME | \ - BT_HFP_HF_FEATURE_CODEC_NEG) + BT_HFP_HF_FEATURE_VOLUME) + +#define HF_MAX_BUF_LEN 20 struct bt_hfp_hf { struct bt_rfcomm_dlc rfcomm_dlc; + char hf_buffer[HF_MAX_BUF_LEN]; + struct at_client at; uint32_t hf_features; + uint32_t ag_features; };