2676 lines
70 KiB
C
2676 lines
70 KiB
C
/*
|
|
* Copyright (C) 2013 Intel Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <hardware/bluetooth.h>
|
|
|
|
#include "../hal-utils.h"
|
|
#include "if-main.h"
|
|
|
|
const btgatt_interface_t *if_gatt = NULL;
|
|
|
|
/*
|
|
* In version 19 some callback were changed.
|
|
* btgatt_char_id_t -> btgatt_gatt_id_t
|
|
* bt_uuid_t -> btgatt_gatt_id_t
|
|
*/
|
|
#define str2btgatt_descr_id_t str2btgatt_gatt_id_t
|
|
#define btgatt_descr_id_t2str btgatt_gatt_id_t2str
|
|
#define btgatt_descr_id_t btgatt_gatt_id_t
|
|
|
|
#define MAX_CHAR_ID_STR_LEN (MAX_UUID_STR_LEN + 3 + 11)
|
|
#define MAX_SRVC_ID_STR_LEN (MAX_UUID_STR_LEN + 3 + 11 + 1 + 11)
|
|
/* How man characters print from binary objects (arbitrary) */
|
|
#define MAX_HEX_VAL_STR_LEN 100
|
|
#define MAX_NOTIFY_PARAMS_STR_LEN (MAX_SRVC_ID_STR_LEN + MAX_CHAR_ID_STR_LEN \
|
|
+ MAX_ADDR_STR_LEN + MAX_HEX_VAL_STR_LEN + 60)
|
|
#define MAX_READ_PARAMS_STR_LEN (MAX_SRVC_ID_STR_LEN + MAX_CHAR_ID_STR_LEN \
|
|
+ MAX_UUID_STR_LEN + MAX_HEX_VAL_STR_LEN + 80)
|
|
|
|
/* Hex arguments must have "0x" or "0X" prefix */
|
|
#define VERIFY_INT_ARG(n, v, err) \
|
|
do { \
|
|
if (n < argc) \
|
|
v = strtol(argv[n], NULL, 0); \
|
|
else { \
|
|
haltest_error(err); \
|
|
return;\
|
|
} \
|
|
} while (0)
|
|
|
|
#define VERIFY_HEX_ARG(n, v, err) \
|
|
do { \
|
|
if (n < argc) \
|
|
v = strtol(argv[n], NULL, 16); \
|
|
else { \
|
|
haltest_error(err); \
|
|
return;\
|
|
} \
|
|
} while (0)
|
|
|
|
/* Helper macros to verify arguments of methods */
|
|
#define VERIFY_CLIENT_IF(n, v) VERIFY_INT_ARG(n, v, "No client_if specified\n")
|
|
#define VERIFY_SERVER_IF(n, v) VERIFY_INT_ARG(n, v, "No server_if specified\n")
|
|
#define VERIFY_CONN_ID(n, v) VERIFY_INT_ARG(n, v, "No conn_if specified\n")
|
|
#define VERIFY_TRANS_ID(n, v) VERIFY_INT_ARG(n, v, "No trans_id specified\n")
|
|
#define VERIFY_STATUS(n, v) VERIFY_INT_ARG(n, v, "No status specified\n")
|
|
#define VERIFY_OFFSET(n, v) VERIFY_INT_ARG(n, v, "No offset specified\n")
|
|
#define VERIFY_TEST_ARG(n, v) VERIFY_INT_ARG(n, v, "No test arg specified\n")
|
|
#define VERIFY_ACTION(n, v) VERIFY_INT_ARG(n, v, "No action specified\n")
|
|
#define VERIFY_FILT_TYPE(n, v) VERIFY_INT_ARG(n, v, "No filter specified\n")
|
|
#define VERIFY_FILT_INDEX(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No filter index specified\n")
|
|
#define VERIFY_FEAT_SELN(n, v) VERIFY_INT_ARG(n, v, "No feat seln specified\n")
|
|
#define VERIFY_LIST_LOGIC_TYPE(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No list logic type specified\n")
|
|
#define VERIFY_FILT_LOGIC_TYPE(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No filt logic type specified\n")
|
|
#define VERIFY_RSSI_HI_THR(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No rssi hi threshold specified\n")
|
|
#define VERIFY_RSSI_LOW_THR(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No low threshold specified\n")
|
|
#define VERIFY_DELY_MODE(n, v) VERIFY_INT_ARG(n, v, "No delay mode specified\n")
|
|
#define VERIFY_FND_TIME(n, v) VERIFY_INT_ARG(n, v, "No found time specified\n")
|
|
#define VERIFY_LOST_TIME(n, v) VERIFY_INT_ARG(n, v, "No lost time specified\n")
|
|
#define VERIFY_FND_TIME_CNT(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No found timer counter specified\n")
|
|
#define VERIFY_COMP_ID(n, v) VERIFY_INT_ARG(n, v, "No company id specified\n")
|
|
#define VERIFY_COMP_ID_MASK(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No comp. id mask specified\n")
|
|
#define VERIFY_DATA_LEN(n, v) VERIFY_INT_ARG(n, v, "No data len specified\n")
|
|
#define VERIFY_MASK_LEN(n, v) VERIFY_INT_ARG(n, v, "No mask len specified\n")
|
|
#define VERIFY_MIN_INTERVAL(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No min interval specified\n")
|
|
#define VERIFY_MAX_INTERVAL(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No max interval specified\n")
|
|
#define VERIFY_APPEARANCE(n, v) VERIFY_INT_ARG(n, v, "No apperance specified\n")
|
|
#define VERIFY_MANUFACTURER_LEN(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No manufacturer len specified\n")
|
|
#define VERIFY_SERVICE_DATA_LEN(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No service data len specified\n")
|
|
#define VERIFY_SERVICE_UUID_LEN(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No service uuid len specified\n")
|
|
#define VERIFY_MTU(n, v) VERIFY_INT_ARG(n, v, "No mtu specified\n")
|
|
#define VERIFY_LATENCY(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No latency specified\n")
|
|
#define VERIFY_TIMEOUT(n, v) VERIFY_INT_ARG(n, v, "No timeout specified\n")
|
|
#define VERIFY_SCAN_INTERVAL(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No scan interval specified\n")
|
|
#define VERIFY_SCAN_WINDOW(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No scan window specified\n")
|
|
#define VERIFY_ADV_TYPE(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No advertising type specified\n")
|
|
#define VERIFY_CHNL_MAP(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No channel map specified\n")
|
|
#define VERIFY_TX_POWER(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No tx power specified\n")
|
|
#define VERIFY_TIMEOUT_S(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No timeout in sec specified\n")
|
|
#define VERIFY_BATCH_SCAN_FULL_MAX(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No batch scan full max specified\n")
|
|
#define VERIFY_BATCH_SCAN_TRUNC_MAX(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No batch scan trunc max specified\n")
|
|
#define VERIFY_BATCH_SCAN_NOTIFY_THR(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No batch scan notify threshold specified\n")
|
|
#define VERIFY_SCAN_MODE(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No scan mode specified\n")
|
|
#define VERIFY_ADDR_TYPE(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No address type specified\n")
|
|
#define VERIFY_DISCARD_RULE(n, v) VERIFY_INT_ARG(n, v, \
|
|
"No discard rule specified\n")
|
|
#define VERIFY_HANDLE(n, v) VERIFY_HEX_ARG(n, v, "No "#v" specified\n")
|
|
#define VERIFY_SERVICE_HANDLE(n, v) VERIFY_HANDLE(n, v)
|
|
|
|
#define VERIFY_UUID(n, v) \
|
|
do { \
|
|
if (n < argc) \
|
|
gatt_str2bt_uuid_t(argv[n], -1, v); \
|
|
else { \
|
|
haltest_error("No uuid specified\n"); \
|
|
return;\
|
|
} \
|
|
} while (0)
|
|
|
|
#define VERIFY_SRVC_ID(n, v) \
|
|
do { \
|
|
if (n < argc) \
|
|
str2btgatt_srvc_id_t(argv[n], v); \
|
|
else { \
|
|
haltest_error("No srvc_id specified\n"); \
|
|
return;\
|
|
} \
|
|
} while (0)
|
|
|
|
#define VERIFY_CHAR_ID(n, v) \
|
|
do { \
|
|
if (n < argc) \
|
|
str2btgatt_gatt_id_t(argv[n], v); \
|
|
else { \
|
|
haltest_error("No char_id specified\n"); \
|
|
return;\
|
|
} \
|
|
} while (0)
|
|
|
|
#define VERIFY_DESCR_ID(n, v) \
|
|
do { \
|
|
if (n < argc) \
|
|
str2btgatt_descr_id_t(argv[n], v); \
|
|
else { \
|
|
haltest_error("No descr_id specified\n"); \
|
|
return;\
|
|
} \
|
|
} while (0)
|
|
|
|
#define GET_VERIFY_HEX_STRING(i, v, l) \
|
|
do { \
|
|
int ll;\
|
|
const char *n = argv[i]; \
|
|
if (argc <= i) { \
|
|
haltest_error("No value specified\n"); \
|
|
return; \
|
|
} \
|
|
if (n[0] != '0' || (n[1] != 'X' && n[1] != 'x')) { \
|
|
haltest_error("Value must be hex string\n"); \
|
|
return; \
|
|
} \
|
|
ll = fill_buffer(n + 2, (uint8_t *) v, sizeof(v)); \
|
|
if (ll < 0) { \
|
|
haltest_error("Value must be byte hex string\n"); \
|
|
return; \
|
|
} \
|
|
l = ll; \
|
|
} while (0)
|
|
|
|
/* Gatt uses little endian uuid */
|
|
static const char GATT_BASE_UUID[] = {
|
|
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
|
|
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
/*
|
|
* converts gatt uuid to string
|
|
* buf should be at least 39 bytes
|
|
*
|
|
* This function formats 16, 32 and 128 bits uuid
|
|
*
|
|
* returns string representation of uuid
|
|
*/
|
|
static char *gatt_uuid_t2str(const bt_uuid_t *uuid, char *buf)
|
|
{
|
|
int shift = 0;
|
|
int i = 16;
|
|
int limit = 0;
|
|
int j = 0;
|
|
|
|
/* for bluetooth uuid only 32 bits */
|
|
if (0 == memcmp(&uuid->uu, &GATT_BASE_UUID,
|
|
sizeof(bt_uuid_t) - 4)) {
|
|
limit = 12;
|
|
/* make it 16 bits */
|
|
if (uuid->uu[15] == 0 && uuid->uu[14] == 0)
|
|
i = 14;
|
|
}
|
|
|
|
while (i-- > limit) {
|
|
if (i == 11 || i == 9 || i == 7 || i == 5) {
|
|
buf[j * 2 + shift] = '-';
|
|
shift++;
|
|
}
|
|
|
|
sprintf(buf + j * 2 + shift, "%02x", uuid->uu[i]);
|
|
++j;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
/*
|
|
* Tries to convert hex string of given size into out buffer.
|
|
* Output buffer is little endian.
|
|
*/
|
|
static void scan_field(const char *str, int len, uint8_t *out, int out_size)
|
|
{
|
|
int i;
|
|
|
|
memset(out, 0, out_size);
|
|
if (out_size * 2 > len + 1)
|
|
out_size = (len + 1) / 2;
|
|
|
|
for (i = 0; i < out_size && len > 0; ++i) {
|
|
len -= 2;
|
|
if (len >= 0)
|
|
sscanf(str + len, "%02hhx", &out[i]);
|
|
else
|
|
sscanf(str, "%1hhx", &out[i]);
|
|
}
|
|
}
|
|
|
|
/* Like strchr but with upper limit instead of 0 terminated string */
|
|
static const char *strchrlimit(const char *p, const char *e, int c)
|
|
{
|
|
while (p < e && *p != (char) c)
|
|
++p;
|
|
|
|
return p < e ? p : NULL;
|
|
}
|
|
|
|
/*
|
|
* converts string to uuid
|
|
* it accepts uuid in following forms:
|
|
* 123
|
|
* 0000123
|
|
* 0000123-0014-1234-0000-000056789abc
|
|
* 0000123001412340000000056789abc
|
|
* 123-14-1234-0-56789abc
|
|
*/
|
|
static void gatt_str2bt_uuid_t(const char *str, int len, bt_uuid_t *uuid)
|
|
{
|
|
int dash_cnt = 0;
|
|
int dashes[6] = {-1}; /* indexes of '-' or \0 */
|
|
static uint8_t filed_offset[] = { 16, 12, 10, 8, 6, 0 };
|
|
const char *p = str;
|
|
const char *e;
|
|
int i;
|
|
|
|
e = str + ((len >= 0) ? len : (int) strlen(str));
|
|
|
|
while (p != NULL && dash_cnt < 5) {
|
|
const char *f = strchrlimit(p, e, '-');
|
|
|
|
if (f != NULL)
|
|
dashes[++dash_cnt] = f++ - str;
|
|
p = f;
|
|
}
|
|
|
|
/* get index of \0 to dashes table */
|
|
if (dash_cnt < 5)
|
|
dashes[++dash_cnt] = e - str;
|
|
|
|
memcpy(uuid, GATT_BASE_UUID, sizeof(bt_uuid_t));
|
|
|
|
/* whole uuid in one string without dashes */
|
|
if (dash_cnt == 1 && dashes[1] > 8) {
|
|
if (dashes[1] > 32)
|
|
dashes[1] = 32;
|
|
scan_field(str, dashes[1],
|
|
&uuid->uu[16 - (dashes[1] + 1) / 2],
|
|
(dashes[1] + 1) / 2);
|
|
} else {
|
|
for (i = 0; i < dash_cnt; ++i) {
|
|
scan_field(str + dashes[i] + 1,
|
|
dashes[i + 1] - dashes[i] - 1,
|
|
&uuid->uu[filed_offset[i + 1]],
|
|
filed_offset[i] - filed_offset[i + 1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* char_id formating function */
|
|
static char *btgatt_gatt_id_t2str(const btgatt_gatt_id_t *char_id, char *buf)
|
|
{
|
|
char uuid_buf[MAX_UUID_STR_LEN];
|
|
|
|
sprintf(buf, "{%s,%d}", gatt_uuid_t2str(&char_id->uuid, uuid_buf),
|
|
char_id->inst_id);
|
|
return buf;
|
|
}
|
|
|
|
/* Parse btgatt_gatt_id_t */
|
|
static void str2btgatt_gatt_id_t(const char *buf, btgatt_gatt_id_t *char_id)
|
|
{
|
|
const char *e;
|
|
|
|
memcpy(&char_id->uuid, &GATT_BASE_UUID, sizeof(bt_uuid_t));
|
|
char_id->inst_id = 0;
|
|
|
|
if (*buf == '{')
|
|
buf++;
|
|
e = strpbrk(buf, " ,}");
|
|
if (e == NULL)
|
|
e = buf + strlen(buf);
|
|
|
|
gatt_str2bt_uuid_t(buf, e - buf, &char_id->uuid);
|
|
if (*e == ',') {
|
|
buf = e + 1;
|
|
e = strpbrk(buf, " ,}");
|
|
if (e == NULL)
|
|
e = buf + strlen(buf);
|
|
if (buf < e)
|
|
char_id->inst_id = atoi(buf);
|
|
}
|
|
}
|
|
|
|
/* service_id formating function */
|
|
static char *btgatt_srvc_id_t2str(const btgatt_srvc_id_t *srvc_id, char *buf)
|
|
{
|
|
char uuid_buf[MAX_UUID_STR_LEN];
|
|
|
|
sprintf(buf, "{%s,%d,%d}", gatt_uuid_t2str(&srvc_id->id.uuid, uuid_buf),
|
|
srvc_id->id.inst_id, srvc_id->is_primary);
|
|
return buf;
|
|
}
|
|
|
|
/* Parse btgatt_srvc_id_t */
|
|
static void str2btgatt_srvc_id_t(const char *buf, btgatt_srvc_id_t *srvc_id)
|
|
{
|
|
const char *e;
|
|
|
|
memcpy(&srvc_id->id.uuid, &GATT_BASE_UUID, sizeof(bt_uuid_t));
|
|
srvc_id->id.inst_id = 0;
|
|
srvc_id->is_primary = 1;
|
|
|
|
if (*buf == '{')
|
|
buf++;
|
|
e = strpbrk(buf, " ,}");
|
|
if (e == NULL)
|
|
e = buf + strlen(buf);
|
|
|
|
gatt_str2bt_uuid_t(buf, e - buf, &srvc_id->id.uuid);
|
|
if (*e == ',') {
|
|
buf = e + 1;
|
|
e = strpbrk(buf, " ,}");
|
|
if (e == NULL)
|
|
e = buf + strlen(buf);
|
|
if (buf < e)
|
|
srvc_id->id.inst_id = atoi(buf);
|
|
}
|
|
|
|
if (*e == ',') {
|
|
buf = e + 1;
|
|
e = strpbrk(buf, " ,}");
|
|
if (e == NULL)
|
|
e = buf + strlen(buf);
|
|
if (buf < e)
|
|
srvc_id->is_primary = atoi(buf);
|
|
}
|
|
}
|
|
|
|
/* Converts array of uint8_t to string representation */
|
|
static char *array2str(const uint8_t *v, int size, char *buf, int out_size)
|
|
{
|
|
int limit = size;
|
|
int i;
|
|
|
|
if (out_size > 0) {
|
|
*buf = '\0';
|
|
if (size >= 2 * out_size)
|
|
limit = (out_size - 2) / 2;
|
|
|
|
for (i = 0; i < limit; ++i)
|
|
sprintf(buf + 2 * i, "%02x", v[i]);
|
|
|
|
/* output buffer not enough to hold whole field fill with ...*/
|
|
if (limit < size)
|
|
sprintf(buf + 2 * i, "...");
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
/* Converts btgatt_notify_params_t to string */
|
|
static char *btgatt_notify_params_t2str(const btgatt_notify_params_t *data,
|
|
char *buf)
|
|
{
|
|
char addr[MAX_ADDR_STR_LEN];
|
|
char srvc_id[MAX_SRVC_ID_STR_LEN];
|
|
char char_id[MAX_CHAR_ID_STR_LEN];
|
|
char value[MAX_HEX_VAL_STR_LEN];
|
|
|
|
sprintf(buf, "{bda=%s, srvc_id=%s, char_id=%s, val=%s, is_notify=%u}",
|
|
bt_bdaddr_t2str(&data->bda, addr),
|
|
btgatt_srvc_id_t2str(&data->srvc_id, srvc_id),
|
|
btgatt_gatt_id_t2str(&data->char_id, char_id),
|
|
array2str(data->value, data->len, value, sizeof(value)),
|
|
data->is_notify);
|
|
return buf;
|
|
}
|
|
|
|
static char *btgatt_unformatted_value_t2str(const btgatt_unformatted_value_t *v,
|
|
char *buf, int size)
|
|
{
|
|
return array2str(v->value, v->len, buf, size);
|
|
}
|
|
|
|
static char *btgatt_read_params_t2str(const btgatt_read_params_t *data,
|
|
char *buf)
|
|
{
|
|
char srvc_id[MAX_SRVC_ID_STR_LEN];
|
|
char char_id[MAX_CHAR_ID_STR_LEN];
|
|
char descr_id[MAX_UUID_STR_LEN];
|
|
char value[MAX_HEX_VAL_STR_LEN];
|
|
|
|
sprintf(buf, "{srvc_id=%s, char_id=%s, descr_id=%s, val=%s value_type=%d, status=%d}",
|
|
btgatt_srvc_id_t2str(&data->srvc_id, srvc_id),
|
|
btgatt_gatt_id_t2str(&data->char_id, char_id),
|
|
btgatt_descr_id_t2str(&data->descr_id, descr_id),
|
|
btgatt_unformatted_value_t2str(&data->value, value, 100),
|
|
data->value_type, data->status);
|
|
return buf;
|
|
}
|
|
|
|
/* BT-GATT Client callbacks. */
|
|
|
|
/* Cache client_if and conn_id for tab completion */
|
|
static char client_if_str[20];
|
|
static char conn_id_str[20];
|
|
/* Cache address for tab completion */
|
|
static char last_addr[MAX_ADDR_STR_LEN];
|
|
|
|
/* Callback invoked in response to register_client */
|
|
static void gattc_register_client_cb(int status, int client_if,
|
|
bt_uuid_t *app_uuid)
|
|
{
|
|
char buf[MAX_UUID_STR_LEN];
|
|
|
|
snprintf(client_if_str, sizeof(client_if_str), "%d", client_if);
|
|
|
|
haltest_info("%s: status=%d client_if=%d app_uuid=%s\n", __func__,
|
|
status, client_if,
|
|
gatt_uuid_t2str(app_uuid, buf));
|
|
}
|
|
|
|
/* Callback for scan results */
|
|
static void gattc_scan_result_cb(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data)
|
|
{
|
|
char buf[MAX_ADDR_STR_LEN];
|
|
|
|
haltest_info("%s: bda=%s rssi=%d adv_data=%p\n", __func__,
|
|
bt_bdaddr_t2str(bda, buf), rssi, adv_data);
|
|
}
|
|
|
|
/* GATT open callback invoked in response to open */
|
|
static void gattc_connect_cb(int conn_id, int status, int client_if,
|
|
bt_bdaddr_t *bda)
|
|
{
|
|
haltest_info("%s: conn_id=%d status=%d, client_if=%d bda=%s\n",
|
|
__func__, conn_id, status, client_if,
|
|
bt_bdaddr_t2str(bda, last_addr));
|
|
}
|
|
|
|
/* Callback invoked in response to close */
|
|
static void gattc_disconnect_cb(int conn_id, int status, int client_if,
|
|
bt_bdaddr_t *bda)
|
|
{
|
|
char buf[MAX_ADDR_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d status=%d, client_if=%d bda=%s\n",
|
|
__func__, conn_id, status, client_if,
|
|
bt_bdaddr_t2str(bda, buf));
|
|
}
|
|
|
|
/*
|
|
* Invoked in response to search_service when the GATT service search
|
|
* has been completed.
|
|
*/
|
|
static void gattc_search_complete_cb(int conn_id, int status)
|
|
{
|
|
haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
|
|
}
|
|
|
|
/* Reports GATT services on a remote device */
|
|
static void gattc_search_result_cb(int conn_id, btgatt_srvc_id_t *srvc_id)
|
|
{
|
|
char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d srvc_id=%s\n", __func__, conn_id,
|
|
btgatt_srvc_id_t2str(srvc_id, srvc_id_buf));
|
|
}
|
|
|
|
/* GATT characteristic enumeration result callback */
|
|
static void gattc_get_characteristic_cb(int conn_id, int status,
|
|
btgatt_srvc_id_t *srvc_id,
|
|
btgatt_gatt_id_t *char_id,
|
|
int char_prop)
|
|
{
|
|
char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
|
|
char char_id_buf[MAX_CHAR_ID_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d status=%d srvc_id=%s char_id=%s, char_prop=0x%x\n",
|
|
__func__, conn_id, status,
|
|
btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
|
|
btgatt_gatt_id_t2str(char_id, char_id_buf), char_prop);
|
|
|
|
/* enumerate next characteristic */
|
|
if (status == 0)
|
|
EXEC(if_gatt->client->get_characteristic, conn_id, srvc_id,
|
|
char_id);
|
|
}
|
|
|
|
/* GATT descriptor enumeration result callback */
|
|
static void gattc_get_descriptor_cb(int conn_id, int status,
|
|
btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
|
|
btgatt_descr_id_t *descr_id)
|
|
{
|
|
char buf[MAX_UUID_STR_LEN];
|
|
char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
|
|
char char_id_buf[MAX_CHAR_ID_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d status=%d srvc_id=%s char_id=%s, descr_id=%s\n",
|
|
__func__, conn_id, status,
|
|
btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
|
|
btgatt_gatt_id_t2str(char_id, char_id_buf),
|
|
btgatt_descr_id_t2str(descr_id, buf));
|
|
|
|
if (status == 0)
|
|
EXEC(if_gatt->client->get_descriptor, conn_id, srvc_id, char_id,
|
|
descr_id);
|
|
}
|
|
|
|
/* GATT included service enumeration result callback */
|
|
static void gattc_get_included_service_cb(int conn_id, int status,
|
|
btgatt_srvc_id_t *srvc_id,
|
|
btgatt_srvc_id_t *incl_srvc_id)
|
|
{
|
|
char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
|
|
char incl_srvc_id_buf[MAX_SRVC_ID_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d status=%d srvc_id=%s incl_srvc_id=%s)\n",
|
|
__func__, conn_id, status,
|
|
btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
|
|
btgatt_srvc_id_t2str(incl_srvc_id, incl_srvc_id_buf));
|
|
|
|
if (status == 0)
|
|
EXEC(if_gatt->client->get_included_service, conn_id, srvc_id,
|
|
incl_srvc_id);
|
|
}
|
|
|
|
/* Callback invoked in response to [de]register_for_notification */
|
|
static void gattc_register_for_notification_cb(int conn_id, int registered,
|
|
int status,
|
|
btgatt_srvc_id_t *srvc_id,
|
|
btgatt_gatt_id_t *char_id)
|
|
{
|
|
char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
|
|
char char_id_buf[MAX_CHAR_ID_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d registered=%d status=%d srvc_id=%s char_id=%s\n",
|
|
__func__, conn_id, registered, status,
|
|
btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
|
|
btgatt_gatt_id_t2str(char_id, char_id_buf));
|
|
}
|
|
|
|
/*
|
|
* Remote device notification callback, invoked when a remote device sends
|
|
* a notification or indication that a client has registered for.
|
|
*/
|
|
static void gattc_notify_cb(int conn_id, btgatt_notify_params_t *p_data)
|
|
{
|
|
char buf[MAX_NOTIFY_PARAMS_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d data=%s\n", __func__, conn_id,
|
|
btgatt_notify_params_t2str(p_data, buf));
|
|
}
|
|
|
|
/* Reports result of a GATT read operation */
|
|
static void gattc_read_characteristic_cb(int conn_id, int status,
|
|
btgatt_read_params_t *p_data)
|
|
{
|
|
char buf[MAX_READ_PARAMS_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d status=%d data=%s\n", __func__, conn_id,
|
|
status, btgatt_read_params_t2str(p_data, buf));
|
|
}
|
|
|
|
/* GATT write characteristic operation callback */
|
|
static void gattc_write_characteristic_cb(int conn_id, int status,
|
|
btgatt_write_params_t *p_data)
|
|
{
|
|
haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
|
|
}
|
|
|
|
/* GATT execute prepared write callback */
|
|
static void gattc_execute_write_cb(int conn_id, int status)
|
|
{
|
|
haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
|
|
}
|
|
|
|
/* Callback invoked in response to read_descriptor */
|
|
static void gattc_read_descriptor_cb(int conn_id, int status,
|
|
btgatt_read_params_t *p_data)
|
|
{
|
|
char buf[MAX_READ_PARAMS_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d status=%d data=%s\n", __func__, conn_id,
|
|
status, btgatt_read_params_t2str(p_data, buf));
|
|
}
|
|
|
|
/* Callback invoked in response to write_descriptor */
|
|
static void gattc_write_descriptor_cb(int conn_id, int status,
|
|
btgatt_write_params_t *p_data)
|
|
{
|
|
haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
|
|
}
|
|
|
|
/* Callback triggered in response to read_remote_rssi */
|
|
static void gattc_read_remote_rssi_cb(int client_if, bt_bdaddr_t *bda, int rssi,
|
|
int status)
|
|
{
|
|
char buf[MAX_ADDR_STR_LEN];
|
|
|
|
haltest_info("%s: client_if=%d bda=%s rssi=%d satus=%d\n", __func__,
|
|
client_if, bt_bdaddr_t2str(bda, buf), rssi, status);
|
|
}
|
|
|
|
/* Callback invoked in response to listen */
|
|
static void gattc_listen_cb(int status, int client_if)
|
|
{
|
|
haltest_info("%s: client_if=%d status=%d\n", __func__, client_if,
|
|
status);
|
|
}
|
|
|
|
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
|
/* Callback invoked when the MTU for a given connection changes */
|
|
static void gattc_configure_mtu_cb(int conn_id, int status, int mtu)
|
|
{
|
|
haltest_info("%s: conn_id=%d, status=%d, mtu=%d\n", __func__, conn_id,
|
|
status, mtu);
|
|
}
|
|
|
|
/* Callback invoked when a scan filter configuration command has completed */
|
|
static void gattc_scan_filter_cfg_cb(int action, int client_if, int status,
|
|
int filt_type, int avbl_space)
|
|
{
|
|
haltest_info("%s: action=%d, client_if=%d, status=%d, filt_type=%d"
|
|
", avbl_space=%d", __func__, action, client_if, status,
|
|
filt_type, avbl_space);
|
|
}
|
|
|
|
/* Callback invoked when scan param has been added, cleared, or deleted */
|
|
static void gattc_scan_filter_param_cb(int action, int client_if, int status,
|
|
int avbl_space)
|
|
{
|
|
haltest_info("%s: action=%d, client_if=%d, status=%d, avbl_space=%d",
|
|
__func__, action, client_if, status, avbl_space);
|
|
}
|
|
|
|
/* Callback invoked when a scan filter configuration command has completed */
|
|
static void gattc_scan_filter_status_cb(int enable, int client_if, int status)
|
|
{
|
|
haltest_info("%s: enable=%d, client_if=%d, status=%d", __func__,
|
|
enable, client_if, status);
|
|
}
|
|
|
|
/* Callback invoked when multi-adv enable operation has completed */
|
|
static void gattc_multi_adv_enable_cb(int client_if, int status)
|
|
{
|
|
haltest_info("%s: client_if=%d, status=%d", __func__, client_if,
|
|
status);
|
|
}
|
|
|
|
/* Callback invoked when multi-adv param update operation has completed */
|
|
static void gattc_multi_adv_update_cb(int client_if, int status)
|
|
{
|
|
haltest_info("%s: client_if=%d, status=%d", __func__, client_if,
|
|
status);
|
|
}
|
|
|
|
/* Callback invoked when multi-adv instance data set operation has completed */
|
|
static void gattc_multi_adv_data_cb(int client_if, int status)
|
|
{
|
|
haltest_info("%s: client_if=%d, status=%d", __func__, client_if,
|
|
status);
|
|
}
|
|
|
|
/* Callback invoked when multi-adv disable operation has completed */
|
|
static void gattc_multi_adv_disable_cb(int client_if, int status)
|
|
{
|
|
haltest_info("%s: client_if=%d, status=%d", __func__, client_if,
|
|
status);
|
|
}
|
|
|
|
/*
|
|
* Callback notifying an application that a remote device connection is
|
|
* currently congested and cannot receive any more data. An application should
|
|
* avoid sending more data until a further callback is received indicating the
|
|
* congestion status has been cleared.
|
|
*/
|
|
static void gattc_congestion_cb(int conn_id, bool congested)
|
|
{
|
|
haltest_info("%s: conn_id=%d, congested=%d", __func__, conn_id,
|
|
congested);
|
|
}
|
|
|
|
/* Callback invoked when batchscan storage config operation has completed */
|
|
static void gattc_batchscan_cfg_storage_cb(int client_if, int status)
|
|
{
|
|
haltest_info("%s: client_if=%d, status=%d", __func__, client_if,
|
|
status);
|
|
}
|
|
|
|
/* Callback invoked when batchscan enable / disable operation has completed */
|
|
static void gattc_batchscan_enable_disable_cb(int action, int client_if,
|
|
int status)
|
|
{
|
|
haltest_info("%s: action=%d, client_if=%d, status=%d", __func__, action,
|
|
client_if, status);
|
|
}
|
|
|
|
/* Callback invoked when batchscan reports are obtained */
|
|
static void gattc_batchscan_reports_cb(int client_if, int status,
|
|
int report_format, int num_records,
|
|
int data_len, uint8_t* rep_data)
|
|
{
|
|
/* BTGATT_MAX_ATTR_LEN = 600 */
|
|
char valbuf[600];
|
|
|
|
haltest_info("%s: client_if=%d, status=%d, report_format=%d"
|
|
", num_records=%d, data_len=%d, rep_data=%s", __func__,
|
|
client_if, status, report_format, num_records, data_len,
|
|
array2str(rep_data, data_len, valbuf, sizeof(valbuf)));
|
|
}
|
|
|
|
/* Callback invoked when batchscan storage threshold limit is crossed */
|
|
static void gattc_batchscan_threshold_cb(int client_if)
|
|
{
|
|
haltest_info("%s: client_if=%d", __func__, client_if);
|
|
}
|
|
|
|
/* Track ADV VSE callback invoked when tracked device is found or lost */
|
|
static void gattc_track_adv_event_cb(int client_if, int filt_index,
|
|
int addr_type, bt_bdaddr_t* bda,
|
|
int adv_state)
|
|
{
|
|
char buf[MAX_ADDR_STR_LEN];
|
|
|
|
haltest_info("%s, client_if=%d, filt_index=%d, addr_type=%d, bda=%s"
|
|
", adv_state=%d", __func__, client_if, filt_index,
|
|
addr_type, bt_bdaddr_t2str(bda, buf), adv_state);
|
|
}
|
|
#endif
|
|
|
|
static const btgatt_client_callbacks_t btgatt_client_callbacks = {
|
|
.register_client_cb = gattc_register_client_cb,
|
|
.scan_result_cb = gattc_scan_result_cb,
|
|
.open_cb = gattc_connect_cb,
|
|
.close_cb = gattc_disconnect_cb,
|
|
.search_complete_cb = gattc_search_complete_cb,
|
|
.search_result_cb = gattc_search_result_cb,
|
|
.get_characteristic_cb = gattc_get_characteristic_cb,
|
|
.get_descriptor_cb = gattc_get_descriptor_cb,
|
|
.get_included_service_cb = gattc_get_included_service_cb,
|
|
.register_for_notification_cb = gattc_register_for_notification_cb,
|
|
.notify_cb = gattc_notify_cb,
|
|
.read_characteristic_cb = gattc_read_characteristic_cb,
|
|
.write_characteristic_cb = gattc_write_characteristic_cb,
|
|
.read_descriptor_cb = gattc_read_descriptor_cb,
|
|
.write_descriptor_cb = gattc_write_descriptor_cb,
|
|
.execute_write_cb = gattc_execute_write_cb,
|
|
.read_remote_rssi_cb = gattc_read_remote_rssi_cb,
|
|
.listen_cb = gattc_listen_cb,
|
|
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
|
.configure_mtu_cb = gattc_configure_mtu_cb,
|
|
.scan_filter_cfg_cb = gattc_scan_filter_cfg_cb,
|
|
.scan_filter_param_cb = gattc_scan_filter_param_cb,
|
|
.scan_filter_status_cb = gattc_scan_filter_status_cb,
|
|
.multi_adv_enable_cb = gattc_multi_adv_enable_cb,
|
|
.multi_adv_update_cb = gattc_multi_adv_update_cb,
|
|
.multi_adv_data_cb = gattc_multi_adv_data_cb,
|
|
.multi_adv_disable_cb = gattc_multi_adv_disable_cb,
|
|
.congestion_cb = gattc_congestion_cb,
|
|
.batchscan_cfg_storage_cb = gattc_batchscan_cfg_storage_cb,
|
|
.batchscan_enb_disable_cb = gattc_batchscan_enable_disable_cb,
|
|
.batchscan_reports_cb = gattc_batchscan_reports_cb,
|
|
.batchscan_threshold_cb = gattc_batchscan_threshold_cb,
|
|
.track_adv_event_cb = gattc_track_adv_event_cb,
|
|
#endif
|
|
};
|
|
|
|
/* BT-GATT Server callbacks */
|
|
|
|
/* Cache server_if and conn_id for tab completion */
|
|
static char server_if_str[20];
|
|
|
|
/* Callback invoked in response to register_server */
|
|
static void gatts_register_server_cb(int status, int server_if,
|
|
bt_uuid_t *app_uuid)
|
|
{
|
|
char buf[MAX_UUID_STR_LEN];
|
|
|
|
haltest_info("%s: status=%d server_if=%d app_uuid=%s\n", __func__,
|
|
status, server_if, gatt_uuid_t2str(app_uuid, buf));
|
|
}
|
|
|
|
/*
|
|
* Callback indicating that a remote device has connected
|
|
* or been disconnected
|
|
*/
|
|
static void gatts_connection_cb(int conn_id, int server_if, int connected,
|
|
bt_bdaddr_t *bda)
|
|
{
|
|
haltest_info("%s: conn_id=%d server_if=%d connected=%d bda=%s\n",
|
|
__func__, conn_id, server_if, connected,
|
|
bt_bdaddr_t2str(bda, last_addr));
|
|
snprintf(conn_id_str, sizeof(conn_id_str), "%d", conn_id);
|
|
}
|
|
|
|
/* Callback invoked in response to create_service */
|
|
static void gatts_service_added_cb(int status, int server_if,
|
|
btgatt_srvc_id_t *srvc_id, int srvc_handle)
|
|
{
|
|
char buf[MAX_SRVC_ID_STR_LEN];
|
|
|
|
snprintf(server_if_str, sizeof(server_if_str), "%d", server_if);
|
|
|
|
haltest_info("%s: status=%d server_if=%d srvc_id=%s handle=0x%x\n",
|
|
__func__, status, server_if,
|
|
btgatt_srvc_id_t2str(srvc_id, buf), srvc_handle);
|
|
}
|
|
|
|
/* Callback indicating that an included service has been added to a service */
|
|
static void gatts_included_service_added_cb(int status, int server_if,
|
|
int srvc_handle,
|
|
int incl_srvc_handle)
|
|
{
|
|
haltest_info("%s: status=%d server_if=%d srvc_handle=0x%x inc_srvc_handle=0x%x\n",
|
|
__func__, status, server_if,
|
|
srvc_handle, incl_srvc_handle);
|
|
}
|
|
|
|
/* Callback invoked when a characteristic has been added to a service */
|
|
static void gatts_characteristic_added_cb(int status, int server_if,
|
|
bt_uuid_t *uuid,
|
|
int srvc_handle,
|
|
int char_handle)
|
|
{
|
|
char buf[MAX_SRVC_ID_STR_LEN];
|
|
|
|
haltest_info("%s: status=%d server_if=%d uuid=%s srvc_handle=0x%x char_handle=0x%x\n",
|
|
__func__, status, server_if, gatt_uuid_t2str(uuid, buf),
|
|
srvc_handle, char_handle);
|
|
}
|
|
|
|
/* Callback invoked when a descriptor has been added to a characteristic */
|
|
static void gatts_descriptor_added_cb(int status, int server_if,
|
|
bt_uuid_t *uuid, int srvc_handle,
|
|
int descr_handle)
|
|
{
|
|
char buf[MAX_SRVC_ID_STR_LEN];
|
|
|
|
haltest_info("%s: status=%d server_if=%d uuid=%s srvc_handle=0x%x descr_handle=0x%x\n",
|
|
__func__, status, server_if, gatt_uuid_t2str(uuid, buf),
|
|
srvc_handle, descr_handle);
|
|
}
|
|
|
|
/* Callback invoked in response to start_service */
|
|
static void gatts_service_started_cb(int status, int server_if, int srvc_handle)
|
|
{
|
|
haltest_info("%s: status=%d server_if=%d srvc_handle=0x%x\n",
|
|
__func__, status, server_if, srvc_handle);
|
|
}
|
|
|
|
/* Callback invoked in response to stop_service */
|
|
static void gatts_service_stopped_cb(int status, int server_if, int srvc_handle)
|
|
{
|
|
haltest_info("%s: status=%d server_if=%d srvc_handle=0x%x\n",
|
|
__func__, status, server_if, srvc_handle);
|
|
}
|
|
|
|
/* Callback triggered when a service has been deleted */
|
|
static void gatts_service_deleted_cb(int status, int server_if, int srvc_handle)
|
|
{
|
|
haltest_info("%s: status=%d server_if=%d srvc_handle=0x%x\n",
|
|
__func__, status, server_if, srvc_handle);
|
|
}
|
|
|
|
/*
|
|
* Callback invoked when a remote device has requested to read a characteristic
|
|
* or descriptor. The application must respond by calling send_response
|
|
*/
|
|
static void gatts_request_read_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
|
|
int attr_handle, int offset,
|
|
bool is_long)
|
|
{
|
|
char buf[MAX_ADDR_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d trans_id=%d bda=%s attr_handle=0x%x offset=%d is_long=%d\n",
|
|
__func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
|
|
attr_handle, offset, is_long);
|
|
}
|
|
|
|
/*
|
|
* Callback invoked when a remote device has requested to write to a
|
|
* characteristic or descriptor.
|
|
*/
|
|
static void gatts_request_write_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
|
|
int attr_handle, int offset, int length,
|
|
bool need_rsp, bool is_prep,
|
|
uint8_t *value)
|
|
{
|
|
char buf[MAX_ADDR_STR_LEN];
|
|
char valbuf[100];
|
|
|
|
haltest_info("%s: conn_id=%d trans_id=%d bda=%s attr_handle=0x%x offset=%d length=%d need_rsp=%d is_prep=%d value=%s\n",
|
|
__func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
|
|
attr_handle, offset, length, need_rsp, is_prep,
|
|
array2str(value, length, valbuf, sizeof(valbuf)));
|
|
}
|
|
|
|
/* Callback invoked when a previously prepared write is to be executed */
|
|
static void gatts_request_exec_write_cb(int conn_id, int trans_id,
|
|
bt_bdaddr_t *bda, int exec_write)
|
|
{
|
|
char buf[MAX_ADDR_STR_LEN];
|
|
|
|
haltest_info("%s: conn_id=%d trans_id=%d bda=%s exec_write=%d\n",
|
|
__func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
|
|
exec_write);
|
|
}
|
|
|
|
/*
|
|
* Callback triggered in response to send_response if the remote device
|
|
* sends a confirmation.
|
|
*/
|
|
static void gatts_response_confirmation_cb(int status, int handle)
|
|
{
|
|
haltest_info("%s: status=%d handle=0x%x\n", __func__, status, handle);
|
|
}
|
|
|
|
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
|
/**
|
|
* Callback confirming that a notification or indication has been sent
|
|
* to a remote device.
|
|
*/
|
|
static void gatts_indication_sent_cb(int conn_id, int status)
|
|
{
|
|
haltest_info("%s: status=%d conn_id=%d", __func__, status, conn_id);
|
|
}
|
|
|
|
/**
|
|
* Callback notifying an application that a remote device connection is
|
|
* currently congested and cannot receive any more data. An application
|
|
* should avoid sending more data until a further callback is received
|
|
* indicating the congestion status has been cleared.
|
|
*/
|
|
static void gatts_congestion_cb(int conn_id, bool congested)
|
|
{
|
|
haltest_info("%s: conn_id=%d congested=%d", __func__, conn_id,
|
|
congested);
|
|
}
|
|
#endif
|
|
|
|
static const btgatt_server_callbacks_t btgatt_server_callbacks = {
|
|
.register_server_cb = gatts_register_server_cb,
|
|
.connection_cb = gatts_connection_cb,
|
|
.service_added_cb = gatts_service_added_cb,
|
|
.included_service_added_cb = gatts_included_service_added_cb,
|
|
.characteristic_added_cb = gatts_characteristic_added_cb,
|
|
.descriptor_added_cb = gatts_descriptor_added_cb,
|
|
.service_started_cb = gatts_service_started_cb,
|
|
.service_stopped_cb = gatts_service_stopped_cb,
|
|
.service_deleted_cb = gatts_service_deleted_cb,
|
|
.request_read_cb = gatts_request_read_cb,
|
|
.request_write_cb = gatts_request_write_cb,
|
|
.request_exec_write_cb = gatts_request_exec_write_cb,
|
|
.response_confirmation_cb = gatts_response_confirmation_cb,
|
|
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
|
.indication_sent_cb = gatts_indication_sent_cb,
|
|
.congestion_cb = gatts_congestion_cb,
|
|
#endif
|
|
};
|
|
|
|
static const btgatt_callbacks_t gatt_cbacks = {
|
|
.size = sizeof(gatt_cbacks),
|
|
.client = &btgatt_client_callbacks,
|
|
.server = &btgatt_server_callbacks
|
|
};
|
|
|
|
/*
|
|
* convert hex string to uint8_t array
|
|
*/
|
|
static int fill_buffer(const char *str, uint8_t *out, int out_size)
|
|
{
|
|
int str_len;
|
|
int i, j;
|
|
char c;
|
|
uint8_t b;
|
|
|
|
str_len = strlen(str);
|
|
|
|
/* Hex string must be byte format */
|
|
if (str_len % 2)
|
|
return -1;
|
|
|
|
for (i = 0, j = 0; i < out_size && j < str_len; i++, j++) {
|
|
c = str[j];
|
|
|
|
if (c >= 'a' && c <= 'f')
|
|
c += 'A' - 'a';
|
|
|
|
if (c >= '0' && c <= '9')
|
|
b = c - '0';
|
|
else if (c >= 'A' && c <= 'F')
|
|
b = 10 + c - 'A';
|
|
else
|
|
return 0;
|
|
|
|
j++;
|
|
|
|
c = str[j];
|
|
|
|
if (c >= 'a' && c <= 'f')
|
|
c += 'A' - 'a';
|
|
|
|
if (c >= '0' && c <= '9')
|
|
b = b * 16 + c - '0';
|
|
else if (c >= 'A' && c <= 'F')
|
|
b = b * 16 + 10 + c - 'A';
|
|
else
|
|
return 0;
|
|
|
|
out[i] = b;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
/* gatt client methods */
|
|
|
|
/* init */
|
|
|
|
static void init_p(int argc, const char **argv)
|
|
{
|
|
RETURN_IF_NULL(if_gatt);
|
|
|
|
EXEC(if_gatt->init, &gatt_cbacks);
|
|
}
|
|
|
|
/* cleanup */
|
|
|
|
static void cleanup_p(int argc, const char **argv)
|
|
{
|
|
RETURN_IF_NULL(if_gatt);
|
|
|
|
EXECV(if_gatt->cleanup);
|
|
|
|
if_gatt = NULL;
|
|
}
|
|
|
|
static struct method methods[] = {
|
|
STD_METHOD(init),
|
|
STD_METHOD(cleanup),
|
|
END_METHOD
|
|
};
|
|
|
|
const struct interface gatt_if = {
|
|
.name = "gatt",
|
|
.methods = methods
|
|
};
|
|
|
|
/* register_client */
|
|
|
|
static void register_client_p(int argc, const char **argv)
|
|
{
|
|
bt_uuid_t uuid;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
|
|
/* uuid */
|
|
if (argc <= 2)
|
|
gatt_str2bt_uuid_t("babe4bed", -1, &uuid);
|
|
else
|
|
gatt_str2bt_uuid_t(argv[2], -1, &uuid);
|
|
|
|
EXEC(if_gatt->client->register_client, &uuid);
|
|
}
|
|
|
|
/* unregister_client */
|
|
|
|
static void unregister_client_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void unregister_client_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
|
|
EXEC(if_gatt->client->unregister_client, client_if);
|
|
}
|
|
|
|
/* scan */
|
|
|
|
/* Same completion as unregister for now, start stop is not auto completed */
|
|
#define scan_c unregister_client_c
|
|
|
|
static void scan_p(int argc, const char **argv)
|
|
{
|
|
#if ANDROID_VERSION < PLATFORM_VER(5, 0, 0)
|
|
int client_if;
|
|
#endif
|
|
int start = 1;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
|
|
#if ANDROID_VERSION < PLATFORM_VER(5, 0, 0)
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
|
|
/* start */
|
|
if (argc >= 4)
|
|
start = strtol(argv[3], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->scan, client_if, start);
|
|
#else
|
|
/* start */
|
|
if (argc >= 3)
|
|
start = strtol(argv[2], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->scan, start);
|
|
#endif
|
|
}
|
|
|
|
/* connect */
|
|
|
|
static void connect_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 4) {
|
|
*user = NULL;
|
|
*enum_func = enum_devices;
|
|
}
|
|
}
|
|
|
|
static void connect_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
bt_bdaddr_t bd_addr;
|
|
int is_direct = 1;
|
|
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
|
int transport = 1;
|
|
#endif
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_ADDR_ARG(3, &bd_addr);
|
|
|
|
/* is_direct */
|
|
if (argc > 4)
|
|
is_direct = strtol(argv[4], NULL, 0);
|
|
|
|
#if ANDROID_VERSION < PLATFORM_VER(5, 0, 0)
|
|
EXEC(if_gatt->client->connect, client_if, &bd_addr, is_direct);
|
|
#else
|
|
/* transport */
|
|
if (argc > 5)
|
|
transport = strtol(argv[5], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->connect, client_if, &bd_addr, is_direct,
|
|
transport);
|
|
#endif
|
|
}
|
|
|
|
/* disconnect */
|
|
|
|
static void disconnect_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 4) {
|
|
*user = last_addr;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 5) {
|
|
*user = conn_id_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void disconnect_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
bt_bdaddr_t bd_addr;
|
|
int conn_id;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_ADDR_ARG(3, &bd_addr);
|
|
VERIFY_CONN_ID(4, conn_id);
|
|
|
|
EXEC(if_gatt->client->disconnect, client_if, &bd_addr, conn_id);
|
|
}
|
|
|
|
/* listen */
|
|
|
|
/* Same completion as unregister for now, start stop is not auto completed */
|
|
#define listen_c unregister_client_c
|
|
|
|
static void listen_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int start = 1;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
|
|
/* start */
|
|
if (argc >= 4)
|
|
start = strtol(argv[3], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->listen, client_if, start);
|
|
}
|
|
|
|
/* refresh */
|
|
|
|
static void refresh_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 4) {
|
|
*enum_func = enum_devices;
|
|
}
|
|
}
|
|
|
|
static void refresh_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
bt_bdaddr_t bd_addr;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_ADDR_ARG(3, &bd_addr);
|
|
|
|
EXEC(if_gatt->client->refresh, client_if, &bd_addr);
|
|
}
|
|
|
|
/* search_service */
|
|
|
|
static void search_service_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = conn_id_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void search_service_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
|
|
/* uuid */
|
|
if (argc <= 3) {
|
|
EXEC(if_gatt->client->search_service, conn_id, NULL);
|
|
|
|
} else {
|
|
bt_uuid_t filter_uuid;
|
|
|
|
gatt_str2bt_uuid_t(argv[3], -1, &filter_uuid);
|
|
EXEC(if_gatt->client->search_service, conn_id, &filter_uuid);
|
|
}
|
|
}
|
|
|
|
/* get_included_service */
|
|
|
|
static void get_included_service_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = conn_id_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void get_included_service_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
btgatt_srvc_id_t srvc_id;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
VERIFY_SRVC_ID(3, &srvc_id);
|
|
|
|
EXEC(if_gatt->client->get_included_service, conn_id, &srvc_id, NULL);
|
|
}
|
|
|
|
/* get_characteristic */
|
|
|
|
/* Same completion as get_included_service_c */
|
|
#define get_characteristic_c get_included_service_c
|
|
|
|
static void get_characteristic_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
btgatt_srvc_id_t srvc_id;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
VERIFY_SRVC_ID(3, &srvc_id);
|
|
|
|
EXEC(if_gatt->client->get_characteristic, conn_id, &srvc_id, NULL);
|
|
}
|
|
|
|
/* get_descriptor */
|
|
|
|
/* Same completion as get_included_service_c */
|
|
#define get_descriptor_c get_included_service_c
|
|
|
|
static void get_descriptor_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
btgatt_srvc_id_t srvc_id;
|
|
btgatt_gatt_id_t char_id;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
VERIFY_SRVC_ID(3, &srvc_id);
|
|
VERIFY_CHAR_ID(4, &char_id);
|
|
|
|
EXEC(if_gatt->client->get_descriptor, conn_id, &srvc_id, &char_id,
|
|
NULL);
|
|
}
|
|
|
|
/* read_characteristic */
|
|
|
|
/* Same completion as get_included_service_c */
|
|
#define read_characteristic_c get_included_service_c
|
|
|
|
static void read_characteristic_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
btgatt_srvc_id_t srvc_id;
|
|
btgatt_gatt_id_t char_id;
|
|
int auth_req = 0;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
VERIFY_SRVC_ID(3, &srvc_id);
|
|
VERIFY_CHAR_ID(4, &char_id);
|
|
|
|
/* auth_req */
|
|
if (argc > 5)
|
|
auth_req = strtol(argv[5], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->read_characteristic, conn_id, &srvc_id, &char_id,
|
|
auth_req);
|
|
}
|
|
|
|
/* write_characteristic */
|
|
|
|
static void write_characteristic_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
/*
|
|
* This should be from tGATT_WRITE_TYPE but it's burried
|
|
* inside bluedroid guts
|
|
*/
|
|
static const char *wrtypes[] = { "1", "2", "3", NULL };
|
|
|
|
if (argc == 3) {
|
|
*user = conn_id_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 6) {
|
|
*user = wrtypes;
|
|
*enum_func = enum_strings;
|
|
}
|
|
}
|
|
|
|
static void write_characteristic_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
btgatt_srvc_id_t srvc_id;
|
|
btgatt_gatt_id_t char_id;
|
|
int write_type;
|
|
int len;
|
|
int auth_req = 0;
|
|
uint8_t value[100];
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
VERIFY_SRVC_ID(3, &srvc_id);
|
|
VERIFY_CHAR_ID(4, &char_id);
|
|
|
|
/* write type */
|
|
if (argc <= 5) {
|
|
haltest_error("No write type specified\n");
|
|
return;
|
|
}
|
|
write_type = strtol(argv[5], NULL, 0);
|
|
|
|
GET_VERIFY_HEX_STRING(6, value, len);
|
|
|
|
/* auth_req */
|
|
if (argc > 7)
|
|
auth_req = strtol(argv[7], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->write_characteristic, conn_id, &srvc_id, &char_id,
|
|
write_type, len, auth_req, (char *) value);
|
|
}
|
|
|
|
/* read_descriptor */
|
|
|
|
/* Same completion as get_included_service_c */
|
|
#define read_descriptor_c get_included_service_c
|
|
|
|
static void read_descriptor_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
btgatt_srvc_id_t srvc_id;
|
|
btgatt_gatt_id_t char_id;
|
|
btgatt_descr_id_t descr_id;
|
|
int auth_req = 0;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
VERIFY_SRVC_ID(3, &srvc_id);
|
|
VERIFY_CHAR_ID(4, &char_id);
|
|
VERIFY_DESCR_ID(5, &descr_id);
|
|
|
|
/* auth_req */
|
|
if (argc > 6)
|
|
auth_req = strtol(argv[6], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->read_descriptor, conn_id, &srvc_id, &char_id,
|
|
&descr_id, auth_req);
|
|
}
|
|
|
|
/* write_descriptor */
|
|
|
|
static void write_descriptor_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
/*
|
|
* This should be from tGATT_WRITE_TYPE but it's burried
|
|
* inside bluedroid guts
|
|
*/
|
|
static const char *wrtypes[] = { "1", "2", "3", NULL };
|
|
|
|
if (argc == 3) {
|
|
*user = conn_id_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 7) {
|
|
*user = wrtypes;
|
|
*enum_func = enum_strings;
|
|
}
|
|
}
|
|
|
|
static void write_descriptor_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
btgatt_srvc_id_t srvc_id;
|
|
btgatt_gatt_id_t char_id;
|
|
btgatt_descr_id_t descr_id;
|
|
int write_type;
|
|
int len;
|
|
int auth_req = 0;
|
|
uint8_t value[200] = {0};
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
VERIFY_SRVC_ID(3, &srvc_id);
|
|
VERIFY_CHAR_ID(4, &char_id);
|
|
VERIFY_DESCR_ID(5, &descr_id);
|
|
|
|
/* write type */
|
|
if (argc <= 6) {
|
|
haltest_error("No write type specified\n");
|
|
return;
|
|
}
|
|
write_type = strtol(argv[6], NULL, 0);
|
|
|
|
/* value */
|
|
if (argc <= 7) {
|
|
haltest_error("No value specified\n");
|
|
return;
|
|
}
|
|
|
|
/* len in chars */
|
|
if (strncmp(argv[7], "0X", 2) && strncmp(argv[7], "0x", 2)) {
|
|
haltest_error("Value must be hex string");
|
|
return;
|
|
}
|
|
|
|
len = fill_buffer(argv[7] + 2, value, sizeof(value));
|
|
|
|
/* auth_req */
|
|
if (argc > 8)
|
|
auth_req = strtol(argv[8], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->write_descriptor, conn_id, &srvc_id, &char_id,
|
|
&descr_id, write_type, len, auth_req, (char *) value);
|
|
}
|
|
|
|
/* execute_write */
|
|
|
|
/* Same completion as search_service */
|
|
#define execute_write_c search_service_c
|
|
|
|
static void execute_write_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
int execute;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
|
|
/* execute */
|
|
if (argc <= 3) {
|
|
haltest_error("No execute specified\n");
|
|
return;
|
|
}
|
|
execute = strtol(argv[3], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->execute_write, conn_id, execute);
|
|
}
|
|
|
|
/* register_for_notification */
|
|
|
|
static void register_for_notification_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 4) {
|
|
*user = last_addr;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void register_for_notification_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
bt_bdaddr_t bd_addr;
|
|
btgatt_srvc_id_t srvc_id;
|
|
btgatt_gatt_id_t char_id;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_ADDR_ARG(3, &bd_addr);
|
|
VERIFY_SRVC_ID(4, &srvc_id);
|
|
VERIFY_CHAR_ID(5, &char_id);
|
|
|
|
EXEC(if_gatt->client->register_for_notification, client_if, &bd_addr,
|
|
&srvc_id, &char_id);
|
|
}
|
|
|
|
/* deregister_for_notification */
|
|
|
|
/* Same completion as search_service */
|
|
#define deregister_for_notification_c register_for_notification_c
|
|
|
|
static void deregister_for_notification_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
bt_bdaddr_t bd_addr;
|
|
btgatt_srvc_id_t srvc_id;
|
|
btgatt_gatt_id_t char_id;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_ADDR_ARG(3, &bd_addr);
|
|
VERIFY_SRVC_ID(4, &srvc_id);
|
|
VERIFY_CHAR_ID(5, &char_id);
|
|
|
|
EXEC(if_gatt->client->deregister_for_notification, client_if, &bd_addr,
|
|
&srvc_id, &char_id);
|
|
}
|
|
|
|
/* read_remote_rssi */
|
|
|
|
static void read_remote_rssi_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 4) {
|
|
*enum_func = enum_devices;
|
|
}
|
|
}
|
|
|
|
static void read_remote_rssi_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
bt_bdaddr_t bd_addr;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_ADDR_ARG(3, &bd_addr);
|
|
|
|
EXEC(if_gatt->client->read_remote_rssi, client_if, &bd_addr);
|
|
}
|
|
|
|
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
|
/* scan filter parameter setup */
|
|
static void scan_filter_param_setup_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void scan_filter_param_setup_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int action;
|
|
int filt_index;
|
|
int feat_seln;
|
|
int list_logic_type, filt_logic_type;
|
|
int rssi_high_thres, rssi_low_thres;
|
|
int dely_mode;
|
|
int found_timeout, lost_timeout, found_timeout_cnt;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_ACTION(3, action);
|
|
VERIFY_FILT_INDEX(4, filt_index);
|
|
VERIFY_FEAT_SELN(5, feat_seln);
|
|
VERIFY_LIST_LOGIC_TYPE(6, list_logic_type);
|
|
VERIFY_FILT_LOGIC_TYPE(7, filt_logic_type);
|
|
VERIFY_RSSI_HI_THR(8, rssi_high_thres);
|
|
VERIFY_RSSI_LOW_THR(9, rssi_low_thres);
|
|
VERIFY_DELY_MODE(10, dely_mode);
|
|
VERIFY_FND_TIME(11, found_timeout);
|
|
VERIFY_LOST_TIME(12, lost_timeout);
|
|
VERIFY_FND_TIME_CNT(13, found_timeout_cnt);
|
|
|
|
EXEC(if_gatt->client->scan_filter_param_setup, client_if, action,
|
|
filt_index, feat_seln, list_logic_type, filt_logic_type,
|
|
rssi_high_thres, rssi_low_thres, dely_mode, found_timeout,
|
|
lost_timeout, found_timeout_cnt);
|
|
}
|
|
|
|
/* scan filter add remove */
|
|
|
|
static void scan_filter_add_remove_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 10) {
|
|
*user = last_addr;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void scan_filter_add_remove_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int action;
|
|
int filt_type;
|
|
int filt_index;
|
|
int company_id;
|
|
int company_id_mask;
|
|
bt_uuid_t p_uuid;
|
|
bt_uuid_t p_uuid_mask;
|
|
bt_bdaddr_t bd_addr;
|
|
char addr_type;
|
|
int data_len;
|
|
uint8_t p_data[100];
|
|
int mask_len;
|
|
uint8_t p_mask[100];
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_ACTION(3, action);
|
|
VERIFY_FILT_TYPE(4, filt_type);
|
|
VERIFY_FILT_INDEX(5, filt_index);
|
|
VERIFY_COMP_ID(6, company_id);
|
|
VERIFY_COMP_ID_MASK(7, company_id_mask);
|
|
|
|
if (argc <= 9) {
|
|
haltest_error("No p_uuid, p_uuid_mask specified\n");
|
|
return;
|
|
}
|
|
gatt_str2bt_uuid_t(argv[8], -1, &p_uuid);
|
|
gatt_str2bt_uuid_t(argv[9], -1, &p_uuid_mask);
|
|
|
|
VERIFY_UUID(8, &p_uuid);
|
|
VERIFY_UUID(9, &p_uuid_mask);
|
|
VERIFY_ADDR_ARG(10, &bd_addr);
|
|
VERIFY_ADDR_TYPE(11, addr_type);
|
|
GET_VERIFY_HEX_STRING(12, p_data, data_len);
|
|
GET_VERIFY_HEX_STRING(13, p_mask, mask_len);
|
|
|
|
EXEC(if_gatt->client->scan_filter_add_remove, client_if, action,
|
|
filt_type, filt_index, company_id, company_id_mask,
|
|
&p_uuid, &p_uuid_mask, &bd_addr, addr_type, data_len,
|
|
(char *) p_data, mask_len, (char *) p_mask);
|
|
}
|
|
|
|
/* scan filter clean */
|
|
static void scan_filter_clear_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void scan_filter_clear_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int filt_index;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_FILT_INDEX(3, filt_index);
|
|
|
|
EXEC(if_gatt->client->scan_filter_clear, client_if, filt_index);
|
|
}
|
|
|
|
/* scan filter enable */
|
|
static void scan_filter_enable_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void scan_filter_enable_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int enable = 0;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
|
|
/* enable */
|
|
if (argc >= 4)
|
|
enable = strtol(argv[3], NULL, 0);
|
|
|
|
EXEC(if_gatt->client->scan_filter_clear, client_if, enable);
|
|
}
|
|
|
|
/* set advertising data */
|
|
static void set_adv_data_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void set_adv_data_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
bool set_scan_rsp;
|
|
bool include_name, include_txpower;
|
|
int min_interval, max_interval;
|
|
int appearance;
|
|
uint16_t manufacturer_len;
|
|
uint8_t manufacturer_data[100];
|
|
uint16_t service_data_len;
|
|
uint8_t service_data[100];
|
|
uint16_t service_uuid_len;
|
|
uint8_t service_uuid[100];
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
|
|
/* set scan response */
|
|
if (argc >= 4)
|
|
set_scan_rsp = strtol(argv[3], NULL, 0);
|
|
/* include name */
|
|
if (argc >= 5)
|
|
include_name = strtol(argv[4], NULL, 0);
|
|
/* include txpower */
|
|
if (argc >= 6)
|
|
include_txpower = strtol(argv[5], NULL, 0);
|
|
|
|
VERIFY_MIN_INTERVAL(6, min_interval);
|
|
VERIFY_MAX_INTERVAL(7, max_interval);
|
|
VERIFY_APPEARANCE(8, appearance);
|
|
GET_VERIFY_HEX_STRING(9, manufacturer_data, manufacturer_len);
|
|
GET_VERIFY_HEX_STRING(10, service_data, service_data_len);
|
|
GET_VERIFY_HEX_STRING(11, service_uuid, service_uuid_len);
|
|
|
|
EXEC(if_gatt->client->set_adv_data, client_if, set_scan_rsp,
|
|
include_name, include_txpower, min_interval, max_interval,
|
|
appearance, manufacturer_len, (char *) manufacturer_data,
|
|
service_data_len, (char *) service_data, service_uuid_len,
|
|
(char *) service_uuid);
|
|
}
|
|
|
|
/* configure mtu */
|
|
static void configure_mtu_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = conn_id_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void configure_mtu_p(int argc, const char **argv)
|
|
{
|
|
int conn_id;
|
|
int mtu;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
VERIFY_MTU(3, mtu);
|
|
|
|
EXEC(if_gatt->client->configure_mtu, conn_id, mtu);
|
|
}
|
|
|
|
/* con parameter update */
|
|
static void conn_parameter_update_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = last_addr;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void conn_parameter_update_p(int argc, const char **argv)
|
|
{
|
|
bt_bdaddr_t bd_addr;
|
|
int min_interval, max_interval;
|
|
int latency;
|
|
int timeout;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_ADDR_ARG(2, &bd_addr);
|
|
VERIFY_MIN_INTERVAL(3, min_interval);
|
|
VERIFY_MAX_INTERVAL(4, max_interval);
|
|
VERIFY_LATENCY(5, latency);
|
|
VERIFY_TIMEOUT(6, timeout);
|
|
|
|
EXEC(if_gatt->client->conn_parameter_update, &bd_addr, min_interval,
|
|
max_interval, latency, timeout);
|
|
}
|
|
|
|
/* set scan parameters */
|
|
static void set_scan_parameters_p(int argc, const char **argv)
|
|
{
|
|
int scan_interval;
|
|
int scan_window;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SCAN_INTERVAL(2, scan_interval);
|
|
VERIFY_SCAN_WINDOW(3, scan_window);
|
|
|
|
EXEC(if_gatt->client->set_scan_parameters, scan_interval, scan_window);
|
|
}
|
|
|
|
/* enable multi advertising */
|
|
static void multi_adv_enable_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void multi_adv_enable_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int min_interval, max_interval;
|
|
int adv_type;
|
|
int chnl_map;
|
|
int tx_power;
|
|
int timeout_s;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_MIN_INTERVAL(3, min_interval);
|
|
VERIFY_MAX_INTERVAL(4, max_interval);
|
|
VERIFY_ADV_TYPE(5, adv_type);
|
|
VERIFY_CHNL_MAP(6, chnl_map);
|
|
VERIFY_TX_POWER(7, tx_power);
|
|
VERIFY_TIMEOUT_S(8, timeout_s);
|
|
|
|
EXEC(if_gatt->client->multi_adv_enable, client_if, min_interval,
|
|
max_interval, adv_type, chnl_map, tx_power, timeout_s);
|
|
}
|
|
|
|
/* update multi advertiser */
|
|
static void multi_adv_update_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void multi_adv_update_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int min_interval, max_interval;
|
|
int adv_type;
|
|
int chnl_map;
|
|
int tx_power;
|
|
int timeout_s;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_MIN_INTERVAL(3, min_interval);
|
|
VERIFY_MAX_INTERVAL(4, max_interval);
|
|
VERIFY_ADV_TYPE(5, adv_type);
|
|
VERIFY_CHNL_MAP(6, chnl_map);
|
|
VERIFY_TX_POWER(7, tx_power);
|
|
VERIFY_TIMEOUT_S(8, timeout_s);
|
|
|
|
EXEC(if_gatt->client->multi_adv_update, client_if, min_interval,
|
|
max_interval, adv_type, chnl_map, tx_power, timeout_s);
|
|
}
|
|
|
|
/* set advertising data */
|
|
static void multi_adv_set_inst_data_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void multi_adv_set_inst_data_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
bool set_scan_rsp;
|
|
bool include_name, include_txpower;
|
|
int appearance;
|
|
uint16_t manufacturer_len;
|
|
uint8_t manufacturer_data[100];
|
|
uint16_t service_data_len;
|
|
uint8_t service_data[100];
|
|
uint16_t service_uuid_len;
|
|
uint8_t service_uuid[100];
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
|
|
/* set scan response */
|
|
if (argc >= 4)
|
|
set_scan_rsp = strtol(argv[3], NULL, 0);
|
|
/* include name */
|
|
if (argc >= 5)
|
|
include_name = strtol(argv[4], NULL, 0);
|
|
/* include txpower */
|
|
if (argc >= 6)
|
|
include_txpower = strtol(argv[5], NULL, 0);
|
|
|
|
VERIFY_APPEARANCE(6, appearance);
|
|
GET_VERIFY_HEX_STRING(7, manufacturer_data, manufacturer_len);
|
|
GET_VERIFY_HEX_STRING(8, service_data, service_data_len);
|
|
GET_VERIFY_HEX_STRING(9, service_uuid, service_uuid_len);
|
|
|
|
EXEC(if_gatt->client->multi_adv_set_inst_data, client_if, set_scan_rsp,
|
|
include_name, include_txpower, appearance, manufacturer_len,
|
|
(char *) manufacturer_data, service_data_len,
|
|
(char *) service_data, service_uuid_len, (char *) service_uuid);
|
|
}
|
|
|
|
/* multi advertising disable */
|
|
static void multi_adv_disable_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void multi_adv_disable_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
|
|
EXEC(if_gatt->client->multi_adv_disable, client_if);
|
|
}
|
|
|
|
/* batch scanconfigure storage */
|
|
static void batchscan_cfg_storage_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void batchscan_cfg_storage_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int batch_scan_full_max;
|
|
int batch_scan_trunc_max;
|
|
int batch_scan_notify_threshold;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_BATCH_SCAN_FULL_MAX(3, batch_scan_full_max);
|
|
VERIFY_BATCH_SCAN_TRUNC_MAX(4, batch_scan_trunc_max);
|
|
VERIFY_BATCH_SCAN_NOTIFY_THR(5, batch_scan_notify_threshold);
|
|
|
|
EXEC(if_gatt->client->batchscan_cfg_storage, client_if,
|
|
batch_scan_full_max, batch_scan_trunc_max,
|
|
batch_scan_notify_threshold);
|
|
}
|
|
|
|
/* enable batch scan */
|
|
static void batchscan_enb_batch_scan_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void batchscan_enb_batch_scan_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int scan_mode, scan_interval, scan_window;
|
|
int addr_type;
|
|
int discard_rule;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_SCAN_MODE(3, scan_mode);
|
|
VERIFY_SCAN_INTERVAL(4, scan_interval);
|
|
VERIFY_SCAN_WINDOW(5, scan_window);
|
|
VERIFY_ADDR_TYPE(6, addr_type);
|
|
VERIFY_DISCARD_RULE(7, discard_rule);
|
|
|
|
EXEC(if_gatt->client->batchscan_enb_batch_scan, client_if, scan_mode,
|
|
scan_interval, scan_window, addr_type, discard_rule);
|
|
}
|
|
|
|
/* batchscan disable */
|
|
static void batchscan_dis_batch_scan_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void batchscan_dis_batch_scan_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
|
|
EXEC(if_gatt->client->batchscan_dis_batch_scan, client_if);
|
|
}
|
|
|
|
/* batchscan read reports */
|
|
static void batchscan_read_reports_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 2) {
|
|
*user = client_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void batchscan_read_reports_p(int argc, const char **argv)
|
|
{
|
|
int client_if;
|
|
int scan_mode;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_CLIENT_IF(2, client_if);
|
|
VERIFY_SCAN_MODE(3, scan_mode);
|
|
|
|
EXEC(if_gatt->client->batchscan_read_reports, client_if, scan_mode);
|
|
}
|
|
#endif
|
|
|
|
/* get_device_type */
|
|
|
|
static void get_device_type_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3)
|
|
*enum_func = enum_devices;
|
|
}
|
|
|
|
static void get_device_type_p(int argc, const char **argv)
|
|
{
|
|
bt_bdaddr_t bd_addr;
|
|
int dev_type;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_ADDR_ARG(2, &bd_addr);
|
|
|
|
dev_type = if_gatt->client->get_device_type(&bd_addr);
|
|
haltest_info("%s: %d\n", "get_device_type", dev_type);
|
|
}
|
|
|
|
/* test_command */
|
|
|
|
static void test_command_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 4)
|
|
*enum_func = enum_devices;
|
|
}
|
|
|
|
static void test_command_p(int argc, const char **argv)
|
|
{
|
|
int command;
|
|
int i;
|
|
bt_bdaddr_t bd_addr;
|
|
bt_uuid_t uuid;
|
|
btgatt_test_params_t params = {
|
|
.bda1 = &bd_addr,
|
|
.uuid1 = &uuid
|
|
};
|
|
uint16_t *u = ¶ms.u1;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
|
|
/* command */
|
|
if (argc <= 2) {
|
|
haltest_error("No command specified\n");
|
|
return;
|
|
}
|
|
command = strtol(argv[2], NULL, 0);
|
|
|
|
VERIFY_ADDR_ARG(3, &bd_addr);
|
|
VERIFY_UUID(4, &uuid);
|
|
|
|
for (i = 5; i < argc; i++)
|
|
VERIFY_TEST_ARG(i, *u++);
|
|
|
|
EXEC(if_gatt->client->test_command, command, ¶ms);
|
|
}
|
|
|
|
static struct method client_methods[] = {
|
|
STD_METHODH(register_client, "[<uuid>]"),
|
|
STD_METHODCH(unregister_client, "<client_if>"),
|
|
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
|
STD_METHODCH(scan, "[1|0]"),
|
|
STD_METHODCH(connect, "<client_if> <addr> [<is_direct>] [<transport]"),
|
|
STD_METHODCH(scan_filter_param_setup, "<client_if> <action>"
|
|
" <filt_index> <feat_seln> <list_logic_type>"
|
|
" <filt_logic_type> <rssi_high_thres> <rssi_low_thres>"
|
|
" <dely_mode> <found_timeout> <lost_timeout>"
|
|
" <found_timeout_cnt>"),
|
|
STD_METHODCH(scan_filter_add_remove, "<client_if> <action> <filt_type>"
|
|
" <filt_index> <company_id> <company_id_mask>"
|
|
" [<p_uuid>] <p_uuid_mask> <addr> <addr_type>"
|
|
" [<p_data>] [<p_mask>]"),
|
|
STD_METHODCH(scan_filter_clear, "<client_if> <filt_index>"),
|
|
STD_METHODCH(scan_filter_enable, "<client_if> [<enable>]"),
|
|
STD_METHODCH(set_adv_data, "<client_if> [<set_scan_rsp>] <include_name>"
|
|
" [<include_txpower>] <min_interval> <max_interval>"
|
|
" <appearance> [<manufacturer_data>] [<service_data>]"
|
|
" [<service_uuid>]"),
|
|
STD_METHODCH(configure_mtu, "<conn_id> <mtu>"),
|
|
STD_METHODCH(conn_parameter_update, "<bd_addr> <min_interval>"
|
|
" <max_interval> <latency> <timeout>"),
|
|
STD_METHODH(set_scan_parameters, "<scan_inverval> <scan_window>"),
|
|
STD_METHODCH(multi_adv_enable, "<client_if> <min_interval>"
|
|
" <max_interval> <adv_type> <chnl_map> <tx_power>"
|
|
" <timeout_s>"),
|
|
STD_METHODCH(multi_adv_update, "<client_if> <min_interval>"
|
|
" <max_interval> <adv_type> <chnl_map> <tx_power>"
|
|
" <timeout_s>"),
|
|
STD_METHODCH(multi_adv_set_inst_data, "<client_if> [<set_scan_rsp>]"
|
|
" <include_name> [<include_txpower>] <appearance>"
|
|
" [<manufacturer_data>] [<service_data>]"
|
|
" [<service_uuid>]"),
|
|
STD_METHODCH(multi_adv_disable, "<client_if>"),
|
|
STD_METHODCH(batchscan_cfg_storage, "<client_if> <batch_scan_full_max>"
|
|
" <batch_scan_trunc_max>"
|
|
" <batch_scan_notify_threshold>"),
|
|
STD_METHODCH(batchscan_enb_batch_scan, "<client_if> <scan_mode>"
|
|
" <scan_interval> <scan_window> <addr_type>"
|
|
" <discard_rule>"),
|
|
STD_METHODCH(batchscan_dis_batch_scan, "<client_if>"),
|
|
STD_METHODCH(batchscan_read_reports, "<client_if> <scan_mode>"),
|
|
#else
|
|
STD_METHODCH(scan, "<client_if> [1|0]"),
|
|
STD_METHODCH(connect, "<client_if> <addr> [<is_direct>]"),
|
|
#endif
|
|
STD_METHODCH(disconnect, "<client_if> <addr> <conn_id>"),
|
|
STD_METHODCH(refresh, "<client_if> <addr>"),
|
|
STD_METHODCH(search_service, "<conn_id> [<uuid>]"),
|
|
STD_METHODCH(get_included_service, "<conn_id> <srvc_id>"),
|
|
STD_METHODCH(get_characteristic, "<conn_id> <srvc_id>"),
|
|
STD_METHODCH(get_descriptor, "<conn_id> <srvc_id> <char_id>"),
|
|
STD_METHODCH(read_characteristic,
|
|
"<conn_id> <srvc_id> <char_id> [<auth_req>]"),
|
|
STD_METHODCH(write_characteristic,
|
|
"<conn_id> <srvc_id> <char_id> <write_type> <hex_value> [<auth_req>]"),
|
|
STD_METHODCH(read_descriptor,
|
|
"<conn_id> <srvc_id> <char_id> <descr_id> [<auth_req>]"),
|
|
STD_METHODCH(write_descriptor,
|
|
"<conn_id> <srvc_id> <char_id> <descr_id> <write_type> <hex_value> [<auth_req>]"),
|
|
STD_METHODCH(execute_write, "<conn_id> <execute>"),
|
|
STD_METHODCH(register_for_notification,
|
|
"<client_if> <addr> <srvc_id> <char_id>"),
|
|
STD_METHODCH(deregister_for_notification,
|
|
"<client_if> <addr> <srvc_id> <char_id>"),
|
|
STD_METHODCH(read_remote_rssi, "<client_if> <addr>"),
|
|
STD_METHODCH(get_device_type, "<addr>"),
|
|
STD_METHODCH(test_command,
|
|
"<cmd> <addr> <uuid> [u1] [u2] [u3] [u4] [u5]"),
|
|
STD_METHODCH(listen, "<client_if> [1|0]"),
|
|
END_METHOD
|
|
};
|
|
|
|
const struct interface gatt_client_if = {
|
|
.name = "gattc",
|
|
.methods = client_methods
|
|
};
|
|
|
|
/* gatt server methods */
|
|
|
|
/* register_server */
|
|
|
|
static void gatts_register_server_p(int argc, const char *argv[])
|
|
{
|
|
bt_uuid_t uuid;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
|
|
/* uuid */
|
|
if (argc <= 2)
|
|
gatt_str2bt_uuid_t("bed4babe", -1, &uuid);
|
|
else
|
|
gatt_str2bt_uuid_t(argv[2], -1, &uuid);
|
|
|
|
EXEC(if_gatt->server->register_server, &uuid);
|
|
}
|
|
|
|
/* unregister_server */
|
|
|
|
static void gatts_unregister_server_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = server_if_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void gatts_unregister_server_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
|
|
EXEC(if_gatt->server->unregister_server, server_if);
|
|
}
|
|
|
|
/* connect */
|
|
|
|
static void gatts_connect_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = server_if_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 4) {
|
|
*user = NULL;
|
|
*enum_func = enum_devices;
|
|
}
|
|
}
|
|
|
|
static void gatts_connect_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
bt_bdaddr_t bd_addr;
|
|
int is_direct = 1;
|
|
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
|
int transport = 1;
|
|
#endif
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_ADDR_ARG(3, &bd_addr);
|
|
|
|
/* is_direct */
|
|
if (argc > 4)
|
|
is_direct = strtol(argv[4], NULL, 0);
|
|
|
|
#if ANDROID_VERSION < PLATFORM_VER(5, 0, 0)
|
|
EXEC(if_gatt->server->connect, server_if, &bd_addr, is_direct);
|
|
#else
|
|
/* transport */
|
|
if (argc > 5)
|
|
transport = strtol(argv[5], NULL, 0);
|
|
|
|
EXEC(if_gatt->server->connect, server_if, &bd_addr, is_direct,
|
|
transport);
|
|
#endif
|
|
}
|
|
|
|
/* disconnect */
|
|
|
|
static void gatts_disconnect_c(int argc, const char **argv,
|
|
enum_func *enum_func, void **user)
|
|
{
|
|
if (argc == 3) {
|
|
*user = server_if_str;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 4) {
|
|
*user = last_addr;
|
|
*enum_func = enum_one_string;
|
|
} else if (argc == 5) {
|
|
*user = conn_id_str;
|
|
*enum_func = enum_one_string;
|
|
}
|
|
}
|
|
|
|
static void gatts_disconnect_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
bt_bdaddr_t bd_addr;
|
|
int conn_id;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_ADDR_ARG(3, &bd_addr);
|
|
VERIFY_CONN_ID(4, conn_id);
|
|
|
|
EXEC(if_gatt->server->disconnect, server_if, &bd_addr, conn_id);
|
|
}
|
|
|
|
/* add_service */
|
|
|
|
/* Same completion as gatts_unregister_server_c */
|
|
#define gatts_add_service_c gatts_unregister_server_c
|
|
|
|
static void gatts_add_service_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
btgatt_srvc_id_t srvc_id;
|
|
int num_handles;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_SRVC_ID(3, &srvc_id);
|
|
|
|
/* num handles */
|
|
if (argc <= 4) {
|
|
haltest_error("No num_handles specified\n");
|
|
return;
|
|
}
|
|
num_handles = strtol(argv[4], NULL, 0);
|
|
|
|
EXEC(if_gatt->server->add_service, server_if, &srvc_id, num_handles);
|
|
}
|
|
|
|
/* add_included_service */
|
|
|
|
/* Same completion as gatts_unregister_server_c */
|
|
#define gatts_add_included_service_c gatts_unregister_server_c
|
|
|
|
static void gatts_add_included_service_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
int service_handle;
|
|
int included_handle;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_SERVICE_HANDLE(3, service_handle);
|
|
VERIFY_HANDLE(4, included_handle);
|
|
|
|
EXEC(if_gatt->server->add_included_service, server_if, service_handle,
|
|
included_handle);
|
|
}
|
|
|
|
/* add_characteristic */
|
|
|
|
/* Same completion as gatts_unregister_server_c */
|
|
#define gatts_add_characteristic_c gatts_unregister_server_c
|
|
|
|
static void gatts_add_characteristic_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
int service_handle;
|
|
int properties;
|
|
int permissions;
|
|
bt_uuid_t uuid;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_SERVICE_HANDLE(3, service_handle);
|
|
VERIFY_UUID(4, &uuid);
|
|
|
|
/* properties */
|
|
if (argc <= 5) {
|
|
haltest_error("No properties specified\n");
|
|
return;
|
|
}
|
|
properties = strtol(argv[5], NULL, 0);
|
|
|
|
/* permissions */
|
|
if (argc <= 6) {
|
|
haltest_error("No permissions specified\n");
|
|
return;
|
|
}
|
|
permissions = strtol(argv[6], NULL, 0);
|
|
|
|
EXEC(if_gatt->server->add_characteristic, server_if, service_handle,
|
|
&uuid, properties, permissions);
|
|
}
|
|
|
|
/* add_descriptor */
|
|
|
|
/* Same completion as gatts_unregister_server_c */
|
|
#define gatts_add_descriptor_c gatts_unregister_server_c
|
|
|
|
static void gatts_add_descriptor_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
int service_handle;
|
|
int permissions;
|
|
bt_uuid_t uuid;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_SERVICE_HANDLE(3, service_handle);
|
|
VERIFY_UUID(4, &uuid);
|
|
|
|
/* permissions */
|
|
if (argc <= 5) {
|
|
haltest_error("No permissions specified\n");
|
|
return;
|
|
}
|
|
permissions = strtol(argv[5], NULL, 0);
|
|
|
|
EXEC(if_gatt->server->add_descriptor, server_if, service_handle, &uuid,
|
|
permissions);
|
|
}
|
|
|
|
/* start_service */
|
|
|
|
/* Same completion as gatts_unregister_server_c */
|
|
#define gatts_start_service_c gatts_unregister_server_c
|
|
|
|
static void gatts_start_service_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
int service_handle;
|
|
int transport;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_SERVICE_HANDLE(3, service_handle);
|
|
|
|
/* transport */
|
|
if (argc <= 4) {
|
|
haltest_error("No transport specified\n");
|
|
return;
|
|
}
|
|
transport = strtol(argv[4], NULL, 0);
|
|
|
|
EXEC(if_gatt->server->start_service, server_if, service_handle,
|
|
transport);
|
|
}
|
|
|
|
/* stop_service */
|
|
|
|
/* Same completion as gatts_unregister_server_c */
|
|
#define gatts_stop_service_c gatts_unregister_server_c
|
|
|
|
static void gatts_stop_service_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
int service_handle;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_SERVICE_HANDLE(3, service_handle);
|
|
|
|
EXEC(if_gatt->server->stop_service, server_if, service_handle);
|
|
}
|
|
|
|
/* delete_service */
|
|
|
|
/* Same completion as gatts_unregister_server_c */
|
|
#define gatts_delete_service_c gatts_unregister_server_c
|
|
|
|
static void gatts_delete_service_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
int service_handle;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_SERVICE_HANDLE(3, service_handle);
|
|
|
|
EXEC(if_gatt->server->delete_service, server_if, service_handle);
|
|
}
|
|
|
|
/* send_indication */
|
|
|
|
static void gatts_send_indication_p(int argc, const char *argv[])
|
|
{
|
|
int server_if;
|
|
int attr_handle;
|
|
int conn_id;
|
|
int confirm;
|
|
char data[200];
|
|
int len = 0;
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
VERIFY_SERVER_IF(2, server_if);
|
|
VERIFY_HANDLE(3, attr_handle);
|
|
VERIFY_CONN_ID(4, conn_id);
|
|
|
|
/* confirm */
|
|
if (argc <= 5) {
|
|
haltest_error("No transport specified\n");
|
|
return;
|
|
}
|
|
confirm = strtol(argv[5], NULL, 0);
|
|
|
|
GET_VERIFY_HEX_STRING(6, data, len);
|
|
|
|
EXEC(if_gatt->server->send_indication, server_if, attr_handle, conn_id,
|
|
len, confirm, data);
|
|
}
|
|
|
|
/* send_response */
|
|
|
|
static void gatts_send_response_p(int argc, const char *argv[])
|
|
{
|
|
int conn_id;
|
|
int trans_id;
|
|
int status;
|
|
btgatt_response_t data;
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
|
|
RETURN_IF_NULL(if_gatt);
|
|
|
|
VERIFY_CONN_ID(2, conn_id);
|
|
VERIFY_TRANS_ID(3, trans_id);
|
|
VERIFY_STATUS(4, status);
|
|
VERIFY_HANDLE(5, data.attr_value.handle);
|
|
VERIFY_OFFSET(6, data.attr_value.offset);
|
|
|
|
data.attr_value.auth_req = 0;
|
|
data.attr_value.len = 0;
|
|
|
|
GET_VERIFY_HEX_STRING(7, data.attr_value.value, data.attr_value.len);
|
|
|
|
haltest_info("conn_id %d, trans_id %d, status %d", conn_id, trans_id,
|
|
status);
|
|
|
|
EXEC(if_gatt->server->send_response, conn_id, trans_id, status, &data);
|
|
}
|
|
|
|
#define GATTS_METHODH(n, h) METHOD(#n, gatts_##n##_p, NULL, h)
|
|
#define GATTS_METHODCH(n, h) METHOD(#n, gatts_##n##_p, gatts_##n##_c, h)
|
|
|
|
static struct method server_methods[] = {
|
|
GATTS_METHODH(register_server, "[<uuid>]"),
|
|
GATTS_METHODCH(unregister_server, "<server_if>"),
|
|
#if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
|
|
GATTS_METHODCH(connect, "<server_if> <addr> [<is_direct>] [<transport>]"),
|
|
#else
|
|
GATTS_METHODCH(connect, "<server_if> <addr> [<is_direct>]"),
|
|
#endif
|
|
GATTS_METHODCH(disconnect, "<server_if> <addr> <conn_id>"),
|
|
GATTS_METHODCH(add_service, "<server_if> <srvc_id> <num_handles>"),
|
|
GATTS_METHODCH(add_included_service,
|
|
"<server_if> <service_handle> <included_handle>"),
|
|
GATTS_METHODCH(add_characteristic,
|
|
"<server_if> <service_handle> <uuid> <properites> <permissions>"),
|
|
GATTS_METHODCH(add_descriptor,
|
|
"<server_if> <service_handle> <uuid> <permissions>"),
|
|
GATTS_METHODCH(start_service,
|
|
"<server_if> <service_handle> <transport>"),
|
|
GATTS_METHODCH(stop_service, "<server_if> <service_handle>"),
|
|
GATTS_METHODCH(delete_service, "<server_if> <service_handle>"),
|
|
GATTS_METHODH(send_indication,
|
|
"<server_if> <attr_handle> <conn_id> <confirm> [<data>]"),
|
|
GATTS_METHODH(send_response,
|
|
"<conn_id> <trans_id> <status> <handle> <offset> [<data>]"),
|
|
END_METHOD
|
|
};
|
|
|
|
const struct interface gatt_server_if = {
|
|
.name = "gatts",
|
|
.methods = server_methods
|
|
};
|