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 <sathish.narasimman@intel.com>
This commit is contained in:
parent
b0d34d83c5
commit
c719bfb689
2 changed files with 145 additions and 7 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue