Bluetooth: HFP HF: SLC query indicators present value

Service level connection sending AT+CIND? and parse the response
to get the present value of the available indicators.
This patch also providing callback interface to application for
the indicators value received.

Also added doxygen comment for connected and disconnected callback.

< ACL Data TX: Handle 256 flags 0x00 dlen 17                   [hci0] 25.251358
      Channel: 67 len 13 [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: 9
         FCS: 0x40
        41 54 2b 43 49 4e 44 3f 0d 40                    AT+CIND?.@
> HCI Event: Number of Completed Packets (0x13) plen 5         [hci0] 25.262012
        Num handles: 1
        Handle: 256
        Count: 1
> ACL Data RX: Handle 256 flags 0x02 dlen 33                   [hci0] 25.293028
      Channel: 64 len 29 [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: 24
         FCS: 0x86
         Credits: 1
        0d 0a 2b 43 49 4e 44 3a 20 30 2c 30 2c 31 2c 33  ..+CIND: 0,0,1,3
        2c 30 2c 33 2c 30 0d 0a 86                       ,0,3,0...
> ACL Data RX: Handle 256 flags 0x02 dlen 14                   [hci0] 25.295006
      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: I7b2a89487e2d481391c51201e32b3287808f82dc
Signed-off-by: Sathish Narasimman <sathish.narasimman@intel.com>
This commit is contained in:
Sathish Narasimman 2016-11-14 19:01:18 +05:30 committed by Johan Hedberg
commit 7eacb0477c
3 changed files with 211 additions and 10 deletions

View file

@ -33,10 +33,81 @@
extern "C" {
#endif
/* HFP profile application callback */
/** @brief HFP profile application callback */
struct bt_hfp_hf_cb {
/** HF connected callback to application
*
* If this callback is provided it will be called whenever the
* connection completes.
*
* @param conn Connection object.
*/
void (*connected)(struct bt_conn *conn);
/** HF disconnected callback to application
*
* If this callback is provided it will be called whenever the
* connection gets disconnected, including when a connection gets
* rejected or cancelled or any error in SLC establisment.
*
* @param conn Connection object.
*/
void (*disconnected)(struct bt_conn *conn);
/** HF indicator Callback
*
* This callback provides service indicator value to the application
*
* @param conn Connection object.
* @param value service indicator value received from the AG.
*/
void (*service)(struct bt_conn *conn, uint32_t value);
/** HF indicator Callback
*
* This callback provides call indicator value to the application
*
* @param conn Connection object.
* @param value call indicator value received from the AG.
*/
void (*call)(struct bt_conn *conn, uint32_t value);
/** HF indicator Callback
*
* This callback provides call setup indicator value to the application
*
* @param conn Connection object.
* @param value call setup indicator value received from the AG.
*/
void (*call_setup)(struct bt_conn *conn, uint32_t value);
/** HF indicator Callback
*
* This callback provides call held indicator value to the application
*
* @param conn Connection object.
* @param value call held indicator value received from the AG.
*/
void (*call_held)(struct bt_conn *conn, uint32_t value);
/** HF indicator Callback
*
* This callback provides signal indicator value to the application
*
* @param conn Connection object.
* @param value signal indicator value received from the AG.
*/
void (*signal)(struct bt_conn *conn, uint32_t value);
/** HF indicator Callback
*
* This callback provides roaming indicator value to the application
*
* @param conn Connection object.
* @param value roaming indicator value received from the AG.
*/
void (*roam)(struct bt_conn *conn, uint32_t value);
/** HF indicator Callback
*
* This callback battery service indicator value to the application
*
* @param conn Connection object.
* @param value battery indicator value received from the AG.
*/
void (*battery)(struct bt_conn *conn, uint32_t value);
};
/** @brief Register HFP HF profile

View file

@ -47,18 +47,19 @@ NET_BUF_POOL_DEFINE(hf_pool, CONFIG_BLUETOOTH_MAX_CONN + 1,
static struct bt_hfp_hf bt_hfp_hf_pool[CONFIG_BLUETOOTH_MAX_CONN];
/* The order should follow the enum hfp_hf_ag_indicators */
static const struct {
char *name;
uint32_t min;
uint32_t max;
} ag_ind[] = {
{"service", 0, 1},
{"call", 0, 1},
{"callsetup", 0, 3},
{"callheld", 0, 2},
{"signal", 0, 5},
{"roam", 0, 1},
{"battchg", 0, 5}
{"service", 0, 1}, /* HF_SERVICE_IND */
{"call", 0, 1}, /* HF_CALL_IND */
{"callsetup", 0, 3}, /* HF_CALL_SETUP_IND */
{"callheld", 0, 2}, /* HF_CALL_HELD_IND */
{"signal", 0, 5}, /* HF_SINGNAL_IND */
{"roam", 0, 1}, /* HF_ROAM_IND */
{"battchg", 0, 5} /* HF_BATTERY_IND */
};
void hf_slc_error(struct at_client *hf_at)
@ -221,8 +222,105 @@ int cind_resp(struct at_client *hf_at, struct net_buf *buf)
return 0;
}
int cind_finish(struct at_client *hf_at, struct net_buf *buf,
enum at_result result)
void cind_status_handle_values(struct at_client *hf_at, uint32_t index,
uint32_t value)
{
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
BT_DBG("Index :%u, Value :%u", index, value);
if (index >= ARRAY_SIZE(ag_ind)) {
BT_ERR("Max only %lu indicators are supported",
ARRAY_SIZE(ag_ind));
return;
}
if (value > ag_ind[hf->ind_table[index]].max ||
value < ag_ind[hf->ind_table[index]].min) {
BT_ERR("Indicators out of range - value: %u", value);
return;
}
switch (hf->ind_table[index]) {
case HF_SERVICE_IND:
if (bt_hf->service) {
bt_hf->service(conn, value);
}
break;
case HF_CALL_IND:
if (bt_hf->call) {
bt_hf->call(conn, value);
}
break;
case HF_CALL_SETUP_IND:
if (bt_hf->call_setup) {
bt_hf->call_setup(conn, value);
}
break;
case HF_CALL_HELD_IND:
if (bt_hf->call_held) {
bt_hf->call_held(conn, value);
}
break;
case HF_SINGNAL_IND:
if (bt_hf->signal) {
bt_hf->signal(conn, value);
}
break;
case HF_ROAM_IND:
if (bt_hf->roam) {
bt_hf->roam(conn, value);
}
break;
case HF_BATTERY_IND:
if (bt_hf->battery) {
bt_hf->battery(conn, value);
}
break;
default:
BT_ERR("Unknown AG indicator");
break;
}
}
int cind_status_handle(struct at_client *hf_at)
{
uint32_t index = 0;
while (at_has_next_list(hf_at)) {
uint32_t value;
int ret;
ret = at_get_number(hf_at, &value);
if (ret < 0) {
BT_ERR("could not get the value");
return ret;
}
cind_status_handle_values(hf_at, index, value);
index++;
}
return 0;
}
int cind_status_resp(struct at_client *hf_at, struct net_buf *buf)
{
int err;
err = at_parse_cmd_input(hf_at, buf, "CIND", cind_status_handle);
if (err < 0) {
BT_ERR("Error parsing CMD input");
hf_slc_error(hf_at);
}
return 0;
}
int cind_status_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");
@ -235,6 +333,28 @@ int cind_finish(struct at_client *hf_at, struct net_buf *buf,
return 0;
}
int cind_finish(struct at_client *hf_at, struct net_buf *buf,
enum at_result result)
{
struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
int err;
if (result != AT_RESULT_OK) {
BT_ERR("SLC Connection ERROR in response");
hf_slc_error(hf_at);
return -EINVAL;
}
err = hfp_hf_send_cmd(hf, cind_status_resp, cind_status_finish,
"AT+CIND?");
if (err < 0) {
hf_slc_error(hf_at);
return err;
}
return 0;
}
int brsf_finish(struct at_client *hf_at, struct net_buf *buf,
enum at_result result)
{

View file

@ -62,3 +62,13 @@ struct bt_hfp_hf {
uint32_t ag_features;
int8_t ind_table[HF_MAX_AG_INDICATORS];
};
enum hfp_hf_ag_indicators {
HF_SERVICE_IND,
HF_CALL_IND,
HF_CALL_SETUP_IND,
HF_CALL_HELD_IND,
HF_SINGNAL_IND,
HF_ROAM_IND,
HF_BATTERY_IND
};