wireless/bluetooth: Add support for IOCTL commands to perform GATT discovery and obtain the results.
This commit is contained in:
parent
f27124dfc4
commit
2ebe8e99cc
@ -49,6 +49,7 @@
|
||||
#include <nuttx/wireless/wireless.h>
|
||||
#include <nuttx/wireless/bt_core.h>
|
||||
#include <nuttx/wireless/bt_hci.h>
|
||||
#include <nuttx/wireless/bt_gatt.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -59,7 +60,7 @@
|
||||
|
||||
/* Bluetooth network device IOCTL commands. */
|
||||
|
||||
#if !defined(WL_BLUETOOTHCMDS) || WL_BLUETOOTHCMDS != 16
|
||||
#if !defined(WL_BLUETOOTHCMDS) || WL_BLUETOOTHCMDS != 18
|
||||
# error Incorrect setting for number of Bluetooth IOCTL commands
|
||||
#endif
|
||||
|
||||
@ -162,6 +163,18 @@
|
||||
|
||||
#define SIOCBTSECURITY _WLIOC(WL_BLUETOOTHFIRST + 15)
|
||||
|
||||
/* GATT
|
||||
*
|
||||
* SIOCBTDISCOVER
|
||||
* Starts GATT discovery
|
||||
* SIOCBTDISCGET
|
||||
* Return discovery results buffered since the call time that the
|
||||
* SIOCBTDISCGET command was invoked.
|
||||
*/
|
||||
|
||||
#define SIOCBTDISCOVER _WLIOC(WL_BLUETOOTHFIRST + 16)
|
||||
#define SIOCBTDISCGET _WLIOC(WL_BLUETOOTHFIRST + 17)
|
||||
|
||||
/* Definitions associated with struct btreg_s *******************************/
|
||||
/* struct btreq_s union field accessors */
|
||||
|
||||
@ -193,6 +206,15 @@
|
||||
#define btr_secaddr btru.btrse.btrse_secaddr
|
||||
#define btr_seclevel btru.btrse.btrse_seclevel
|
||||
|
||||
#define btr_dtype btru.btrds.btrds_dtype
|
||||
#define btr_dpeer btru.btrds.btrds_dpeer
|
||||
#define btr_duuid16 btru.btrds.btrds_duuid16
|
||||
#define btr_dstart btru.btrds.btrds_dstart
|
||||
#define btr_dend btru.btrds.btrds_dend
|
||||
|
||||
#define btr_gnrsp btru.btrdg.btrdg_gnrsp
|
||||
#define btr_grsp btru.btrdg.btrdg_grsp
|
||||
|
||||
#define btr_stats btru.btrs
|
||||
|
||||
/* btr_flags */
|
||||
@ -213,6 +235,15 @@
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* Type of GATT discovery command */
|
||||
|
||||
enum bt_gatt_discover_e
|
||||
{
|
||||
GATT_DISCOVER = 0, /* Discover */
|
||||
GATT_DISCOVER_DESC, /* Discover descriptor */
|
||||
GATT_DISCOVER_CHAR, /* Discover characteristic */
|
||||
};
|
||||
|
||||
/* Write-able data that accompanies the SIOCBTSCANGET IOCTL command */
|
||||
|
||||
struct bt_scanresponse_s
|
||||
@ -224,6 +255,14 @@ struct bt_scanresponse_s
|
||||
uint8_t sr_data[CONFIG_BLUETOOTH_MAXSCANDATA];
|
||||
};
|
||||
|
||||
/* Write-able data that accompanies the SIOCBTDISCGET IOCTL command */
|
||||
|
||||
struct bt_discresonse_s
|
||||
{
|
||||
uint16_t dr_handle; /* Discovered handled */
|
||||
uint8_t dr_perm; /* Permissions */
|
||||
};
|
||||
|
||||
/* Bluetooth statistics */
|
||||
|
||||
struct bt_stats_s
|
||||
@ -323,6 +362,32 @@ struct btreq_s
|
||||
enum bt_security_e btrse_seclevel; /* Security level */
|
||||
} btrse;
|
||||
|
||||
/* Read-only data that accompanies SIOCBTDISCOVER command */
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t btrds_dtype; /* Discovery type (see enum
|
||||
* bt_gatt_discover_e) */
|
||||
bt_addr_le_t btrds_dpeer; /* Peer address */
|
||||
uint16_t btrds_duuid16; /* Discover UUID type */
|
||||
uint16_t btrds_dstart; /* Discover start handle */
|
||||
uint16_t btrds_dend; /* Discover end handle */
|
||||
} btrds;
|
||||
|
||||
/* Write-able structure that accompanies SIOCBTDISCGET command. */
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t btrdg_gnrsp; /* Input: Max number of responses
|
||||
* Return: Actual number of responses */
|
||||
|
||||
/* Reference to a beginning of an array in user memory in which to
|
||||
* return the discovered data. The size of the array is btrdg_gnrsp.
|
||||
*/
|
||||
|
||||
FAR struct bt_discresonse_s *btrdg_grsp;
|
||||
} btrdg;
|
||||
|
||||
struct bt_stats_s btrs; /* Unit statistics */
|
||||
} btru;
|
||||
};
|
||||
|
@ -160,7 +160,7 @@
|
||||
/* Reserved for Bluetooth network devices (see bt_ioctls.h) */
|
||||
|
||||
#define WL_BLUETOOTHFIRST (WL_NETFIRST + WL_NNETCMDS)
|
||||
#define WL_BLUETOOTHCMDS (16)
|
||||
#define WL_BLUETOOTHCMDS (18)
|
||||
#define WL_IBLUETOOTHCMD(cmd) (_WLIOCVALID(cmd) && \
|
||||
_IOC_NR(cmd) >= WL_BLUETOOTHFIRST && \
|
||||
_IOC_NR(cmd) < (WL_BLUETOOTHFIRST + WL_BLUETOOTHCMDS))
|
||||
|
@ -98,6 +98,15 @@ config BLUETOOTH_MAXSCANRESULT
|
||||
This contributes to a static memory allocation that will be greater
|
||||
than CONFIG_BLUETOOTH_MAXSCANDATA * CONFIG_BLUETOOTH_MAXSCANRESULT
|
||||
|
||||
config BLUETOOTH_MAXDISCOVER
|
||||
int "Max GATT discovery results"
|
||||
default 8
|
||||
range 1 255
|
||||
---help---
|
||||
GATT discovery results will be buffered in memory until the user
|
||||
requests the results. This parameter specifies the maximum results
|
||||
that can be buffered before discovery results are lost.
|
||||
|
||||
config BLUETOOTH_BUFFER_PREALLOC
|
||||
int "Number of pre-allocated buffer structures"
|
||||
default 20
|
||||
|
@ -702,6 +702,15 @@ done:
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_gatt_discover
|
||||
*
|
||||
* Description:
|
||||
* This function implements the SIOCBTDISCOVER ioctl command for the
|
||||
* GATT discovery.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_gatt_discover(FAR struct bt_conn_s *conn,
|
||||
FAR struct bt_gatt_discover_params_s *params)
|
||||
{
|
||||
@ -867,6 +876,15 @@ done:
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_gatt_discover_characteristic
|
||||
*
|
||||
* Description:
|
||||
* This function implements the SIOCBTDISCOVER ioctl command for the
|
||||
* GATT discover characteristics type.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_gatt_discover_characteristic(FAR struct bt_conn_s *conn,
|
||||
FAR struct bt_gatt_discover_params_s *params)
|
||||
{
|
||||
@ -1014,6 +1032,15 @@ done:
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_gatt_discover_descriptor
|
||||
*
|
||||
* Description:
|
||||
* This function implements the SIOCBTDISCOVER ioctl command for the
|
||||
* GATT discover descriptor type.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bt_gatt_discover_descriptor(FAR struct bt_conn_s *conn,
|
||||
FAR struct bt_gatt_discover_params_s *params)
|
||||
{
|
||||
|
@ -62,7 +62,7 @@
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure encapsulates all globals used by the IOCTL logic */
|
||||
/* These structures encapsulate all globals used by the IOCTL logic. */
|
||||
|
||||
struct btnet_scanstate_s
|
||||
{
|
||||
@ -74,15 +74,28 @@ struct btnet_scanstate_s
|
||||
struct bt_scanresponse_s bs_rsp[CONFIG_BLUETOOTH_MAXSCANRESULT];
|
||||
};
|
||||
|
||||
struct btnet_discoverstate_s
|
||||
{
|
||||
sem_t bd_exclsem; /* Manages exclusive access */
|
||||
bool bd_discovering; /* True: Discovery in progress */
|
||||
uint8_t bd_head; /* Head of circular list (for removal) */
|
||||
uint8_t bd_tail; /* Tail of circular list (for addition) */
|
||||
|
||||
struct bt_discresonse_s bd_rsp[CONFIG_BLUETOOTH_MAXDISCOVER];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* At present only a single Bluetooth device is supported. So we can simply
|
||||
* maintain the scan state as a global.
|
||||
* maintain the scan and the discovery state as globals.
|
||||
* NOTE: This limits to one concurrent scan action and one concurrent
|
||||
* discovery action.
|
||||
*/
|
||||
|
||||
static struct btnet_scanstate_s g_scanstate;
|
||||
static struct btnet_scanstate_s g_scanstate;
|
||||
static struct btnet_discoverstate_s g_discoverstate;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@ -179,9 +192,8 @@ static void btnet_scan_callback(FAR const bt_addr_le_t *addr, int8_t rssi,
|
||||
* Name: btnet_scan_result
|
||||
*
|
||||
* Description:
|
||||
* This is an HCI callback function. HCI provides scan result data via
|
||||
* this callback function. The scan result data will be added to the
|
||||
* cached scan results.
|
||||
* This function implements the SIOCBTSCANGET IOCTL command. It returns
|
||||
* the current, buffered discovered handles.
|
||||
*
|
||||
* Input Parameters:
|
||||
* result - Location to return the scan result data
|
||||
@ -214,8 +226,8 @@ static int btnet_scan_result(FAR struct bt_scanresponse_s *result,
|
||||
|
||||
/* Copy all available results */
|
||||
|
||||
head = g_scanstate.bs_head;
|
||||
tail = g_scanstate.bs_tail;
|
||||
head = g_scanstate.bs_head;
|
||||
tail = g_scanstate.bs_tail;
|
||||
|
||||
for (nrsp = 0; nrsp < maxrsp && head != tail; nrsp++)
|
||||
{
|
||||
@ -241,6 +253,177 @@ static int btnet_scan_result(FAR struct bt_scanresponse_s *result,
|
||||
return nrsp;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_discover_func
|
||||
*
|
||||
* Description:
|
||||
* GATT discovery callback. This function is called when a new handle is
|
||||
* discovered
|
||||
*
|
||||
* Input Parameters:
|
||||
* attr - The discovered attributes
|
||||
* arg - The original discovery parameters
|
||||
*
|
||||
* Returned Value:
|
||||
* BT_GATT_ITER_CONTINUE meaning to continue the iteration.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint8_t bt_discover_func(FAR const struct bt_gatt_attr_s *attr,
|
||||
FAR void *arg)
|
||||
{
|
||||
uint8_t nexttail;
|
||||
uint8_t head;
|
||||
uint8_t tail;
|
||||
int ret;
|
||||
|
||||
wlinfo("Discovered handle %u\n", attr->handle);
|
||||
|
||||
if (!g_discoverstate.bd_discovering)
|
||||
{
|
||||
wlerr("ERROR: Results received while not discovering\n");
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
/* Get exclusive access to the discovered data */
|
||||
|
||||
while ((ret = nxsem_wait(&g_discoverstate.bd_exclsem)) < 0)
|
||||
{
|
||||
DEBUGASSERT(ret == -EINTR || ret == -ECANCELED);
|
||||
if (ret != -EINTR)
|
||||
{
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the discovered data to the cache */
|
||||
|
||||
tail = g_discoverstate.bd_tail;
|
||||
nexttail = tail + 1;
|
||||
|
||||
if (nexttail >= CONFIG_BLUETOOTH_MAXSCANRESULT)
|
||||
{
|
||||
nexttail = 0;
|
||||
}
|
||||
|
||||
/* Is the circular buffer full? */
|
||||
|
||||
head = g_discoverstate.bd_head;
|
||||
if (nexttail == head)
|
||||
{
|
||||
wlerr("ERROR: Too many handles discovered. Data lost.\n");
|
||||
|
||||
if (++head >= CONFIG_BLUETOOTH_MAXSCANRESULT)
|
||||
{
|
||||
head = 0;
|
||||
}
|
||||
|
||||
g_discoverstate.bd_head = head;
|
||||
}
|
||||
|
||||
/* Save the newly discovered handle */
|
||||
|
||||
g_discoverstate.bd_rsp[tail].dr_handle = attr->handle;
|
||||
g_discoverstate.bd_rsp[tail].dr_perm = attr->perm;
|
||||
g_discoverstate.bd_tail = nexttail;
|
||||
|
||||
nxsem_post(&g_discoverstate.bd_exclsem);
|
||||
return BT_GATT_ITER_CONTINUE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bt_discover_destroy
|
||||
*
|
||||
* Description:
|
||||
* GATT destroy callback. This function is called when a discovery
|
||||
* completes.
|
||||
*
|
||||
* Input Parameters:
|
||||
* arg - The original discovery parameters
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void bt_discover_destroy(FAR void *arg)
|
||||
{
|
||||
FAR struct bt_gatt_discover_params *params = arg;
|
||||
|
||||
/* There is nothing that needs to be down here. The parameters were
|
||||
* allocated on the stack and are long gone.
|
||||
*/
|
||||
|
||||
wlinfo("Discover destroy. params %p\n", params);
|
||||
DEBUGASSERT(params != NULL);
|
||||
UNUSED(params);
|
||||
|
||||
DEBUGASSERT(g_discoverstate.bd_discovering);
|
||||
nxsem_destroy(&g_discoverstate.bd_exclsem);
|
||||
g_discoverstate.bd_discovering = false;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: btnet_discover_result
|
||||
*
|
||||
* Description:
|
||||
* This function implements the SIOCBTDISCGET IOCTL command. It returns
|
||||
* the current, buffered discovered handles.
|
||||
*
|
||||
* Input Parameters:
|
||||
* result - Location to return the discovery result data
|
||||
* maxrsp - The maximum number of responses that can be returned.
|
||||
*
|
||||
* Returned Value:
|
||||
* On success, the actual number of discovery results obtain is returned. A
|
||||
* negated errno value is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int btnet_discover_result(FAR struct bt_discresonse_s *result,
|
||||
uint8_t maxrsp)
|
||||
{
|
||||
uint8_t head;
|
||||
uint8_t tail;
|
||||
uint8_t nrsp;
|
||||
int ret;
|
||||
|
||||
wlinfo("Discovering? %s\n", g_discoverstate.bd_discovering ? "YES" : "NO");
|
||||
|
||||
/* Get exclusive access to the discovery data */
|
||||
|
||||
ret = nxsem_wait(&g_discoverstate.bd_exclsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
DEBUGASSERT(ret == -EINTR || ret == -ECANCELED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Copy all available results */
|
||||
|
||||
head = g_discoverstate.bd_head;
|
||||
tail = g_discoverstate.bd_tail;
|
||||
|
||||
for (nrsp = 0; nrsp < maxrsp && head != tail; nrsp++)
|
||||
{
|
||||
/* Copy data from the head index into the user buffer */
|
||||
|
||||
result[nrsp].dr_handle = g_discoverstate.bd_rsp[head].dr_handle;
|
||||
result[nrsp].dr_perm = g_discoverstate.bd_rsp[head].dr_perm;
|
||||
|
||||
/* Increment the head index */
|
||||
|
||||
if (++head >= CONFIG_BLUETOOTH_MAXDISCOVER)
|
||||
{
|
||||
head = 0;
|
||||
}
|
||||
}
|
||||
|
||||
g_discoverstate.bd_head = head;
|
||||
nxsem_post(&g_discoverstate.bd_exclsem);
|
||||
return nrsp;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -363,6 +546,7 @@ int btnet_ioctl(FAR struct net_driver_s *netdev, int cmd, unsigned long arg)
|
||||
|
||||
if (g_scanstate.bs_scanning)
|
||||
{
|
||||
wlwarn("WARNING: Already scanning\n");
|
||||
ret = -EBUSY;
|
||||
}
|
||||
else
|
||||
@ -445,6 +629,103 @@ int btnet_ioctl(FAR struct net_driver_s *netdev, int cmd, unsigned long arg)
|
||||
}
|
||||
break;
|
||||
|
||||
/* SIOCBTDISCOVER: Starts GATT discovery */
|
||||
|
||||
case SIOCBTDISCOVER:
|
||||
{
|
||||
FAR struct bt_conn_s *conn;
|
||||
|
||||
/* Check if discovery is already in progress */
|
||||
|
||||
if (g_discoverstate.bd_discovering)
|
||||
{
|
||||
wlwarn("WARNING: Discovery is already in progress\n");
|
||||
ret = -EBUSY;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the connection associated with the provided LE address */
|
||||
|
||||
conn = bt_conn_lookup_addr_le(&btreq->btr_dpeer);
|
||||
if (conn == NULL)
|
||||
{
|
||||
wlwarn("WARNING: Peer not connected\n");
|
||||
ret = -ENOTCONN;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct bt_gatt_discover_params_s params;
|
||||
struct bt_uuid_s uuid;
|
||||
|
||||
|
||||
/* Set up the query */
|
||||
|
||||
nxsem_init(&g_discoverstate.bd_exclsem, 0, 1);
|
||||
g_discoverstate.bd_discovering = true;
|
||||
g_discoverstate.bd_head = 0;
|
||||
g_discoverstate.bd_tail = 0;
|
||||
|
||||
/* Start the query */
|
||||
|
||||
uuid.type = BT_UUID_16;
|
||||
uuid.u.u16 = btreq->btr_duuid16;
|
||||
|
||||
params.uuid = &uuid;
|
||||
params.func = bt_discover_func;
|
||||
params.destroy = bt_discover_destroy;
|
||||
params.start_handle = btreq->btr_dstart;
|
||||
params.end_handle = btreq->btr_dend;
|
||||
|
||||
switch (btreq->btr_dtype)
|
||||
{
|
||||
case GATT_DISCOVER:
|
||||
ret = bt_gatt_discover(conn, ¶ms);
|
||||
break;
|
||||
|
||||
case GATT_DISCOVER_DESC:
|
||||
ret = bt_gatt_discover_descriptor(conn, ¶ms);
|
||||
break;
|
||||
|
||||
case GATT_DISCOVER_CHAR:
|
||||
ret = bt_gatt_discover_characteristic(conn, ¶ms);
|
||||
break;
|
||||
|
||||
default:
|
||||
wlerr("ERROR: Unrecognized GATT discover type: %u\n",
|
||||
btreq->btr_dtype);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
wlerr("ERROR: Failed to start discovery: %d\n", ret);
|
||||
nxsem_destroy(&g_discoverstate.bd_exclsem);
|
||||
g_discoverstate.bd_discovering = false;
|
||||
}
|
||||
|
||||
bt_conn_release(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* SIOCBTDISCGET: Return discovered results buffered since the call time
|
||||
* that the SIOCBTDISCGET command was invoked.
|
||||
*/
|
||||
|
||||
case SIOCBTDISCGET:
|
||||
{
|
||||
ret = btnet_discover_result(btreq->btr_grsp, btreq->btr_gnrsp);
|
||||
wlinfo("Get discovery results: %d\n", ret);
|
||||
|
||||
if (ret >= 0)
|
||||
{
|
||||
btreq->btr_nrsp = ret;
|
||||
ret = OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
wlwarn("WARNING: Unrecognized IOCTL command: %02x\n", cmd);
|
||||
ret = -ENOTTY;
|
||||
|
Loading…
Reference in New Issue
Block a user