#include <stdio.h>
|
#include <errno.h>
|
#include <glib.h>
|
#include <unistd.h>
|
#include <stdlib.h>
|
#include <signal.h>
|
#include <stdbool.h>
|
#include <wordexp.h>
|
#include <sys/un.h>
|
#include <sys/signalfd.h>
|
#include <sys/socket.h>
|
#include <readline/readline.h>
|
#include <readline/history.h>
|
#include <linux/input.h>
|
#include <dirent.h>
|
#include <fcntl.h>
|
#include <pthread.h>
|
|
#include "DeviceIo.h"
|
//#include "Rk_shell.h"
|
|
#include "a2dp_masterctrl.h"
|
#include "shell.h"
|
#include "util.h"
|
#include "agent.h"
|
#include "gatt.h"
|
#include "advertising.h"
|
#include "../bluez_ctrl.h"
|
#include "../gatt_config.h"
|
#include "../gatt_client.h"
|
#include "../bluez_ctrl.h"
|
#include "utility.h"
|
#include "slog.h"
|
|
/* operands in passthrough commands */
|
#define AVC_VOLUME_UP 0x41
|
#define AVC_VOLUME_DOWN 0x42
|
#define AVC_PLAY 0x44
|
#define AVC_STOP 0x45
|
#define AVC_PAUSE 0x46
|
#define AVC_FORWARD 0x4b
|
#define AVC_BACKWARD 0x4c
|
|
/* String display constants */
|
#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
|
#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF
|
#define COLORED_DEL COLOR_RED "DEL" COLOR_OFF
|
|
#define PROMPT_ON COLOR_BLUE "[bluetooth]" COLOR_OFF "# "
|
#define PROMPT_OFF "Waiting to connect to bluetoothd..."
|
|
#define DISTANCE_VAL_INVALID 0x7FFF
|
|
DBusConnection *dbus_conn = NULL;
|
static GDBusProxy *agent_manager;
|
static char *auto_register_agent = NULL;
|
static RkBtContent *g_bt_content = NULL;
|
|
struct remote_sink_device {
|
int state;
|
char addr[64];
|
char name[64];
|
};
|
struct remote_sink_device rsd;
|
|
struct adapter {
|
GDBusProxy *proxy;
|
GDBusProxy *ad_proxy;
|
GList *devices;
|
};
|
|
typedef struct {
|
RK_BT_STATE_CALLBACK bt_state_cb;
|
RK_BT_BOND_CALLBACK bt_bond_state_cb;
|
RK_BT_DISCOVERY_CALLBACK bt_decovery_cb;
|
RK_BT_DEV_FOUND_CALLBACK bt_dev_found_cb;
|
RK_BT_SOURCE_CALLBACK bt_source_event_cb;
|
RK_BLE_STATE_CALLBACK ble_state_cb;
|
RK_BT_NAME_CHANGE_CALLBACK bt_name_change_cb;
|
RK_BT_MTU_CALLBACK ble_mtu_cb;
|
} bt_callback_t;
|
|
typedef struct {
|
bool is_scaning;
|
bool scan_off_failed;
|
pthread_t scan_thread;
|
unsigned int scan_time;
|
RK_BT_SCAN_TYPE scan_type;
|
} bt_scan_info_t;
|
|
typedef struct {
|
bool is_connecting;
|
bool is_reconnected;
|
char connect_address[18];
|
char reconnect_address[18];
|
} bt_source_info_t;
|
|
//workround unknow err for con/discon remote proxy
|
struct ConnectContext_t {
|
GDBusProxy *proxy;
|
char *address;
|
};
|
|
struct adapter *default_ctrl = NULL;
|
GDBusProxy *default_dev = NULL;
|
GDBusProxy *ble_dev = NULL;
|
GDBusProxy *default_attr = NULL;
|
GList *ctrl_list;
|
|
GDBusClient *btsrc_client = NULL;
|
|
/* For connect cmd */
|
#define BTSRC_CONNECT_IDLE 0
|
#define BTSRC_CONNECT_DOING 1
|
#define BTSRC_CONNECT_SUCESS 2
|
#define BTSRC_CONNECT_FAILED 3
|
|
static bool BT_OPENED = 0;
|
static bool BT_CLOSED = 0;
|
|
static void *g_btmaster_userdata = NULL;
|
static RK_BLE_STATE g_ble_state;
|
static RK_BT_SOURCE_EVENT g_device_state = BT_SOURCE_EVENT_DISCONNECTED;
|
|
static bt_source_info_t g_bt_source_info = {
|
false, false,
|
};
|
|
static bt_callback_t g_bt_callback = {
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
};
|
|
static bt_scan_info_t g_bt_scan_info = {
|
false, false, 0, 0, SCAN_TYPE_AUTO,
|
};
|
|
#ifdef __cplusplus
|
extern "C" {
|
#endif
|
|
extern void register_app(GDBusProxy *proxy);
|
extern void unregister_app(GDBusProxy *proxy);
|
int gatt_set_on_adv(void);
|
static void filter_clear_transport();
|
static int remove_device(GDBusProxy *proxy);
|
|
#ifdef __cplusplus
|
}
|
#endif
|
|
extern void a2dp_sink_proxy_removed(GDBusProxy *proxy, void *user_data);
|
extern void a2dp_sink_proxy_added(GDBusProxy *proxy, void *user_data);
|
extern void a2dp_sink_property_changed(GDBusProxy *proxy, const char *name, DBusMessageIter *iter, void *user_data);
|
extern void adapter_changed(GDBusProxy *proxy, DBusMessageIter *iter, void *user_data);
|
extern void device_changed(GDBusProxy *proxy, DBusMessageIter *iter, void *user_data);
|
extern int init_avrcp_ctrl(void);
|
|
static volatile int ble_service_cnt = 0;
|
|
extern void report_avrcp_event(enum BtEvent event, void *data, int len);
|
|
static const char *agent_arguments[] = {
|
"on",
|
"off",
|
"DisplayOnly",
|
"DisplayYesNo",
|
"KeyboardDisplay",
|
"KeyboardOnly",
|
"NoInputNoOutput",
|
NULL
|
};
|
|
static const char *ad_arguments[] = {
|
"on",
|
"off",
|
"peripheral",
|
"broadcast",
|
NULL
|
};
|
|
#define BT_RECONNECT_CFG "/data/cfg/lib/bluetooth/reconnect_cfg"
|
|
int a2dp_master_save_status(char *address);
|
static int load_last_device(char *address);
|
static void save_last_device(GDBusProxy *proxy);
|
|
static void bt_bond_state_send(const char *bd_addr, const char *name, RK_BT_BOND_STATE state)
|
{
|
if(g_bt_callback.bt_bond_state_cb)
|
g_bt_callback.bt_bond_state_cb(bd_addr, name, state);
|
}
|
|
void bt_register_bond_callback(RK_BT_BOND_CALLBACK cb)
|
{
|
g_bt_callback.bt_bond_state_cb = cb;
|
}
|
|
void bt_deregister_bond_callback()
|
{
|
g_bt_callback.bt_bond_state_cb = NULL;
|
}
|
|
void bt_state_send(RK_BT_STATE state)
|
{
|
if(g_bt_callback.bt_state_cb)
|
g_bt_callback.bt_state_cb(state);
|
}
|
|
void bt_register_state_callback(RK_BT_STATE_CALLBACK cb)
|
{
|
g_bt_callback.bt_state_cb = cb;
|
}
|
|
void bt_deregister_state_callback()
|
{
|
g_bt_callback.bt_state_cb = NULL;
|
}
|
|
void ble_state_send(RK_BLE_STATE status)
|
{
|
char addr[18], name[256];
|
|
g_ble_state = status;
|
|
if(!g_bt_callback.ble_state_cb) {
|
pr_info("%s: ble_state_cb are not registered\n", __func__);
|
return;
|
}
|
|
if(!ble_is_open()) {
|
pr_info("%s: ble is close\n", __func__);
|
return;
|
}
|
|
memset(addr, 0, 18);
|
memset(name, 0, 256);
|
bt_get_device_addr_by_proxy(ble_dev, addr, 18);
|
bt_get_device_name_by_proxy(ble_dev, name, 256);
|
g_bt_callback.ble_state_cb(addr, name, status);
|
}
|
|
void ble_get_state(RK_BLE_STATE *p_state)
|
{
|
if (!p_state)
|
return;
|
|
*p_state = g_ble_state;
|
}
|
|
void ble_register_state_callback(RK_BLE_STATE_CALLBACK cb)
|
{
|
g_bt_callback.ble_state_cb = cb;
|
}
|
|
void ble_deregister_state_callback()
|
{
|
g_bt_callback.ble_state_cb = NULL;
|
}
|
|
static void bt_discovery_state_send(RK_BT_DISCOVERY_STATE state)
|
{
|
if(g_bt_callback.bt_decovery_cb) {
|
pr_info("%s: state = %d\n", __func__, state);
|
g_bt_callback.bt_decovery_cb(state);
|
}
|
}
|
|
void bt_register_discovery_callback(RK_BT_DISCOVERY_CALLBACK cb)
|
{
|
g_bt_callback.bt_decovery_cb = cb;
|
}
|
|
void bt_deregister_discovery_callback()
|
{
|
g_bt_callback.bt_decovery_cb = NULL;
|
}
|
|
void dev_found_send(GDBusProxy *proxy, RK_BT_DEV_FOUND_CALLBACK cb)
|
{
|
DBusMessageIter iter;
|
dbus_uint32_t bt_class = 0;
|
const char *address, *name;
|
short rssi = DISTANCE_VAL_INVALID;
|
|
if(!cb) {
|
pr_info("%s: cb == NULL\n", __func__);
|
return;
|
}
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) {
|
pr_info("%s: get Address failed\n", __func__);
|
return;
|
}
|
|
dbus_message_iter_get_basic(&iter, &address);
|
|
if (g_dbus_proxy_get_property(proxy, "Alias", &iter))
|
dbus_message_iter_get_basic(&iter, &name);
|
else
|
name = "unknown";
|
|
if(g_dbus_proxy_get_property(proxy, "Class", &iter))
|
dbus_message_iter_get_basic(&iter, &bt_class);
|
|
if (g_dbus_proxy_get_property(proxy, "RSSI", &iter))
|
dbus_message_iter_get_basic(&iter, &rssi);
|
|
cb(address, name, bt_class, rssi);
|
}
|
|
static void bt_dev_found_send(GDBusProxy *proxy)
|
{
|
if(!bt_is_scaning() || !g_bt_callback.bt_dev_found_cb)
|
return;
|
|
dev_found_send(proxy, g_bt_callback.bt_dev_found_cb);
|
}
|
|
void bt_register_dev_found_callback(RK_BT_DEV_FOUND_CALLBACK cb)
|
{
|
g_bt_callback.bt_dev_found_cb = cb;
|
}
|
|
void bt_deregister_dev_found_callback()
|
{
|
g_bt_callback.bt_dev_found_cb = NULL;
|
}
|
|
static void bt_name_change_send(GDBusProxy *proxy)
|
{
|
const char *address, *name;
|
DBusMessageIter iter;
|
|
if(!g_bt_callback.bt_name_change_cb)
|
return;
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) {
|
pr_info("%s: get Address failed\n", __func__);
|
return;
|
}
|
|
dbus_message_iter_get_basic(&iter, &address);
|
|
if (g_dbus_proxy_get_property(proxy, "Alias", &iter))
|
dbus_message_iter_get_basic(&iter, &name);
|
else
|
name = address;
|
|
g_bt_callback.bt_name_change_cb(address, name);
|
}
|
|
static void ble_mtu_exchange_send(GDBusProxy *proxy)
|
{
|
const char *address;
|
dbus_uint16_t mtu;
|
DBusMessageIter iter;
|
|
if(!ble_is_open() && !ble_client_is_open())
|
return;
|
|
if(!g_bt_callback.ble_mtu_cb)
|
return;
|
|
if (!g_dbus_proxy_get_property(proxy, "Address", &iter)) {
|
pr_info("%s: get Address failed\n", __func__);
|
return;
|
}
|
dbus_message_iter_get_basic(&iter, &address);
|
|
if (!g_dbus_proxy_get_property(proxy, "MTU", &iter)) {
|
pr_info("%s: get MTU failed\n", __func__);
|
return;
|
}
|
dbus_message_iter_get_basic(&iter, &mtu);
|
|
if(mtu > BT_ATT_MAX_LE_MTU || mtu < BT_ATT_DEFAULT_LE_MTU)
|
pr_err("%s: MTU exchange error(%d)\n", __func__, mtu);
|
|
g_bt_callback.ble_mtu_cb(address, mtu);
|
}
|
|
void bt_register_name_change_callback(RK_BT_NAME_CHANGE_CALLBACK cb)
|
{
|
g_bt_callback.bt_name_change_cb = cb;
|
}
|
|
void bt_deregister_name_change_callback()
|
{
|
g_bt_callback.bt_name_change_cb = NULL;
|
}
|
|
void ble_register_mtu_callback(RK_BT_MTU_CALLBACK cb)
|
{
|
g_bt_callback.ble_mtu_cb = cb;
|
}
|
|
void ble_deregister_mtu_callback()
|
{
|
g_bt_callback.ble_mtu_cb = NULL;
|
}
|
|
static void proxy_leak(gpointer data)
|
{
|
pr_info("Leaking proxy %p\n", data);
|
}
|
|
static void connect_handler(DBusConnection *connection, void *user_data)
|
{
|
bt_shell_set_prompt(PROMPT_ON);
|
}
|
|
static void disconnect_handler(DBusConnection *connection, void *user_data)
|
{
|
//bt_shell_detach();
|
|
//bt_shell_set_prompt(PROMPT_OFF);
|
|
g_list_free_full(ctrl_list, proxy_leak);
|
ctrl_list = NULL;
|
|
default_ctrl = NULL;
|
}
|
|
static void print_adapter(GDBusProxy *proxy, const char *description)
|
{
|
DBusMessageIter iter;
|
const char *address, *name;
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
|
return;
|
|
dbus_message_iter_get_basic(&iter, &address);
|
|
if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
|
dbus_message_iter_get_basic(&iter, &name);
|
else
|
name = "<unknown>";
|
|
pr_info("%s%s%sController %s %s %s\n",
|
description ? "[" : "",
|
description ? : "",
|
description ? "] " : "",
|
address, name,
|
default_ctrl &&
|
default_ctrl->proxy == proxy ?
|
"[default]" : "");
|
|
}
|
|
static void btsrc_scan_save_device(GDBusProxy *proxy, BtScanParam *param)
|
{
|
DBusMessageIter iter;
|
const char *address, *name;
|
BtDeviceInfo *device_info = NULL;
|
size_t cplen = 0;
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
|
return;
|
|
dbus_message_iter_get_basic(&iter, &address);
|
|
if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
|
dbus_message_iter_get_basic(&iter, &name);
|
else
|
name = "<unknown>";
|
|
if (param && (param->item_cnt < BT_SOURCE_SCAN_DEVICES_CNT)) {
|
device_info = &(param->devices[param->item_cnt]);
|
memset(device_info, 0, sizeof(BtDeviceInfo));
|
cplen = sizeof(device_info->name);
|
cplen = (strlen(name) > cplen) ? cplen : strlen(name);
|
memcpy(device_info->name, name, cplen);
|
memcpy(device_info->address, address, sizeof(device_info->address));
|
param->item_cnt++;
|
}
|
}
|
|
static void print_device(GDBusProxy *proxy, const char *description)
|
{
|
DBusMessageIter iter;
|
const char *address, *name;
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) {
|
pr_info("%s: can't get Address\n", __func__);
|
return;
|
}
|
|
dbus_message_iter_get_basic(&iter, &address);
|
|
if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
|
dbus_message_iter_get_basic(&iter, &name);
|
else
|
name = "<unknown>";
|
|
printf("%s%s%sDevice %s %s\n",
|
description ? "[" : "",
|
description ? : "",
|
description ? "] " : "",
|
address, name);
|
}
|
|
void print_fixed_iter(const char *label, const char *name,
|
DBusMessageIter *iter)
|
{
|
dbus_bool_t *valbool;
|
dbus_uint32_t *valu32;
|
dbus_uint16_t *valu16;
|
dbus_int16_t *vals16;
|
unsigned char *byte;
|
int len;
|
|
switch (dbus_message_iter_get_arg_type(iter)) {
|
case DBUS_TYPE_BOOLEAN:
|
dbus_message_iter_get_fixed_array(iter, &valbool, &len);
|
|
if (len <= 0)
|
return;
|
|
pr_info("%s%s:\n", label, name);
|
bt_shell_hexdump((void *)valbool, len * sizeof(*valbool));
|
|
break;
|
case DBUS_TYPE_UINT32:
|
dbus_message_iter_get_fixed_array(iter, &valu32, &len);
|
|
if (len <= 0)
|
return;
|
|
pr_info("%s%s:\n", label, name);
|
bt_shell_hexdump((void *)valu32, len * sizeof(*valu32));
|
|
break;
|
case DBUS_TYPE_UINT16:
|
dbus_message_iter_get_fixed_array(iter, &valu16, &len);
|
|
if (len <= 0)
|
return;
|
|
pr_info("%s%s:\n", label, name);
|
bt_shell_hexdump((void *)valu16, len * sizeof(*valu16));
|
|
break;
|
case DBUS_TYPE_INT16:
|
dbus_message_iter_get_fixed_array(iter, &vals16, &len);
|
|
if (len <= 0)
|
return;
|
|
pr_info("%s%s:\n", label, name);
|
bt_shell_hexdump((void *)vals16, len * sizeof(*vals16));
|
|
break;
|
case DBUS_TYPE_BYTE:
|
dbus_message_iter_get_fixed_array(iter, &byte, &len);
|
|
if (len <= 0)
|
return;
|
|
pr_info("%s%s:\n", label, name);
|
bt_shell_hexdump((void *)byte, len * sizeof(*byte));
|
|
break;
|
default:
|
return;
|
};
|
}
|
|
void print_iter(const char *label, const char *name,
|
DBusMessageIter *iter)
|
{
|
dbus_bool_t valbool;
|
dbus_uint32_t valu32;
|
dbus_uint16_t valu16;
|
dbus_int16_t vals16;
|
unsigned char byte;
|
const char *valstr;
|
DBusMessageIter subiter;
|
char *entry;
|
|
if (iter == NULL) {
|
pr_info("%s%s is nil\n", label, name);
|
return;
|
}
|
|
switch (dbus_message_iter_get_arg_type(iter)) {
|
case DBUS_TYPE_INVALID:
|
pr_info("%s%s is invalid\n", label, name);
|
break;
|
case DBUS_TYPE_STRING:
|
case DBUS_TYPE_OBJECT_PATH:
|
dbus_message_iter_get_basic(iter, &valstr);
|
pr_info("%s%s: %s\n", label, name, valstr);
|
if (!strncmp(name, "Status", 6)) {
|
if (strstr(valstr, "playing"))
|
report_avrcp_event(BT_EVENT_START_PLAY, NULL, 0);
|
else if (strstr(valstr, "paused"))
|
report_avrcp_event(BT_EVENT_PAUSE_PLAY, NULL, 0);
|
else if (strstr(valstr, "stopped"))
|
report_avrcp_event(BT_EVENT_STOP_PLAY, NULL, 0);
|
}
|
break;
|
case DBUS_TYPE_BOOLEAN:
|
dbus_message_iter_get_basic(iter, &valbool);
|
pr_info("%s%s: %s\n", label, name,
|
valbool == TRUE ? "yes" : "no");
|
break;
|
case DBUS_TYPE_UINT32:
|
dbus_message_iter_get_basic(iter, &valu32);
|
pr_info("%s%s: 0x%08x\n", label, name, valu32);
|
break;
|
case DBUS_TYPE_UINT16:
|
dbus_message_iter_get_basic(iter, &valu16);
|
pr_info("%s%s: 0x%04x\n", label, name, valu16);
|
break;
|
case DBUS_TYPE_INT16:
|
dbus_message_iter_get_basic(iter, &vals16);
|
pr_info("%s%s: %d\n", label, name, vals16);
|
break;
|
case DBUS_TYPE_BYTE:
|
dbus_message_iter_get_basic(iter, &byte);
|
pr_info("%s%s: 0x%02x\n", label, name, byte);
|
break;
|
case DBUS_TYPE_VARIANT:
|
dbus_message_iter_recurse(iter, &subiter);
|
print_iter(label, name, &subiter);
|
break;
|
case DBUS_TYPE_ARRAY:
|
dbus_message_iter_recurse(iter, &subiter);
|
|
if (dbus_type_is_fixed(
|
dbus_message_iter_get_arg_type(&subiter))) {
|
print_fixed_iter(label, name, &subiter);
|
break;
|
}
|
|
while (dbus_message_iter_get_arg_type(&subiter) !=
|
DBUS_TYPE_INVALID) {
|
print_iter(label, name, &subiter);
|
dbus_message_iter_next(&subiter);
|
}
|
break;
|
case DBUS_TYPE_DICT_ENTRY:
|
dbus_message_iter_recurse(iter, &subiter);
|
entry = g_strconcat(name, " Key", NULL);
|
print_iter(label, entry, &subiter);
|
g_free(entry);
|
|
entry = g_strconcat(name, " Value", NULL);
|
dbus_message_iter_next(&subiter);
|
print_iter(label, entry, &subiter);
|
g_free(entry);
|
break;
|
default:
|
pr_info("%s%s has unsupported type\n", label, name);
|
break;
|
}
|
}
|
|
void print_property(GDBusProxy *proxy, const char *name)
|
{
|
DBusMessageIter iter;
|
|
if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
|
return;
|
|
print_iter("\t", name, &iter);
|
}
|
|
static void print_uuid(const char *uuid)
|
{
|
const char *text;
|
|
text = bt_uuidstr_to_str(uuid);
|
if (text) {
|
char str[26];
|
unsigned int n;
|
|
str[sizeof(str) - 1] = '\0';
|
|
n = snprintf(str, sizeof(str), "%s", text);
|
if (n > sizeof(str) - 1) {
|
str[sizeof(str) - 2] = '.';
|
str[sizeof(str) - 3] = '.';
|
if (str[sizeof(str) - 4] == ' ')
|
str[sizeof(str) - 4] = '.';
|
|
n = sizeof(str) - 1;
|
}
|
|
pr_info("\tUUID: %s%*c(%s)\n", str, 26 - n, ' ', uuid);
|
} else
|
pr_info("\tUUID: %*c(%s)\n", 26, ' ', uuid);
|
}
|
|
static void print_uuids(GDBusProxy *proxy)
|
{
|
DBusMessageIter iter, value;
|
|
if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
|
return;
|
|
dbus_message_iter_recurse(&iter, &value);
|
|
while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
|
const char *uuid;
|
|
dbus_message_iter_get_basic(&value, &uuid);
|
|
print_uuid(uuid);
|
|
dbus_message_iter_next(&value);
|
}
|
}
|
|
static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
|
{
|
DBusMessageIter iter;
|
const char *adapter, *path;
|
|
if (!master)
|
return FALSE;
|
|
if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
|
return FALSE;
|
|
dbus_message_iter_get_basic(&iter, &adapter);
|
path = g_dbus_proxy_get_path(master);
|
|
if (!strcmp(path, adapter))
|
return TRUE;
|
|
return FALSE;
|
}
|
|
static GDBusProxy * service_is_child(GDBusProxy *service)
|
{
|
DBusMessageIter iter;
|
const char *device;
|
|
if (g_dbus_proxy_get_property(service, "Device", &iter) == FALSE)
|
return NULL;
|
|
dbus_message_iter_get_basic(&iter, &device);
|
|
if (!default_ctrl)
|
return NULL;
|
|
return g_dbus_proxy_lookup(default_ctrl->devices, NULL, device,
|
"org.bluez.Device1");
|
}
|
|
static struct adapter *find_parent(GDBusProxy *device)
|
{
|
GList *list;
|
|
for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
|
struct adapter *adapter = (struct adapter *)list->data;
|
|
if (device_is_child(device, adapter->proxy) == TRUE)
|
return adapter;
|
}
|
return NULL;
|
}
|
|
#define SERVER_CLASS_TELEPHONY (1U << (22))
|
#define SERVER_CLASS_AUDIO (1U << (21))
|
#define DEVICE_CLASS_SHIFT 8
|
#define DEVICE_CLASS_MASK 0x3f
|
#define DEVICE_CLASS_PHONE 2
|
#define DEVICE_CLASS_AUDIO 4
|
|
enum BT_Device_Class dist_dev_class(GDBusProxy *proxy)
|
{
|
DBusMessageIter iter;
|
const char *address_type = NULL;
|
const char *address = NULL;
|
const char *alias = NULL;
|
dbus_uint32_t cod;
|
|
if (g_dbus_proxy_get_property(proxy, "AddressType", &iter)) {
|
dbus_message_iter_get_basic(&iter, &address_type);
|
pr_info("%s addressType:%s\n", __func__, address_type);
|
|
if (g_dbus_proxy_get_property(proxy, "Alias", &iter)) {
|
dbus_message_iter_get_basic(&iter, &alias);
|
pr_info("%s Alias: %s\n", __func__, alias);
|
}
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter)) {
|
dbus_message_iter_get_basic(&iter, &address);
|
pr_info("%s address: %s\n", __func__, address);
|
}
|
|
if (!strcmp(address_type, "random")) {
|
pr_info("%s The device is ble(random)\n", __func__);
|
return BT_BLE_DEVICE;
|
}
|
|
if (!strcmp(address_type, "public")) {
|
if (g_dbus_proxy_get_property(proxy, "Class", &iter) == FALSE) {
|
pr_info("%s The device is ble(public)\n", __func__);
|
return BT_BLE_DEVICE;
|
} else {
|
bool is_phone, is_audio;
|
|
dbus_message_iter_get_basic(&iter, &cod);
|
pr_info("%s class: 0x%x\n", __func__, cod);
|
|
is_phone = ((cod >> DEVICE_CLASS_SHIFT) & DEVICE_CLASS_MASK) == DEVICE_CLASS_PHONE ? true : false;
|
is_audio = ((cod >> DEVICE_CLASS_SHIFT) & DEVICE_CLASS_MASK) == DEVICE_CLASS_AUDIO ? true : false;
|
|
if ((cod & SERVER_CLASS_TELEPHONY) && is_phone) {
|
pr_info("%s The device is source\n", __func__);
|
return BT_SOURCE_DEVICE;
|
}
|
|
if ((cod & SERVER_CLASS_AUDIO) && is_audio) {
|
pr_info("%s The device is sink\n", __func__);
|
return BT_SINK_DEVICE;
|
}
|
|
if (is_phone || is_audio) {
|
DBusMessageIter value;
|
const char *text;
|
char str[26];
|
unsigned int n;
|
const char *uuid;
|
enum BT_Device_Class ret = BT_IDLE;
|
|
if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
|
return BT_IDLE;
|
|
dbus_message_iter_recurse(&iter, &value);
|
|
while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
|
dbus_message_iter_get_basic(&value, &uuid);
|
|
text = bt_uuidstr_to_str(uuid);
|
if (text) {
|
str[sizeof(str) - 1] = '\0';
|
|
n = snprintf(str, sizeof(str), "%s", text);
|
if (n > sizeof(str) - 1) {
|
str[sizeof(str) - 2] = '.';
|
str[sizeof(str) - 3] = '.';
|
if (str[sizeof(str) - 4] == ' ')
|
str[sizeof(str) - 4] = '.';
|
|
n = sizeof(str) - 1;
|
}
|
|
if (strstr(str, "Audio Sink")) {
|
ret = BT_SINK_DEVICE;
|
pr_info("%s The device is sink\n", __func__);
|
break;
|
} else if (strstr(str, "Audio Source")) {
|
ret = BT_SOURCE_DEVICE;
|
pr_info("%s The device is source\n", __func__);
|
break;
|
}
|
}
|
|
dbus_message_iter_next(&value);
|
}
|
|
return ret;
|
}
|
}
|
}
|
}
|
|
pr_info("%s The device is unknow\n", __func__);
|
return BT_IDLE;
|
}
|
|
static void set_default_device(GDBusProxy *proxy, const char *attribute)
|
{
|
char *desc = NULL;
|
DBusMessageIter iter;
|
const char *path;
|
|
pr_info("%s: proxy is %s\n", __func__, proxy ? "non-null" : "null");
|
pr_info("%s: default_dev %p, proxy: %p\n", __func__, default_dev, proxy);
|
|
if ((proxy != NULL) && (default_dev != NULL) && (default_dev != proxy)) {
|
pr_info("check proxy: ref: %d:%d\n", *((unsigned int *)proxy), *((unsigned int *)default_dev));
|
return;
|
}
|
|
default_dev = proxy;
|
|
if (proxy == NULL) {
|
default_attr = NULL;
|
goto done;
|
}
|
|
save_last_device(proxy);
|
|
if (!g_dbus_proxy_get_property(proxy, "Alias", &iter)) {
|
if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
|
goto done;
|
}
|
|
path = g_dbus_proxy_get_path(proxy);
|
|
dbus_message_iter_get_basic(&iter, &desc);
|
desc = g_strdup_printf(COLOR_BLUE "[%s%s%s]" COLOR_OFF "# ", desc,
|
attribute ? ":" : "",
|
attribute ? attribute + strlen(path) : "");
|
done:
|
bt_shell_set_prompt(desc ? desc : PROMPT_ON);
|
g_free(desc);
|
}
|
|
static void ble_connected_handler(GDBusProxy *proxy)
|
{
|
if(!ble_is_open()) {
|
pr_info("%s: ble is close\n", __func__);
|
return;
|
}
|
|
if(ble_dev) {
|
pr_info("%s: ble connection already exists\n", __func__);
|
return;
|
}
|
|
ble_dev = proxy;
|
pr_info("%s: ble_dev = %p\n", __func__, ble_dev);
|
ble_state_send(RK_BLE_STATE_CONNECT);
|
}
|
|
static void ble_disconnect_handler()
|
{
|
if(!ble_is_open()) {
|
pr_info("%s: ble is close\n", __func__);
|
return;
|
}
|
|
if(!ble_dev) {
|
pr_info("%s: ble_dev is NULL\n", __func__);
|
return;
|
}
|
|
ble_state_send(RK_BLE_STATE_DISCONNECT);
|
|
ble_dev = NULL;
|
ble_service_cnt = 0;
|
pr_info("%s: ble disconneced\n", __func__);
|
gatt_set_on_adv();
|
}
|
|
static void device_added(GDBusProxy *proxy)
|
{
|
DBusMessageIter iter;
|
struct adapter *adapter = find_parent(proxy);
|
char dev_addr[18], dev_name[256];
|
dbus_bool_t paired = FALSE;
|
dbus_bool_t connected = FALSE;
|
enum BT_Device_Class bdc;
|
|
if (!adapter) {
|
/* TODO: Error */
|
return;
|
}
|
|
adapter->devices = g_list_append(adapter->devices, proxy);
|
//print_device(proxy, COLORED_NEW);
|
bt_shell_set_env(g_dbus_proxy_get_path(proxy), proxy);
|
pr_info("%s: path: %s\n", __func__, g_dbus_proxy_get_path(proxy));
|
|
bt_dev_found_send(proxy);
|
|
if (g_dbus_proxy_get_property(proxy, "Connected", &iter))
|
dbus_message_iter_get_basic(&iter, &connected);
|
|
bdc = dist_dev_class(proxy);
|
if(bdc == BT_SINK_DEVICE || bdc == BT_SOURCE_DEVICE) {
|
if (g_dbus_proxy_get_property(proxy, "Paired", &iter) == TRUE) {
|
dbus_message_iter_get_basic(&iter, &paired);
|
if (!paired && connected) {
|
bt_get_device_addr_by_proxy(proxy, dev_addr, 18);
|
bt_get_device_name_by_proxy(proxy, dev_name, 256);
|
bt_bond_state_send(dev_addr, dev_name, RK_BT_BOND_STATE_BONDING);
|
}
|
}
|
|
if (default_dev)
|
return;
|
|
if (connected)
|
set_default_device(proxy, NULL);
|
} else {
|
if(connected)
|
ble_connected_handler(proxy);
|
}
|
}
|
|
static struct adapter *find_ctrl(GList *source, const char *path);
|
|
static struct adapter *adapter_new(GDBusProxy *proxy)
|
{
|
struct adapter *adapter = (struct adapter *)g_malloc0(sizeof(struct adapter));
|
pr_info("=== %s ===\n", __func__);
|
|
ctrl_list = g_list_append(ctrl_list, adapter);
|
|
if (!default_ctrl)
|
default_ctrl = adapter;
|
|
return adapter;
|
}
|
|
static void adapter_added(GDBusProxy *proxy)
|
{
|
struct adapter *adapter;
|
char hostname_buf[HOSTNAME_MAX_LEN];
|
|
pr_info("=== %s ===\n", __func__);
|
|
adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
|
if (!adapter)
|
adapter = adapter_new(proxy);
|
|
adapter->proxy = proxy;
|
print_adapter(proxy, COLORED_NEW);
|
|
check_open:
|
if(!bt_is_open()) {
|
usleep(20 * 1000);
|
goto check_open;
|
}
|
|
if (g_bt_content && g_bt_content->bt_name) {
|
pr_info("%s: bt_name: %s\n", __func__, g_bt_content->bt_name);
|
rk_bt_set_device_name(g_bt_content->bt_name);
|
} else {
|
bt_gethostname(hostname_buf, sizeof(hostname_buf));
|
pr_info("%s: bt_name: %s\n", __func__, hostname_buf);
|
rk_bt_set_device_name(hostname_buf);
|
}
|
|
msleep(50);
|
exec_command_system("hciconfig hci0 piscan");
|
|
//bt_state_send(RK_BT_STATE_ON);
|
|
pr_info("%s: bt check open ok\n", __func__);
|
}
|
|
static void ad_manager_added(GDBusProxy *proxy)
|
{
|
struct adapter *adapter;
|
adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
|
if (!adapter)
|
adapter = adapter_new(proxy);
|
|
adapter->ad_proxy = proxy;
|
}
|
|
static void le_proxy_added(GDBusProxy *proxy)
|
{
|
enum BT_Device_Class bdc;
|
|
if(!ble_is_open())
|
return;
|
|
bdc = dist_dev_class(proxy);
|
//if(bdc == BT_SINK_DEVICE || bdc == BT_SOURCE_DEVICE) {
|
// pr_info("%s: bdc(%d) != ble\n", __func__, bdc);
|
// return;
|
//}
|
|
pr_info("%s: ble_service_cnt = %d\n", __func__, ble_service_cnt);
|
if (ble_service_cnt == 0) {
|
if(!ble_dev) {
|
ble_dev = proxy;
|
ble_state_send(RK_BLE_STATE_CONNECT);
|
pr_info("%s: ble conneced, ble_dev = %p\n", __func__, ble_dev);
|
}
|
}
|
|
ble_service_cnt++;
|
}
|
|
static void proxy_added(GDBusProxy *proxy, void *user_data)
|
{
|
const char *interface;
|
|
interface = g_dbus_proxy_get_interface(proxy);
|
pr_info("BT Enter: proxy_added: %s\n", interface);
|
|
if (!strcmp(interface, "org.bluez.Device1")) {
|
device_added(proxy);
|
} else if (!strcmp(interface, "org.bluez.Adapter1")) {
|
adapter_added(proxy);
|
} else if (!strcmp(interface, "org.bluez.AgentManager1")) {
|
if (!agent_manager) {
|
agent_manager = proxy;
|
|
if (auto_register_agent &&
|
!bt_shell_get_env("NON_INTERACTIVE")) {
|
agent_register(dbus_conn, agent_manager,
|
auto_register_agent);
|
}
|
}
|
} else if (!strcmp(interface, "org.bluez.GattService1")) {
|
GDBusProxy *le_proxy = service_is_child(proxy);
|
if (le_proxy != NULL) {
|
gatt_add_service(proxy);
|
le_proxy_added(le_proxy);
|
}
|
} else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
|
gatt_add_characteristic(proxy);
|
} else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
|
gatt_add_descriptor(proxy);
|
} else if (!strcmp(interface, "org.bluez.GattManager1")) {
|
//gatt_add_manager(proxy);
|
register_app(proxy);
|
} else if (!strcmp(interface, "org.bluez.LEAdvertisingManager1")) {
|
ad_manager_added(proxy);
|
} else if (!strcmp(interface, "org.bluez.MediaTransport1")) {
|
a2dp_master_event_send(BT_SOURCE_EVENT_CONNECTED, rsd.addr, rsd.name);
|
a2dp_master_save_status(rsd.addr);
|
}
|
|
if (bt_sink_is_open()) {
|
if ((!strcmp(interface, "org.bluez.MediaPlayer1")) ||
|
(!strcmp(interface, "org.bluez.MediaFolder1")) ||
|
(!strcmp(interface, "org.bluez.MediaItem1")))
|
a2dp_sink_proxy_added(proxy, user_data);
|
|
if (!strcmp(interface, "org.bluez.Device1")) {
|
if ((dist_dev_class(proxy) == BT_SOURCE_DEVICE))
|
a2dp_sink_proxy_added(proxy, user_data);
|
}
|
|
if (!strcmp(interface, "org.bluez.Adapter1")) {
|
a2dp_sink_proxy_added(proxy, user_data);
|
}
|
}
|
|
pr_info("BT Exit: proxy_added: %s\n", interface);
|
}
|
|
void set_default_attribute(GDBusProxy *proxy)
|
{
|
//const char *path;
|
|
default_attr = proxy;
|
|
//path = g_dbus_proxy_get_path(proxy);
|
|
//set_default_device(default_dev, path);
|
}
|
|
static void device_removed(GDBusProxy *proxy)
|
{
|
char dev_addr[18], dev_name[256];
|
dbus_bool_t paired;
|
DBusMessageIter iter;
|
|
pr_info("%s: path: %s\n", __func__, g_dbus_proxy_get_path(proxy));
|
struct adapter *adapter = (struct adapter *)find_parent(proxy);
|
if (!adapter) {
|
pr_info("%s: adapter is NULL\n", __func__);
|
/* TODO: Error */
|
return;
|
}
|
|
if (g_dbus_proxy_get_property(proxy, "Paired", &iter) == TRUE) {
|
dbus_message_iter_get_basic(&iter, &paired);
|
if (paired) {
|
bt_get_device_addr_by_proxy(proxy, dev_addr, 18);
|
bt_get_device_name_by_proxy(proxy, dev_name, 256);
|
pr_info("%s: addr: %s, name: %s [%d]\n", __func__, dev_addr, dev_name, paired);
|
bt_bond_state_send(dev_addr, dev_name, RK_BT_BOND_STATE_NONE);
|
}
|
}
|
|
adapter->devices = g_list_remove(adapter->devices, proxy);
|
|
//print_device(proxy, COLORED_DEL);
|
bt_shell_set_env(g_dbus_proxy_get_path(proxy), NULL);
|
|
if (default_dev == proxy)
|
set_default_device(NULL, NULL);
|
else if(ble_dev == proxy)
|
ble_disconnect_handler();
|
}
|
|
static void adapter_removed(GDBusProxy *proxy)
|
{
|
GList *ll;
|
|
for (ll = g_list_first(ctrl_list); ll; ll = g_list_next(ll)) {
|
struct adapter *adapter = (struct adapter *)ll->data;
|
|
if (adapter->proxy == proxy) {
|
print_adapter(proxy, COLORED_DEL);
|
bt_shell_set_env(g_dbus_proxy_get_path(proxy), NULL);
|
|
if (default_ctrl && default_ctrl->proxy == proxy) {
|
default_ctrl = NULL;
|
set_default_device(NULL, NULL);
|
}
|
|
ctrl_list = g_list_remove_link(ctrl_list, ll);
|
g_list_free(adapter->devices);
|
g_free(adapter);
|
g_list_free(ll);
|
return;
|
}
|
}
|
}
|
|
static void le_proxy_removed(GDBusProxy *proxy)
|
{
|
char *proxy_path, *ble_dev_path;
|
|
if(!ble_is_open())
|
return;
|
|
if(!ble_dev) {
|
pr_info("%s: ble_dev == NULL\n", __func__);
|
return;
|
}
|
|
proxy_path = g_dbus_proxy_get_path(proxy);
|
ble_dev_path = g_dbus_proxy_get_path(ble_dev);
|
if(!g_str_has_prefix(proxy_path, ble_dev_path)) {
|
pr_info("%s: proxy_path = %s, ble_dev_path = %s\n", __func__, proxy_path, ble_dev_path);
|
return;
|
}
|
|
ble_service_cnt--;
|
pr_info("%s: ble_service_cnt = %d\n", __func__, ble_service_cnt);
|
if (ble_service_cnt == 0) {
|
ble_disconnect_handler();
|
ble_dev = NULL;
|
}
|
}
|
|
static void proxy_removed(GDBusProxy *proxy, void *user_data)
|
{
|
const char *interface;
|
|
interface = g_dbus_proxy_get_interface(proxy);
|
pr_info("BT Enter: proxy_removed: %s\n", interface);
|
pr_info("%s: path: %s\n", __func__, g_dbus_proxy_get_path(proxy));
|
|
if (!strcmp(interface, "org.bluez.Device1")) {
|
device_removed(proxy);
|
} else if (!strcmp(interface, "org.bluez.Adapter1")) {
|
adapter_removed(proxy);
|
} else if (!strcmp(interface, "org.bluez.AgentManager1")) {
|
if (agent_manager == proxy) {
|
agent_manager = NULL;
|
if (auto_register_agent) {
|
agent_unregister(dbus_conn, NULL);
|
}
|
}
|
} else if (!strcmp(interface, "org.bluez.GattService1")) {
|
gatt_remove_service(proxy);
|
|
if (default_attr == proxy)
|
set_default_attribute(NULL);
|
|
le_proxy_removed(proxy);
|
} else if (!strcmp(interface, "org.bluez.GattCharacteristic1")) {
|
gatt_remove_characteristic(proxy);
|
|
if (default_attr == proxy)
|
set_default_attribute(NULL);
|
} else if (!strcmp(interface, "org.bluez.GattDescriptor1")) {
|
gatt_remove_descriptor(proxy);
|
|
if (default_attr == proxy)
|
set_default_attribute(NULL);
|
} else if (!strcmp(interface, "org.bluez.GattManager1")) {
|
//gatt_remove_manager(proxy);
|
unregister_app(proxy);
|
} else if (!strcmp(interface, "org.bluez.LEAdvertisingManager1")) {
|
ad_unregister(dbus_conn, NULL);
|
} else if (!strcmp(interface, "org.bluez.MediaTransport1")) {
|
//a2dp_master_save_status(NULL);
|
//a2dp_master_event_send(BT_SOURCE_EVENT_DISCONNECTED, NULL, NULL);
|
}
|
|
if (bt_sink_is_open())
|
a2dp_sink_proxy_removed(proxy, user_data);
|
pr_info("BT Exit: proxy_removed: %s\n", interface);
|
}
|
|
static struct adapter *find_ctrl(GList *source, const char *path)
|
{
|
GList *list;
|
|
for (list = g_list_first(source); list; list = g_list_next(list)) {
|
struct adapter *adapter = (struct adapter *)list->data;
|
|
if (!strcasecmp(g_dbus_proxy_get_path(adapter->proxy), path))
|
return adapter;
|
}
|
|
return NULL;
|
}
|
|
static void device_paired_process(GDBusProxy *proxy,
|
DBusMessageIter *iter, char *dev_addr)
|
{
|
dbus_bool_t valbool = FALSE;
|
char dev_name[256];
|
|
bt_get_device_name_by_proxy(proxy, dev_name, 256);
|
|
dbus_message_iter_get_basic(iter, &valbool);
|
if(valbool)
|
bt_bond_state_send(dev_addr, dev_name, RK_BT_BOND_STATE_BONDED);
|
else
|
bt_bond_state_send(dev_addr, dev_name, RK_BT_BOND_STATE_NONE);
|
}
|
|
static void source_connected_handler(GDBusProxy *proxy, enum BT_Device_Class bdc, dbus_bool_t connected)
|
{
|
DBusMessageIter iter;
|
DBusMessageIter addr_iter;
|
const char *address = NULL;
|
const char *name = NULL;
|
|
if (!bt_source_is_open() || bdc != BT_SINK_DEVICE)
|
return;
|
|
if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
|
dbus_message_iter_get_basic(&iter, &name);
|
else
|
pr_info("%s: can't get remote device name\n", __func__);
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &addr_iter) == TRUE)
|
dbus_message_iter_get_basic(&addr_iter, &address);
|
else
|
pr_info("%s: can't get remote device address\n", __func__);
|
|
pr_info("%s thread tid = %lu\n", __func__, pthread_self());
|
memset(&rsd, 0, sizeof(struct remote_sink_device));
|
strcpy(rsd.addr, address);
|
strcpy(rsd.name, name);
|
|
pr_info("%s: connected: %d, rsd addr: %s, name: %s.\n", __func__, connected, rsd.addr, rsd.name);
|
|
if ((connected == FALSE) && (g_device_state == BT_SOURCE_EVENT_CONNECTED)) {
|
a2dp_master_save_status(NULL);
|
a2dp_master_event_send(BT_SOURCE_EVENT_DISCONNECTED, address, name);
|
}
|
}
|
|
static void ble_client_connected_handler(GDBusProxy *proxy, dbus_bool_t connected)
|
{
|
if(!ble_client_is_open())
|
return;
|
|
if(connected) {
|
if(ble_dev) {
|
pr_info("%s: ble connection already exists\n", __func__);
|
return;
|
}
|
|
ble_dev = proxy;
|
gatt_client_state_send(RK_BLE_CLIENT_STATE_CONNECT);
|
pr_info("%s: ble client conneced, ble_dev = %p\n", __func__, ble_dev);
|
} else {
|
if(!ble_dev) {
|
pr_info("%s: ble_dev is NULL\n", __func__);
|
return;
|
}
|
|
if(ble_dev != proxy) {
|
pr_info("%s: ble_dev(%p) != proxy(%p)\n", __func__, ble_dev, proxy);
|
return;
|
}
|
|
gatt_client_state_send(RK_BLE_CLIENT_STATE_DISCONNECT);
|
ble_dev = NULL;
|
pr_info("%s: ble client disconneced\n", __func__);
|
}
|
}
|
|
static void device_connected_handler(GDBusProxy *proxy,
|
DBusMessageIter *iter, void *user_data)
|
{
|
dbus_bool_t connected = false;
|
enum BT_Device_Class bdc;
|
|
dbus_message_iter_get_basic(iter, &connected);
|
|
bdc = dist_dev_class(proxy);
|
if(bdc == BT_SOURCE_DEVICE || bdc == BT_SINK_DEVICE) {
|
if (connected && default_dev == NULL)
|
set_default_device(proxy, NULL);
|
else if (!connected && default_dev == proxy)
|
set_default_device(NULL, NULL);
|
|
source_connected_handler(proxy, bdc, connected);
|
|
//bt_sink
|
if (bt_sink_is_open() && bdc == BT_SOURCE_DEVICE)
|
device_changed(proxy, iter, user_data);
|
} else if(bdc == BT_BLE_DEVICE) {
|
if(ble_is_open()) {
|
if(connected) {
|
ble_connected_handler(proxy);
|
return;
|
}
|
|
if(ble_dev != proxy)
|
pr_info("%s: ble_dev(%p) != proxy(%p)\n", __func__, ble_dev, proxy);
|
|
if(!connected && ble_dev == proxy) {
|
const char *type = NULL;
|
|
if (g_dbus_proxy_get_property(proxy, "AddressType", iter)) {
|
dbus_message_iter_get_basic(iter, &type);
|
pr_info("%s: AddressType = %s\n", __func__, type);
|
if(!strcmp(type, "public"))
|
remove_device(proxy);
|
}
|
}
|
} else {
|
ble_client_connected_handler(proxy, connected);
|
}
|
}
|
}
|
|
static void source_reconnect_handler(GDBusProxy *proxy, char *dev_addr)
|
{
|
pthread_t tid;
|
enum BT_Device_Class cod;
|
|
if(!g_bt_source_info.is_reconnected)
|
return;
|
|
if(!strcmp(g_bt_source_info.reconnect_address, dev_addr)) {
|
cod = dist_dev_class(proxy);
|
if(cod != BT_SINK_DEVICE) {
|
pr_info("%s: find reconnect device(%s), but cod(%d) != sink\n", __func__, dev_addr, cod);
|
return;
|
}
|
|
source_set_reconnect_tag(false);
|
pr_info("%s: reconnect device = %s\n", __func__, dev_addr);
|
a2dp_master_event_send(BT_SOURCE_EVENT_AUTO_RECONNECTING, dev_addr, dev_addr);
|
a2dp_master_connect(dev_addr);
|
}
|
}
|
|
static void source_avrcp_keycode_handler(GDBusProxy *proxy, DBusMessageIter *iter)
|
{
|
dbus_uint32_t keycode;
|
|
dbus_message_iter_get_basic(iter, &keycode);
|
switch(keycode) {
|
case AVC_PLAY:
|
a2dp_master_event_send(BT_SOURCE_EVENT_RC_PLAY, NULL, NULL);
|
break;
|
case AVC_PAUSE:
|
a2dp_master_event_send(BT_SOURCE_EVENT_RC_PAUSE, NULL, NULL);
|
break;
|
case AVC_STOP:
|
a2dp_master_event_send(BT_SOURCE_EVENT_RC_STOP, NULL, NULL);
|
break;
|
case AVC_VOLUME_UP:
|
a2dp_master_event_send(BT_SOURCE_EVENT_RC_VOL_UP, NULL, NULL);
|
break;
|
case AVC_VOLUME_DOWN:
|
a2dp_master_event_send(BT_SOURCE_EVENT_RC_VOL_DOWN, NULL, NULL);
|
break;
|
case AVC_FORWARD:
|
a2dp_master_event_send(BT_SOURCE_EVENT_RC_FORWARD, NULL, NULL);
|
break;
|
case AVC_BACKWARD:
|
a2dp_master_event_send(BT_SOURCE_EVENT_RC_BACKWARD, NULL, NULL);
|
break;
|
default:
|
break;
|
}
|
}
|
|
static void property_changed(GDBusProxy *proxy, const char *name,
|
DBusMessageIter *iter, void *user_data)
|
{
|
const char *interface;
|
struct adapter *ctrl;
|
|
interface = g_dbus_proxy_get_interface(proxy);
|
pr_info("BT Enter: property_changed: %s\n", interface);
|
|
if (!strcmp(interface, "org.bluez.Device1")) {
|
if (default_ctrl && device_is_child(proxy,
|
default_ctrl->proxy) == TRUE) {
|
DBusMessageIter addr_iter;
|
char *str;
|
char dev_addr[18];
|
|
bt_get_device_addr_by_proxy(proxy, dev_addr, 18);
|
|
if (strcmp(name, "Paired") == 0)
|
device_paired_process(proxy, iter, dev_addr);
|
|
if (strcmp(name, "Connected") == 0)
|
device_connected_handler(proxy, iter, user_data);
|
|
if(strcmp(name, "RSSI") == 0)
|
source_reconnect_handler(proxy, dev_addr);
|
|
if(strcmp(name, "Alias") == 0)
|
bt_name_change_send(proxy);
|
|
if(strcmp(name, "MTU") == 0)
|
ble_mtu_exchange_send(proxy);
|
}
|
} else if (!strcmp(interface, "org.bluez.Adapter1")) {
|
DBusMessageIter addr_iter;
|
char *str;
|
|
if (g_dbus_proxy_get_property(proxy, "Address",
|
&addr_iter) == TRUE) {
|
const char *address;
|
|
dbus_message_iter_get_basic(&addr_iter, &address);
|
str = g_strdup_printf("[" COLORED_CHG
|
"] Controller %s ", address);
|
} else
|
str = g_strdup("");
|
|
if (!strcmp(name, "Powered"))
|
adapter_changed(proxy, iter, user_data);
|
|
if (!strcmp(name, "Discovering")) {
|
dbus_bool_t val;
|
dbus_message_iter_get_basic(iter, &val);
|
pr_info("Adapter Discovering changed to %s", val ? "TRUE" : "FALSE");
|
if (!val) {
|
g_bt_scan_info.is_scaning = false;
|
filter_clear_transport();
|
bt_discovery_state_send(RK_BT_DISC_STOPPED_BY_USER);
|
}
|
}
|
|
print_iter(str, name, iter);
|
g_free(str);
|
} else if (!strcmp(interface, "org.bluez.LEAdvertisingManager1")) {
|
DBusMessageIter addr_iter;
|
char *str;
|
|
ctrl = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
|
if (!ctrl)
|
return;
|
|
if (g_dbus_proxy_get_property(ctrl->proxy, "Address",
|
&addr_iter) == TRUE) {
|
const char *address;
|
|
dbus_message_iter_get_basic(&addr_iter, &address);
|
str = g_strdup_printf("[" COLORED_CHG
|
"] Controller %s ",
|
address);
|
} else
|
str = g_strdup("");
|
|
print_iter(str, name, iter);
|
g_free(str);
|
}else if (!strcmp(interface, "org.bluez.GattCharacteristic1")
|
|| !strcmp(interface, "org.bluez.GattDescriptor1")) {
|
char *str;
|
|
str = g_strdup_printf("[" COLORED_CHG "] Attribute %s ",
|
g_dbus_proxy_get_path(proxy));
|
|
print_iter(str, name, iter);
|
g_free(str);
|
|
if(!strcmp(name, "Value"))
|
gatt_client_recv_data_send(proxy, iter);
|
} else if (!strcmp(interface, "org.bluez.MediaPlayer1")) {
|
if (!strcmp(name, "KeyCode"))
|
source_avrcp_keycode_handler(proxy, iter);
|
}
|
|
if (bt_sink_is_open())
|
a2dp_sink_property_changed(proxy, name, iter, user_data);
|
|
pr_info("BT Exit: property_changed: %s\n", interface);
|
}
|
|
static void message_handler(DBusConnection *connection,
|
DBusMessage *message, void *user_data)
|
{
|
pr_info("[SIGNAL] %s.%s\n", dbus_message_get_interface(message),
|
dbus_message_get_member(message));
|
}
|
|
static struct adapter *find_ctrl_by_address(GList *source, const char *address)
|
{
|
GList *list;
|
|
for (list = g_list_first(source); list; list = g_list_next(list)) {
|
struct adapter *adapter = (struct adapter *)list->data;
|
DBusMessageIter iter;
|
const char *str;
|
|
if (g_dbus_proxy_get_property(adapter->proxy,
|
"Address", &iter) == FALSE)
|
continue;
|
|
dbus_message_iter_get_basic(&iter, &str);
|
|
if (!strcasecmp(str, address))
|
return adapter;
|
}
|
|
return NULL;
|
}
|
|
static GDBusProxy *find_proxy_by_address(GList *source, const char *address)
|
{
|
GList *list;
|
|
for (list = g_list_first(source); list; list = g_list_next(list)) {
|
GDBusProxy *proxy = (GDBusProxy *)list->data;
|
DBusMessageIter iter;
|
const char *str;
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
|
continue;
|
|
dbus_message_iter_get_basic(&iter, &str);
|
if (!strcasecmp(str, address))
|
return proxy;
|
}
|
|
return NULL;
|
}
|
|
static gboolean check_default_ctrl(void)
|
{
|
if (!default_ctrl) {
|
pr_info("%s: No default controller available\n", __func__);
|
return FALSE;
|
}
|
|
return TRUE;
|
}
|
|
static gboolean parse_argument(int argc, char *argv[], const char **arg_table,
|
const char *msg, dbus_bool_t *value,
|
const char **option)
|
{
|
const char **opt;
|
|
if (!strcmp(argv[1], "on") || !strcmp(argv[1], "yes")) {
|
*value = TRUE;
|
if (option)
|
*option = "";
|
return TRUE;
|
}
|
|
if (!strcmp(argv[1], "off") || !strcmp(argv[1], "no")) {
|
*value = FALSE;
|
return TRUE;
|
}
|
|
for (opt = arg_table; opt && *opt; opt++) {
|
if (strcmp(argv[1], *opt) == 0) {
|
*value = TRUE;
|
*option = *opt;
|
return TRUE;
|
}
|
}
|
|
pr_info("Invalid argument %s\n", argv[1]);
|
return FALSE;
|
}
|
|
static void cmd_list(int argc, char *argv[])
|
{
|
GList *list;
|
|
for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
|
struct adapter *adapter = (struct adapter *)list->data;
|
print_adapter(adapter->proxy, NULL);
|
}
|
}
|
|
static void cmd_show(int argc, char *argv[])
|
{
|
struct adapter *adapter;
|
GDBusProxy *proxy;
|
DBusMessageIter iter;
|
const char *address;
|
|
if (argc < 2 || !strlen(argv[1])) {
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
proxy = default_ctrl->proxy;
|
} else {
|
adapter = find_ctrl_by_address(ctrl_list, argv[1]);
|
if (!adapter) {
|
pr_info("Controller %s not available\n",
|
argv[1]);
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
proxy = adapter->proxy;
|
}
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
dbus_message_iter_get_basic(&iter, &address);
|
|
if (g_dbus_proxy_get_property(proxy, "AddressType", &iter) == TRUE) {
|
const char *type;
|
|
dbus_message_iter_get_basic(&iter, &type);
|
|
pr_info("Controller %s (%s)\n", address, type);
|
} else {
|
pr_info("Controller %s\n", address);
|
}
|
|
print_property(proxy, "Name");
|
print_property(proxy, "Alias");
|
print_property(proxy, "Class");
|
print_property(proxy, "Powered");
|
print_property(proxy, "Discoverable");
|
print_property(proxy, "Pairable");
|
print_uuids(proxy);
|
print_property(proxy, "Modalias");
|
print_property(proxy, "Discovering");
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void cmd_select(int argc, char *argv[])
|
{
|
struct adapter *adapter;
|
|
adapter = find_ctrl_by_address(ctrl_list, argv[1]);
|
if (!adapter) {
|
pr_info("Controller %s not available\n", argv[1]);
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
if (default_ctrl && default_ctrl->proxy == adapter->proxy)
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
default_ctrl = adapter;
|
print_adapter(adapter->proxy, NULL);
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void cmd_devices(BtScanParam *param)
|
{
|
GList *ll;
|
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
for (ll = g_list_first(default_ctrl->devices); ll; ll = g_list_next(ll)) {
|
GDBusProxy *proxy = (GDBusProxy *)ll->data;
|
|
if(param)
|
btsrc_scan_save_device(proxy, param);
|
else
|
print_device(proxy, NULL);
|
}
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void cmd_paired_devices()
|
{
|
GList *ll;
|
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
|
for (ll = g_list_first(default_ctrl->devices);
|
ll; ll = g_list_next(ll)) {
|
GDBusProxy *proxy = (GDBusProxy *)ll->data;
|
DBusMessageIter iter;
|
dbus_bool_t paired;
|
|
if (g_dbus_proxy_get_property(proxy, "Paired", &iter) == FALSE)
|
continue;
|
|
dbus_message_iter_get_basic(&iter, &paired);
|
if (!paired)
|
continue;
|
|
print_device(proxy, NULL);
|
}
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void generic_callback(const DBusError *error, void *user_data)
|
{
|
if (dbus_error_is_set(error)) {
|
pr_info("Set failed: %s\n", error->name);
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
} else {
|
pr_info("Changing succeeded\n");
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
}
|
|
static void cmd_system_alias(int argc, char *argv[])
|
{
|
char *name;
|
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
name = g_strdup(argv[1]);
|
|
if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Alias",
|
DBUS_TYPE_STRING, &name,
|
generic_callback, name, g_free) == TRUE)
|
return;
|
|
g_free(name);
|
}
|
|
static void cmd_reset_alias(int argc, char *argv[])
|
{
|
char *name;
|
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
name = g_strdup("");
|
|
if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Alias",
|
DBUS_TYPE_STRING, &name,
|
generic_callback, name, g_free) == TRUE)
|
return;
|
|
g_free(name);
|
}
|
|
static void cmd_power(int argc, char *argv[])
|
{
|
dbus_bool_t powered;
|
char *str;
|
|
if (!parse_argument(argc, argv, NULL, NULL, &powered, NULL))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
|
|
if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Powered",
|
DBUS_TYPE_BOOLEAN, &powered,
|
generic_callback, str, g_free) == TRUE)
|
return;
|
|
g_free(str);
|
}
|
|
static void cmd_pairable(int argc, char *argv[])
|
{
|
dbus_bool_t pairable;
|
char *str;
|
|
if (!parse_argument(argc, argv, NULL, NULL, &pairable, NULL))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
str = g_strdup_printf("pairable %s", pairable == TRUE ? "on" : "off");
|
|
if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Pairable",
|
DBUS_TYPE_BOOLEAN, &pairable,
|
generic_callback, str, g_free) == TRUE)
|
return;
|
|
g_free(str);
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
static void cmd_discoverable(int argc, char *argv[])
|
{
|
dbus_bool_t discoverable;
|
char *str;
|
|
if (!parse_argument(argc, argv, NULL, NULL, &discoverable, NULL))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
str = g_strdup_printf("discoverable %s",
|
discoverable == TRUE ? "on" : "off");
|
|
if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Discoverable",
|
DBUS_TYPE_BOOLEAN, &discoverable,
|
generic_callback, str, g_free) == TRUE)
|
return;
|
|
g_free(str);
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
static void cmd_agent(int argc, char *argv[])
|
{
|
dbus_bool_t enable;
|
const char *capability;
|
|
if (!parse_argument(argc, argv, agent_arguments, "capability",
|
&enable, &capability))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
if (enable == TRUE) {
|
g_free(auto_register_agent);
|
auto_register_agent = g_strdup(capability);
|
|
if (agent_manager)
|
agent_register(dbus_conn, agent_manager,
|
auto_register_agent);
|
else
|
pr_info("Agent registration enabled\n");
|
} else {
|
g_free(auto_register_agent);
|
auto_register_agent = NULL;
|
|
if (agent_manager)
|
agent_unregister(dbus_conn, agent_manager);
|
else
|
pr_info("Agent registration disabled\n");
|
}
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void cmd_default_agent(int argc, char *argv[])
|
{
|
agent_default(dbus_conn, agent_manager);
|
}
|
|
static void discovery_reply(DBusMessage *message, void *user_data)
|
{
|
dbus_bool_t enable = GPOINTER_TO_UINT(user_data);
|
DBusError error;
|
|
dbus_error_init(&error);
|
|
if (dbus_set_error_from_message(&error, message) == TRUE) {
|
pr_info("%s: Failed to %s(%lu) discovery: %s\n", __func__,
|
enable == TRUE ? "start" : "stop", pthread_self(), error.name);
|
if(enable)
|
bt_discovery_state_send(RK_BT_DISC_START_FAILED);
|
else
|
g_bt_scan_info.scan_off_failed = true;
|
|
dbus_error_free(&error);
|
return;
|
}
|
|
if(enable)
|
bt_discovery_state_send(RK_BT_DISC_STARTED);
|
|
pr_info("%s: Discovery %s(%lu)\n", __func__, enable ? "started" : "stopped", pthread_self());
|
/* Leave the discovery running even on noninteractive mode */
|
}
|
|
static struct set_discovery_filter_args {
|
char *transport;
|
dbus_uint16_t rssi;
|
dbus_int16_t pathloss;
|
char **uuids;
|
size_t uuids_len;
|
dbus_bool_t duplicate;
|
bool set;
|
} filter = {
|
NULL,
|
DISTANCE_VAL_INVALID,
|
DISTANCE_VAL_INVALID,
|
NULL,
|
0,
|
false,
|
true,
|
};
|
|
static void scan_filter_transport()
|
{
|
const char *type = NULL;
|
|
switch(g_bt_scan_info.scan_type) {
|
case SCAN_TYPE_AUTO:
|
type = "auto";
|
break;
|
|
case SCAN_TYPE_BREDR:
|
type = "bredr";
|
break;
|
|
case SCAN_TYPE_LE:
|
type = "le";
|
break;
|
}
|
|
if(type) {
|
filter_clear_transport();
|
filter.transport = g_strdup(type);
|
filter.set = false;
|
}
|
}
|
|
static void set_discovery_filter_setup(DBusMessageIter *iter, void *user_data)
|
{
|
struct set_discovery_filter_args *args = (struct set_discovery_filter_args *)user_data;
|
DBusMessageIter dict;
|
|
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
|
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
DBUS_TYPE_STRING_AS_STRING
|
DBUS_TYPE_VARIANT_AS_STRING
|
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
|
|
if(args->uuids_len > 0)
|
g_dbus_dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING,
|
&args->uuids,
|
args->uuids_len);
|
|
if (args->pathloss != DISTANCE_VAL_INVALID)
|
g_dbus_dict_append_entry(&dict, "Pathloss", DBUS_TYPE_UINT16,
|
&args->pathloss);
|
|
if (args->rssi != DISTANCE_VAL_INVALID)
|
g_dbus_dict_append_entry(&dict, "RSSI", DBUS_TYPE_INT16,
|
&args->rssi);
|
|
if (args->transport != NULL) {
|
pr_info("%s: scan transport: %s\n", __func__, args->transport);
|
g_dbus_dict_append_entry(&dict, "Transport", DBUS_TYPE_STRING,
|
&args->transport);
|
}
|
|
if (args->duplicate)
|
g_dbus_dict_append_entry(&dict, "DuplicateData",
|
DBUS_TYPE_BOOLEAN,
|
&args->duplicate);
|
|
dbus_message_iter_close_container(iter, &dict);
|
}
|
|
|
static void set_discovery_filter_reply(DBusMessage *message, void *user_data)
|
{
|
DBusError error;
|
|
dbus_error_init(&error);
|
if (dbus_set_error_from_message(&error, message) == TRUE) {
|
pr_info("SetDiscoveryFilter failed: %s\n", error.name);
|
dbus_error_free(&error);
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
filter.set = true;
|
|
pr_info("SetDiscoveryFilter success\n");
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void set_discovery_filter(void)
|
{
|
if (check_default_ctrl() == FALSE || filter.set)
|
return;
|
|
if (g_dbus_proxy_method_call(default_ctrl->proxy, "SetDiscoveryFilter",
|
set_discovery_filter_setup, set_discovery_filter_reply,
|
&filter, NULL) == FALSE) {
|
pr_info("Failed to set discovery filter\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
filter.set = true;
|
}
|
|
static int cmd_scan(const char *cmd)
|
{
|
dbus_bool_t enable;
|
const char *method;
|
|
if (strcmp(cmd, "on") == 0) {
|
enable = TRUE;
|
} else if (strcmp(cmd, "off") == 0){
|
enable = FALSE;
|
} else {
|
pr_info("ERROR: %s cmd(%s) is invalid!\n", __func__, cmd);
|
return -1;
|
}
|
|
if (check_default_ctrl() == FALSE)
|
return -1;
|
|
if (enable == TRUE) {
|
scan_filter_transport();
|
set_discovery_filter();
|
method = "StartDiscovery";
|
} else
|
method = "StopDiscovery";
|
|
pr_info("%s method = %s\n", __func__, method);
|
|
if (g_dbus_proxy_method_call(default_ctrl->proxy, method,
|
NULL, discovery_reply,
|
GUINT_TO_POINTER(enable), NULL) == FALSE) {
|
pr_info("Failed to %s discovery\n",
|
enable == TRUE ? "start" : "stop");
|
return -1;
|
}
|
|
return 0;
|
}
|
|
static void cmd_scan_filter_uuids(int argc, char *argv[])
|
{
|
if (argc < 2 || !strlen(argv[1])) {
|
char **uuid;
|
|
for (uuid = filter.uuids; uuid && *uuid; uuid++)
|
print_uuid(*uuid);
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
g_strfreev(filter.uuids);
|
filter.uuids = NULL;
|
filter.uuids_len = 0;
|
|
if (!strcmp(argv[1], "all"))
|
goto commit;
|
|
filter.uuids = g_strdupv(&argv[1]);
|
if (!filter.uuids) {
|
pr_info("Failed to parse input\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
filter.uuids_len = g_strv_length(filter.uuids);
|
|
commit:
|
filter.set = false;
|
}
|
|
static void cmd_scan_filter_rssi(int argc, char *argv[])
|
{
|
if (argc < 2 || !strlen(argv[1])) {
|
if (filter.rssi != DISTANCE_VAL_INVALID)
|
pr_info("RSSI: %d\n", filter.rssi);
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
filter.pathloss = DISTANCE_VAL_INVALID;
|
filter.rssi = atoi(argv[1]);
|
|
filter.set = false;
|
}
|
|
static void cmd_scan_filter_pathloss(int argc, char *argv[])
|
{
|
if (argc < 2 || !strlen(argv[1])) {
|
if (filter.pathloss != DISTANCE_VAL_INVALID)
|
pr_info("Pathloss: %d\n",
|
filter.pathloss);
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
filter.rssi = DISTANCE_VAL_INVALID;
|
filter.pathloss = atoi(argv[1]);
|
|
filter.set = false;
|
}
|
|
static void cmd_scan_filter_duplicate_data(int argc, char *argv[])
|
{
|
if (argc < 2 || !strlen(argv[1])) {
|
pr_info("DuplicateData: %s\n",
|
filter.duplicate ? "on" : "off");
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
if (!strcmp(argv[1], "on"))
|
filter.duplicate = true;
|
else if (!strcmp(argv[1], "off"))
|
filter.duplicate = false;
|
else {
|
pr_info("Invalid option: %s\n", argv[1]);
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
filter.set = false;
|
}
|
|
static void filter_clear_uuids(void)
|
{
|
g_strfreev(filter.uuids);
|
filter.uuids = NULL;
|
filter.uuids_len = 0;
|
}
|
|
static void filter_clear_rssi(void)
|
{
|
filter.rssi = DISTANCE_VAL_INVALID;
|
}
|
|
static void filter_clear_pathloss(void)
|
{
|
filter.pathloss = DISTANCE_VAL_INVALID;
|
}
|
|
static void filter_clear_transport()
|
{
|
if(filter.transport) {
|
pr_info("%s\n", __func__);
|
g_free(filter.transport);
|
filter.transport = NULL;
|
}
|
}
|
|
static void filter_clear_duplicate(void)
|
{
|
filter.duplicate = false;
|
}
|
|
struct clear_entry {
|
const char *name;
|
void (*clear) (void);
|
};
|
|
static const struct clear_entry filter_clear[] = {
|
{ "uuids", filter_clear_uuids },
|
{ "rssi", filter_clear_rssi },
|
{ "pathloss", filter_clear_pathloss },
|
{ "transport", filter_clear_transport },
|
{ "duplicate-data", filter_clear_duplicate },
|
{}
|
};
|
|
static char *filter_clear_generator(const char *text, int state)
|
{
|
static int index, len;
|
const char *arg;
|
|
if (!state) {
|
index = 0;
|
len = strlen(text);
|
}
|
|
while ((arg = filter_clear[index].name)) {
|
index++;
|
|
if (!strncmp(arg, text, len))
|
return strdup(arg);
|
}
|
|
return NULL;
|
}
|
|
static gboolean data_clear(const struct clear_entry *entry_table,
|
const char *name)
|
{
|
const struct clear_entry *entry;
|
bool all = false;
|
|
if (!name || !strlen(name) || !strcmp("all", name))
|
all = true;
|
|
for (entry = entry_table; entry && entry->name; entry++) {
|
if (all || !strcmp(entry->name, name)) {
|
entry->clear();
|
if (!all)
|
goto done;
|
}
|
}
|
|
if (!all) {
|
pr_info("Invalid argument %s\n", name);
|
return FALSE;
|
}
|
|
done:
|
return TRUE;
|
}
|
|
static void cmd_scan_filter_clear(int argc, char *argv[])
|
{
|
bool all = false;
|
|
if (argc < 2 || !strlen(argv[1]))
|
all = true;
|
|
if (!data_clear(filter_clear, all ? "all" : argv[1]))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
filter.set = false;
|
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
set_discovery_filter();
|
}
|
|
static struct GDBusProxy *find_device(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
|
if (argc < 2 || !strlen(argv[1])) {
|
if (default_dev)
|
return default_dev;
|
pr_info("Missing device address argument\n");
|
return NULL;
|
}
|
|
if (check_default_ctrl() == FALSE)
|
return NULL;
|
|
proxy = find_proxy_by_address(default_ctrl->devices, argv[1]);
|
if (!proxy) {
|
pr_info("Device %s not available\n", argv[1]);
|
return NULL;
|
}
|
|
return proxy;
|
}
|
|
struct GDBusProxy *find_device_by_address(char *address)
|
{
|
GDBusProxy *proxy;
|
|
if (!address || strlen(address) < 17) {
|
if (default_dev)
|
return default_dev;
|
pr_info("Missing device address argument\n");
|
return NULL;
|
}
|
|
if (check_default_ctrl() == FALSE)
|
return NULL;
|
|
proxy = find_proxy_by_address(default_ctrl->devices, address);
|
if (!proxy) {
|
pr_info("%s: Device %s not available\n", __func__, address);
|
return NULL;
|
}
|
|
return proxy;
|
}
|
|
static void cmd_info(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
DBusMessageIter iter;
|
const char *address;
|
|
proxy = find_device(argc, argv);
|
if (!proxy)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
dbus_message_iter_get_basic(&iter, &address);
|
|
if (g_dbus_proxy_get_property(proxy, "AddressType", &iter) == TRUE) {
|
const char *type;
|
|
dbus_message_iter_get_basic(&iter, &type);
|
|
pr_info("Device %s (%s)\n", address, type);
|
} else {
|
pr_info("Device %s\n", address);
|
}
|
|
print_property(proxy, "Name");
|
print_property(proxy, "Alias");
|
print_property(proxy, "Class");
|
print_property(proxy, "Appearance");
|
print_property(proxy, "Icon");
|
print_property(proxy, "Paired");
|
print_property(proxy, "Trusted");
|
print_property(proxy, "Blocked");
|
print_property(proxy, "Connected");
|
print_property(proxy, "LegacyPairing");
|
print_property(proxy, "Modalias");
|
print_property(proxy, "ManufacturerData");
|
print_property(proxy, "ServiceData");
|
print_property(proxy, "RSSI");
|
print_property(proxy, "TxPower");
|
print_property(proxy, "AdvertisingFlags");
|
print_property(proxy, "AdvertisingData");
|
print_uuids(proxy);
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void pair_reply(DBusMessage *message, void *user_data)
|
{
|
DBusError error;
|
|
dbus_error_init(&error);
|
|
if (dbus_set_error_from_message(&error, message) == TRUE) {
|
pr_info("Failed to pair: %s\n", error.name);
|
dbus_error_free(&error);
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
pr_info("Pairing successful\n");
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static const char *proxy_address(GDBusProxy *proxy)
|
{
|
DBusMessageIter iter;
|
const char *addr;
|
|
if (!g_dbus_proxy_get_property(proxy, "Address", &iter))
|
return NULL;
|
|
dbus_message_iter_get_basic(&iter, &addr);
|
|
return addr;
|
}
|
|
static int cmd_pair(GDBusProxy *proxy)
|
{
|
if (!proxy)
|
return -1;
|
|
if (g_dbus_proxy_method_call(proxy, "Pair", NULL, pair_reply,
|
NULL, NULL) == FALSE) {
|
pr_info("%s: Failed to pair\n", __func__);
|
return -1;
|
}
|
|
pr_info("%s: Attempting to pair with %s\n", __func__, proxy_address(proxy));
|
return 0;
|
}
|
|
static void cmd_trust(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
dbus_bool_t trusted;
|
char *str;
|
|
proxy = find_device(argc, argv);
|
if (!proxy)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
trusted = TRUE;
|
|
str = g_strdup_printf("%s trust", proxy_address(proxy));
|
|
if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
|
DBUS_TYPE_BOOLEAN, &trusted,
|
generic_callback, str, g_free) == TRUE)
|
return;
|
|
g_free(str);
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
static void cmd_untrust(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
dbus_bool_t trusted;
|
char *str;
|
|
proxy = find_device(argc, argv);
|
if (!proxy)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
trusted = FALSE;
|
|
str = g_strdup_printf("%s untrust", proxy_address(proxy));
|
|
if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
|
DBUS_TYPE_BOOLEAN, &trusted,
|
generic_callback, str, g_free) == TRUE)
|
return;
|
|
g_free(str);
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
static void cmd_block(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
dbus_bool_t blocked;
|
char *str;
|
|
proxy = find_device(argc, argv);
|
if (!proxy)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
blocked = TRUE;
|
|
str = g_strdup_printf("%s block", proxy_address(proxy));
|
|
if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
|
DBUS_TYPE_BOOLEAN, &blocked,
|
generic_callback, str, g_free) == TRUE)
|
return;
|
|
g_free(str);
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
static void cmd_unblock(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
dbus_bool_t blocked;
|
char *str;
|
|
proxy = find_device(argc, argv);
|
if (!proxy)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
blocked = FALSE;
|
|
str = g_strdup_printf("%s unblock", proxy_address(proxy));
|
|
if (g_dbus_proxy_set_property_basic(proxy, "Blocked",
|
DBUS_TYPE_BOOLEAN, &blocked,
|
generic_callback, str, g_free) == TRUE)
|
return;
|
|
g_free(str);
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
static void remove_device_reply(DBusMessage *message, void *user_data)
|
{
|
DBusError error;
|
|
dbus_error_init(&error);
|
|
if (dbus_set_error_from_message(&error, message) == TRUE) {
|
pr_info("Failed to remove device: %s\n", error.name);
|
//a2dp_master_event_send(BT_SOURCE_EVENT_REMOVE_FAILED, "", "");
|
dbus_error_free(&error);
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
pr_info("%s: Device has been removed\n", __func__);
|
//a2dp_master_event_send(BT_SOURCE_EVENT_REMOVED, "", "");
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void remove_device_setup(DBusMessageIter *iter, void *user_data)
|
{
|
char *path = (char *)user_data;
|
|
dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
|
}
|
|
static int remove_device(GDBusProxy *proxy)
|
{
|
char *path;
|
|
path = g_strdup(g_dbus_proxy_get_path(proxy));
|
|
if (check_default_ctrl() == FALSE)
|
return -1;
|
|
pr_info("%s: Attempting to remove device with %s\n", __func__, proxy_address(proxy));
|
if (g_dbus_proxy_method_call(default_ctrl->proxy, "RemoveDevice",
|
remove_device_setup,
|
remove_device_reply,
|
path, g_free) == FALSE) {
|
pr_info("%s: Failed to remove device\n", __func__);
|
g_free(path);
|
return -1;
|
}
|
|
return 0;
|
}
|
|
static void cmd_remove(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
pr_info("%s\n", __func__);
|
if (strcmp(argv[1], "*") == 0) {
|
GList *list;
|
|
for (list = default_ctrl->devices; list;
|
list = g_list_next(list)) {
|
GDBusProxy *proxy = (GDBusProxy *)list->data;
|
|
remove_device(proxy);
|
}
|
return;
|
}
|
|
proxy = find_proxy_by_address(default_ctrl->devices, argv[1]);
|
if (!proxy) {
|
pr_info("Device %s not available\n", argv[1]);
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
remove_device(proxy);
|
}
|
|
static void cmd_list_attributes(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
|
proxy = find_device(argc, argv);
|
if (!proxy)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_list_attributes(g_dbus_proxy_get_path(proxy));
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void cmd_set_alias(int argc, char *argv[])
|
{
|
char *name;
|
|
if (!default_dev) {
|
pr_info("No device connected\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
name = g_strdup(argv[1]);
|
|
if (g_dbus_proxy_set_property_basic(default_dev, "Alias",
|
DBUS_TYPE_STRING, &name,
|
generic_callback, name, g_free) == TRUE)
|
return;
|
|
g_free(name);
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
static struct GDBusProxy *find_attribute(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
|
if (argc < 2 || !strlen(argv[1])) {
|
if (default_attr)
|
return default_attr;
|
pr_info("Missing attribute argument\n");
|
return NULL;
|
}
|
|
proxy = gatt_select_attribute(default_attr, argv[1]);
|
if (!proxy) {
|
pr_info("Attribute %s not available\n", argv[1]);
|
return NULL;
|
}
|
|
return proxy;
|
}
|
|
static void cmd_attribute_info(int argc, char *argv[])
|
{
|
GDBusProxy *proxy;
|
DBusMessageIter iter;
|
const char *iface, *uuid, *text;
|
|
proxy = find_attribute(argc, argv);
|
if (!proxy)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
dbus_message_iter_get_basic(&iter, &uuid);
|
|
text = bt_uuidstr_to_str(uuid);
|
if (!text)
|
text = g_dbus_proxy_get_path(proxy);
|
|
iface = g_dbus_proxy_get_interface(proxy);
|
if (!strcmp(iface, "org.bluez.GattService1")) {
|
pr_info("Service - %s\n", text);
|
|
print_property(proxy, "UUID");
|
print_property(proxy, "Primary");
|
print_property(proxy, "Characteristics");
|
print_property(proxy, "Includes");
|
} else if (!strcmp(iface, "org.bluez.GattCharacteristic1")) {
|
pr_info("Characteristic - %s\n", text);
|
|
print_property(proxy, "UUID");
|
print_property(proxy, "Service");
|
print_property(proxy, "Value");
|
print_property(proxy, "Notifying");
|
print_property(proxy, "Flags");
|
print_property(proxy, "Descriptors");
|
} else if (!strcmp(iface, "org.bluez.GattDescriptor1")) {
|
pr_info("Descriptor - %s\n", text);
|
|
print_property(proxy, "UUID");
|
print_property(proxy, "Characteristic");
|
print_property(proxy, "Value");
|
}
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void cmd_acquire_write(int argc, char *argv[])
|
{
|
if (!default_attr) {
|
pr_info("No attribute selected\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
gatt_acquire_write(default_attr, argv[1]);
|
}
|
|
static void cmd_release_write(int argc, char *argv[])
|
{
|
if (!default_attr) {
|
pr_info("No attribute selected\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
gatt_release_write(default_attr, argv[1]);
|
}
|
|
static void cmd_acquire_notify(int argc, char *argv[])
|
{
|
if (!default_attr) {
|
pr_info("No attribute selected\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
gatt_acquire_notify(default_attr, argv[1]);
|
}
|
|
static void cmd_release_notify(int argc, char *argv[])
|
{
|
if (!default_attr) {
|
pr_info("No attribute selected\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
gatt_release_notify(default_attr, argv[1]);
|
}
|
|
static void cmd_notify(int argc, char *argv[])
|
{
|
dbus_bool_t enable;
|
|
if (!parse_argument(argc, argv, NULL, NULL, &enable, NULL))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
if (!default_attr) {
|
pr_info("No attribute selected\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
gatt_notify_attribute(default_attr, enable ? true : false);
|
}
|
|
static void cmd_register_app(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_register_app(dbus_conn, default_ctrl->proxy, argc, argv);
|
}
|
|
static void cmd_unregister_app(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_unregister_app(dbus_conn, default_ctrl->proxy);
|
}
|
|
static void cmd_register_service(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_register_service(dbus_conn, default_ctrl->proxy, argc, argv);
|
}
|
|
static void cmd_register_includes(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_register_include(dbus_conn, default_ctrl->proxy, argc, argv);
|
}
|
|
static void cmd_unregister_includes(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_unregister_include(dbus_conn, default_ctrl->proxy, argc, argv);
|
}
|
|
static void cmd_unregister_service(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_unregister_service(dbus_conn, default_ctrl->proxy, argc, argv);
|
}
|
|
static void cmd_register_characteristic(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_register_chrc(dbus_conn, default_ctrl->proxy, argc, argv);
|
}
|
|
static void cmd_unregister_characteristic(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_unregister_chrc(dbus_conn, default_ctrl->proxy, argc, argv);
|
}
|
|
static void cmd_register_descriptor(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_register_desc(dbus_conn, default_ctrl->proxy, argc, argv);
|
}
|
|
static void cmd_unregister_descriptor(int argc, char *argv[])
|
{
|
if (check_default_ctrl() == FALSE)
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
gatt_unregister_desc(dbus_conn, default_ctrl->proxy, argc, argv);
|
}
|
|
static char *generic_generator(const char *text, int state,
|
GList *source, const char *property)
|
{
|
static int index, len;
|
GList *list;
|
|
if (!state) {
|
index = 0;
|
len = strlen(text);
|
}
|
|
for (list = g_list_nth(source, index); list;
|
list = g_list_next(list)) {
|
GDBusProxy *proxy = (GDBusProxy *)list->data;
|
DBusMessageIter iter;
|
const char *str;
|
|
index++;
|
|
if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
|
continue;
|
|
dbus_message_iter_get_basic(&iter, &str);
|
|
if (!strncasecmp(str, text, len))
|
return strdup(str);
|
}
|
|
return NULL;
|
}
|
|
static char *ctrl_generator(const char *text, int state)
|
{
|
static int index = 0;
|
static int len = 0;
|
GList *list;
|
|
if (!state) {
|
index = 0;
|
len = strlen(text);
|
}
|
|
for (list = g_list_nth(ctrl_list, index); list;
|
list = g_list_next(list)) {
|
struct adapter *adapter = (struct adapter *)list->data;
|
DBusMessageIter iter;
|
const char *str;
|
|
index++;
|
|
if (g_dbus_proxy_get_property(adapter->proxy,
|
"Address", &iter) == FALSE)
|
continue;
|
|
dbus_message_iter_get_basic(&iter, &str);
|
|
if (!strncasecmp(str, text, len))
|
return strdup(str);
|
}
|
|
return NULL;
|
}
|
|
static char *dev_generator(const char *text, int state)
|
{
|
return generic_generator(text, state,
|
default_ctrl ? default_ctrl->devices : NULL, "Address");
|
}
|
|
static char *attribute_generator(const char *text, int state)
|
{
|
return gatt_attribute_generator(text, state);
|
}
|
|
static char *argument_generator(const char *text, int state,
|
const char *args_list[])
|
{
|
static int index, len;
|
const char *arg;
|
|
if (!state) {
|
index = 0;
|
len = strlen(text);
|
}
|
|
while ((arg = args_list[index])) {
|
index++;
|
|
if (!strncmp(arg, text, len))
|
return strdup(arg);
|
}
|
|
return NULL;
|
}
|
|
static char *capability_generator(const char *text, int state)
|
{
|
return argument_generator(text, state, agent_arguments);
|
}
|
|
static void cmd_advertise(int argc, char *argv[])
|
{
|
dbus_bool_t enable;
|
const char *type;
|
|
if (!parse_argument(argc, argv, ad_arguments, "type",
|
&enable, &type))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
if (!default_ctrl || !default_ctrl->ad_proxy) {
|
pr_info("LEAdvertisingManager not found\n");
|
bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
if (enable == TRUE)
|
ad_register(dbus_conn, default_ctrl->ad_proxy, type);
|
else
|
ad_unregister(dbus_conn, default_ctrl->ad_proxy);
|
}
|
|
static char *ad_generator(const char *text, int state)
|
{
|
return argument_generator(text, state, ad_arguments);
|
}
|
|
static void cmd_advertise_uuids(int argc, char *argv[])
|
{
|
ad_advertise_uuids(dbus_conn, argc, argv);
|
}
|
|
static void cmd_advertise_service(int argc, char *argv[])
|
{
|
ad_advertise_service(dbus_conn, argc, argv);
|
}
|
|
static void cmd_advertise_manufacturer(int argc, char *argv[])
|
{
|
ad_advertise_manufacturer(dbus_conn, argc, argv);
|
}
|
|
static void cmd_advertise_data(int argc, char *argv[])
|
{
|
ad_advertise_data(dbus_conn, argc, argv);
|
}
|
|
static void cmd_advertise_discoverable(int argc, char *argv[])
|
{
|
dbus_bool_t discoverable;
|
|
if (argc < 2) {
|
ad_advertise_discoverable(dbus_conn, NULL);
|
return;
|
}
|
|
if (!parse_argument(argc, argv, NULL, NULL, &discoverable, NULL))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
ad_advertise_discoverable(dbus_conn, &discoverable);
|
}
|
|
static void cmd_advertise_discoverable_timeout(int argc, char *argv[])
|
{
|
long int value;
|
char *endptr = NULL;
|
|
if (argc < 2) {
|
ad_advertise_discoverable_timeout(dbus_conn, NULL);
|
return;
|
}
|
|
value = strtol(argv[1], &endptr, 0);
|
if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
|
pr_info("Invalid argument\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
ad_advertise_discoverable_timeout(dbus_conn, &value);
|
}
|
|
static void cmd_advertise_tx_power(int argc, char *argv[])
|
{
|
dbus_bool_t powered;
|
|
if (argc < 2) {
|
ad_advertise_tx_power(dbus_conn, NULL);
|
return;
|
}
|
|
if (!parse_argument(argc, argv, NULL, NULL, &powered, NULL))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
|
ad_advertise_tx_power(dbus_conn, &powered);
|
}
|
|
static void cmd_advertise_name(int argc, char *argv[])
|
{
|
if (argc < 2) {
|
ad_advertise_local_name(dbus_conn, NULL);
|
return;
|
}
|
|
if (strcmp(argv[1], "on") == 0 || strcmp(argv[1], "yes") == 0) {
|
ad_advertise_name(dbus_conn, true);
|
return;
|
}
|
|
if (strcmp(argv[1], "off") == 0 || strcmp(argv[1], "no") == 0) {
|
ad_advertise_name(dbus_conn, false);
|
return;
|
}
|
|
ad_advertise_local_name(dbus_conn, argv[1]);
|
}
|
|
static void cmd_advertise_appearance(int argc, char *argv[])
|
{
|
long int value;
|
char *endptr = NULL;
|
|
if (argc < 2) {
|
ad_advertise_local_appearance(dbus_conn, NULL);
|
return;
|
}
|
|
if (strcmp(argv[1], "on") == 0 || strcmp(argv[1], "yes") == 0) {
|
ad_advertise_appearance(dbus_conn, true);
|
return;
|
}
|
|
if (strcmp(argv[1], "off") == 0 || strcmp(argv[1], "no") == 0) {
|
ad_advertise_appearance(dbus_conn, false);
|
return;
|
}
|
|
value = strtol(argv[1], &endptr, 0);
|
if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
|
pr_info("Invalid argument\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
ad_advertise_local_appearance(dbus_conn, &value);
|
}
|
|
static void cmd_advertise_duration(int argc, char *argv[])
|
{
|
long int value;
|
char *endptr = NULL;
|
|
if (argc < 2) {
|
ad_advertise_duration(dbus_conn, NULL);
|
return;
|
}
|
|
value = strtol(argv[1], &endptr, 0);
|
if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
|
pr_info("Invalid argument\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
ad_advertise_duration(dbus_conn, &value);
|
}
|
|
static void cmd_advertise_timeout(int argc, char *argv[])
|
{
|
long int value;
|
char *endptr = NULL;
|
|
if (argc < 2) {
|
ad_advertise_timeout(dbus_conn, NULL);
|
return;
|
}
|
|
value = strtol(argv[1], &endptr, 0);
|
if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
|
pr_info("Invalid argument\n");
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
ad_advertise_timeout(dbus_conn, &value);
|
}
|
|
static void ad_clear_uuids(void)
|
{
|
ad_disable_uuids(dbus_conn);
|
}
|
|
static void ad_clear_service(void)
|
{
|
ad_disable_service(dbus_conn);
|
}
|
|
static void ad_clear_manufacturer(void)
|
{
|
ad_disable_manufacturer(dbus_conn);
|
}
|
|
static void ad_clear_data(void)
|
{
|
ad_disable_data(dbus_conn);
|
}
|
|
static void ad_clear_tx_power(void)
|
{
|
dbus_bool_t powered = false;
|
|
ad_advertise_tx_power(dbus_conn, &powered);
|
}
|
|
static void ad_clear_name(void)
|
{
|
ad_advertise_name(dbus_conn, false);
|
}
|
|
static void ad_clear_appearance(void)
|
{
|
ad_advertise_appearance(dbus_conn, false);
|
}
|
|
static void ad_clear_duration(void)
|
{
|
long int value = 0;
|
|
ad_advertise_duration(dbus_conn, &value);
|
}
|
|
static void ad_clear_timeout(void)
|
{
|
long int value = 0;
|
|
ad_advertise_timeout(dbus_conn, &value);
|
}
|
|
static const struct clear_entry ad_clear[] = {
|
{ "uuids", ad_clear_uuids },
|
{ "service", ad_clear_service },
|
{ "manufacturer", ad_clear_manufacturer },
|
{ "data", ad_clear_data },
|
{ "tx-power", ad_clear_tx_power },
|
{ "name", ad_clear_name },
|
{ "appearance", ad_clear_appearance },
|
{ "duration", ad_clear_duration },
|
{ "timeout", ad_clear_timeout },
|
{}
|
};
|
|
static void cmd_ad_clear(int argc, char *argv[])
|
{
|
bool all = false;
|
|
if (argc < 2 || !strlen(argv[1]))
|
all = true;
|
|
if(!data_clear(ad_clear, all ? "all" : argv[1]))
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
static const struct option options[] = {
|
{ "agent", required_argument, 0, 'a' },
|
{ 0, 0, 0, 0 }
|
};
|
|
static const char *agent_option;
|
|
static const char **optargs[] = {
|
&agent_option
|
};
|
|
static const char *help[] = {
|
"Register agent handler: <capability>"
|
};
|
|
static const struct bt_shell_opt opt = {
|
.options = options,
|
.optno = sizeof(options) / sizeof(struct option),
|
.optstr = "a:",
|
.optarg = optargs,
|
.help = help,
|
};
|
|
static void client_ready(GDBusClient *client, void *user_data)
|
{
|
return;
|
}
|
|
static guint reconnect_timer;
|
static void connect_reply(DBusMessage *message, void *user_data)
|
{
|
struct ConnectContext_t *ctx_ptr = (struct ConnectContext_t *)user_data;
|
if (!ctx_ptr) {
|
pr_err("%s: invaild connect context!\n", __func__);
|
return;
|
}
|
GDBusProxy *proxy = ctx_ptr->proxy;
|
DBusError error;
|
static int conn_count = 0;
|
DBusMessageIter iter;
|
const char *address = ctx_ptr->address;
|
char addr[18], name[256];
|
|
dbus_error_init(&error);
|
|
g_bt_source_info.is_connecting = false;
|
if (dbus_set_error_from_message(&error, message) == TRUE) {
|
pr_info("%s: Failed to connect: %s\n", __func__, error.name);
|
dbus_error_free(&error);
|
|
conn_count--;
|
if (conn_count > 0) {
|
if(g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) {
|
pr_err("%s: can't get address!\n", __func__);
|
return;
|
}
|
|
dbus_message_iter_get_basic(&iter, &address);
|
if (reconnect_timer) {
|
g_source_remove(reconnect_timer);
|
reconnect_timer = 0;
|
}
|
reconnect_timer = g_timeout_add_seconds(3,
|
a2dp_master_connect, address);
|
return;
|
}
|
|
if(bt_source_is_open()) {
|
pr_err("%s: ---------------------- at here\n", __func__);
|
memset(addr, 0, 18);
|
memset(name, 0, 256);
|
//bt_get_device_addr_by_proxy(proxy, addr, 18);
|
//bt_get_device_name_by_proxy(proxy, name, 256);//fail maybe no name
|
a2dp_master_event_send(BT_SOURCE_EVENT_CONNECT_FAILED, address, address);
|
}
|
pr_err("%s: ------------------ ending\n", __func__);
|
conn_count = 0;
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
pr_info("%s: Connection successful\n", __func__);
|
//set_default_device(proxy, NULL);
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void disconn_reply(DBusMessage *message, void *user_data)
|
{
|
GDBusProxy *proxy = (GDBusProxy *)user_data;
|
DBusError error;
|
|
dbus_error_init(&error);
|
|
if (dbus_set_error_from_message(&error, message) == TRUE) {
|
char addr[18], name[256];
|
|
pr_info("Failed to disconnect: %s\n", error.name);
|
dbus_error_free(&error);
|
|
if(bt_source_is_open()) {
|
memset(addr, 0, 18);
|
memset(name, 0, 256);
|
bt_get_device_addr_by_proxy(proxy, addr, 18);
|
bt_get_device_name_by_proxy(proxy, name, 256);
|
a2dp_master_event_send(BT_SOURCE_EVENT_DISCONNECT_FAILED, addr, name);
|
}
|
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
pr_info("%s: Successful disconnected\n", __func__);
|
|
//check disconnect
|
if(bt_is_connected())
|
pr_info("\n\n%s: The ACL link still exists!\n\n\n", __func__);
|
|
if (proxy == default_dev)
|
set_default_device(NULL, NULL);
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
static void a2dp_source_clean(void)
|
{
|
dbus_conn = NULL;
|
agent_manager = NULL;
|
auto_register_agent = NULL;
|
|
default_ctrl = NULL;
|
ctrl_list = NULL;
|
default_dev = NULL;
|
default_attr = NULL;
|
|
btsrc_client = NULL;
|
}
|
|
static void bluetooth_open(RkBtContent *bt_content)
|
{
|
pr_info("%s thread tid = %lu\n", __func__, pthread_self());
|
a2dp_source_clean();
|
|
if (agent_option)
|
auto_register_agent = g_strdup(agent_option);
|
else
|
auto_register_agent = g_strdup("");
|
|
dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
|
g_dbus_attach_object_manager(dbus_conn);
|
|
btsrc_client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
|
if (NULL == btsrc_client) {
|
pr_info("%s: btsrc_client init fail\n", __func__);
|
g_free(auto_register_agent);
|
dbus_connection_unref(dbus_conn);
|
return;
|
}
|
|
init_avrcp_ctrl();
|
|
if(bt_content) {
|
g_bt_content = bt_content;
|
gatt_init(bt_content);
|
} else {
|
g_bt_content = NULL;
|
}
|
|
g_dbus_client_set_connect_watch(btsrc_client, connect_handler, NULL);
|
g_dbus_client_set_disconnect_watch(btsrc_client, disconnect_handler, NULL);
|
g_dbus_client_set_signal_watch(btsrc_client, message_handler, NULL);
|
g_dbus_client_set_proxy_handlers(btsrc_client, proxy_added, proxy_removed,
|
property_changed, NULL);
|
|
BT_OPENED = 1;
|
pr_info("%s: server start...\n", __func__);
|
return;
|
}
|
|
static gboolean _bluetooth_open(void *user_data)
|
{
|
RkBtContent *bt_content = user_data;
|
|
bluetooth_open(bt_content);
|
return FALSE;
|
}
|
|
extern GMainContext *Bluez_Context;
|
int bt_open(RkBtContent *bt_content)
|
{
|
int confirm_cnt = 100;
|
|
BT_OPENED = 0;
|
#ifdef DefGContext
|
//_bluetooth_open(bt_content);
|
g_idle_add(_bluetooth_open, bt_content);
|
#else
|
GSource *source;
|
source = g_idle_source_new();
|
g_source_set_priority (source, G_PRIORITY_DEFAULT_IDLE);
|
g_source_set_callback (source, _bluetooth_open, bt_content, NULL);
|
g_source_attach (source, Bluez_Context);
|
g_source_unref (source);
|
#endif
|
|
while (confirm_cnt--) {
|
if (BT_OPENED)
|
return 0;
|
|
usleep(50 * 1000);
|
}
|
|
return -1;
|
}
|
|
static gboolean _bluetooth_close(void *user_data)
|
{
|
memset(&g_bt_scan_info, 0, sizeof(bt_scan_info_t));
|
|
g_dbus_client_unref(btsrc_client);
|
btsrc_client = NULL;
|
|
gatt_cleanup();
|
|
dbus_connection_unref(dbus_conn);
|
dbus_conn = NULL;
|
|
g_list_free_full(ctrl_list, proxy_leak);
|
g_free(auto_register_agent);
|
auto_register_agent = NULL;
|
//a2dp_source_clean();
|
|
BT_CLOSED = 1;
|
pr_info("%s: server exit!\n", __func__);
|
return FALSE;
|
}
|
|
void bt_close()
|
{
|
int confirm_cnt = 100;
|
|
BT_CLOSED = 0;
|
#ifdef DefGContext
|
//_bluetooth_close(NULL);
|
g_idle_add(_bluetooth_close, NULL);
|
#else
|
GSource *source;
|
|
source = g_idle_source_new();
|
g_source_set_priority (source, G_PRIORITY_DEFAULT_IDLE);
|
g_source_set_callback (source, _bluetooth_close, NULL, NULL);
|
g_source_attach (source, Bluez_Context);
|
g_source_unref (source);
|
#endif
|
}
|
|
static int a2dp_master_get_rssi(GDBusProxy *proxy)
|
{
|
int retry_cnt = 5;
|
DBusMessageIter iter;
|
short rssi = DISTANCE_VAL_INVALID;
|
|
while (retry_cnt--) {
|
if (g_dbus_proxy_get_property(proxy, "RSSI", &iter) == FALSE) {
|
usleep(10000); //10ms
|
continue;
|
}
|
break;
|
}
|
|
if (retry_cnt >= 0)
|
dbus_message_iter_get_basic(&iter, &rssi);
|
|
return rssi;
|
}
|
|
static RK_BT_PLAYROLE_TYPE a2dp_master_get_playrole(GDBusProxy *proxy)
|
{
|
int ret = PLAYROLE_TYPE_UNKNOWN;
|
enum BT_Device_Class device_class;
|
|
device_class = dist_dev_class(proxy);
|
if (device_class == BT_SINK_DEVICE)
|
ret = PLAYROLE_TYPE_SINK;
|
else if (device_class == BT_SOURCE_DEVICE)
|
ret = PLAYROLE_TYPE_SOURCE;
|
|
return ret;
|
}
|
|
int a2dp_master_scan(void *arg, int len, RK_BT_SCAN_TYPE scan_type)
|
{
|
BtScanParam *param = NULL;
|
BtDeviceInfo *start = NULL;
|
GDBusProxy *proxy;
|
int ret = 0;
|
int i;
|
|
if (check_default_ctrl() == FALSE)
|
return -1;
|
|
param = (BtScanParam *)arg;
|
if (len < sizeof(BtScanParam)) {
|
pr_info("%s parameter error. BtScanParam setting is incorrect\n", __func__);
|
return -1;
|
}
|
|
if(g_bt_scan_info.is_scaning) {
|
pr_info("%s: devices discovering\n", __func__);
|
return -1;
|
}
|
g_bt_scan_info.is_scaning = true;
|
g_bt_scan_info.scan_type = scan_type;
|
|
pr_info("=== scan on ===\n");
|
cmd_scan("on");
|
if (param->mseconds > 100) {
|
pr_info("Waiting for Scan(%d ms)...\n", param->mseconds);
|
usleep(param->mseconds * 1000);
|
} else {
|
pr_info("warning:%dms is too short, scan time is changed to 2s.\n",
|
param->mseconds);
|
usleep(2000 * 1000);
|
}
|
|
pr_info("=== scan off ===\n");
|
cmd_scan("off");
|
|
cmd_devices(param);
|
pr_info("=== parse scan device (cnt:%d) ===\n", param->item_cnt);
|
for (i = 0; i < param->item_cnt; i++) {
|
start = ¶m->devices[i];
|
proxy = find_device_by_address(start->address);
|
if (!proxy) {
|
pr_info("%s find_device_by_address failed!\n", __func__);
|
continue;
|
}
|
/* Get bluetooth rssi */
|
ret = a2dp_master_get_rssi(proxy);
|
if (ret != DISTANCE_VAL_INVALID) {
|
start->rssi = ret;
|
start->rssi_valid = TRUE;
|
}
|
/* Get bluetooth AudioProfile */
|
ret = a2dp_master_get_playrole(proxy);
|
if (ret == PLAYROLE_TYPE_SINK)
|
memcpy(start->playrole, "Audio Sink", strlen("Audio Sink"));
|
else if (ret == PLAYROLE_TYPE_SOURCE)
|
memcpy(start->playrole, "Audio Source", strlen("Audio Source"));
|
else
|
memcpy(start->playrole, "Unknow", strlen("Unknow"));
|
}
|
|
g_bt_scan_info.scan_type = SCAN_TYPE_AUTO;
|
filter_clear_transport();
|
g_bt_scan_info.is_scaning = false;
|
return 0;
|
}
|
|
static void *a2dp_master_connect_thread(void *arg)
|
{
|
GDBusProxy *proxy;
|
char *address = (char *)arg;
|
static struct ConnectContext_t ctx;
|
ctx.proxy = NULL;
|
ctx.address = NULL;
|
pr_info("%s thread tid = %lu\n", __func__, pthread_self());
|
|
if(bt_is_scaning())
|
bt_cancel_discovery(RK_BT_DISC_STOPPED_BY_USER);
|
|
if(!bt_source_is_open()) {
|
pr_err("%s: bt source is not open\n", __func__);
|
a2dp_master_event_send(BT_SOURCE_EVENT_CONNECT_FAILED, address, address);
|
return NULL;
|
}
|
|
proxy = find_proxy_by_address(default_ctrl->devices, address);
|
if (!proxy) {
|
pr_info("%s: Device %s not available\n", __func__, address);
|
a2dp_master_event_send(BT_SOURCE_EVENT_CONNECT_FAILED, address, address);
|
return NULL;
|
}
|
|
g_device_state = BT_SOURCE_EVENT_DISCONNECTED;
|
a2dp_master_event_send(BT_SOURCE_EVENT_CONNECTTING, address, NULL);
|
ctx.proxy = proxy;
|
ctx.address = address;
|
if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
|
&ctx, NULL) == FALSE) {
|
//char name[256];
|
//memset(name, 0, 256);
|
//bt_get_device_name_by_proxy(proxy, name, 256);
|
|
pr_info("%s: Failed to connect\n", __func__);
|
a2dp_master_event_send(BT_SOURCE_EVENT_CONNECT_FAILED, address, address);
|
return NULL;
|
}
|
|
g_bt_source_info.is_connecting = true;
|
pr_info("%s: Attempting to connect to %s [proxy: %p]\n", __func__, address, proxy);
|
return NULL;
|
}
|
|
int a2dp_master_connect(char *t_address)
|
{
|
pthread_t tid;
|
int addr_len;
|
|
if (!t_address || (strlen(t_address) < 17)) {
|
pr_err("%s: Invalid address\n", __func__);
|
a2dp_master_event_send(BT_SOURCE_EVENT_CONNECT_FAILED, t_address, t_address);
|
return -1;
|
}
|
|
if (check_default_ctrl() == FALSE) {
|
a2dp_master_event_send(BT_SOURCE_EVENT_CONNECT_FAILED, t_address, t_address);
|
return -1;
|
}
|
|
memset(g_bt_source_info.connect_address, 0, sizeof(g_bt_source_info.connect_address));
|
addr_len = sizeof(g_bt_source_info.connect_address) > strlen(t_address) ?
|
strlen(t_address) : sizeof(g_bt_source_info.connect_address);
|
memcpy(g_bt_source_info.connect_address, t_address, addr_len);
|
|
if (pthread_create(&tid, NULL, a2dp_master_connect_thread, (void *)g_bt_source_info.connect_address)) {
|
pr_err("%s: source connect thread create failed!\n", __func__);
|
a2dp_master_event_send(BT_SOURCE_EVENT_CONNECT_FAILED, t_address, t_address);
|
return -1;
|
}
|
|
pthread_detach(tid);
|
return 0;
|
}
|
|
void ble_disconn_reply(DBusMessage *message, void *user_data)
|
{
|
GDBusProxy *proxy = (GDBusProxy *)user_data;
|
DBusError error;
|
|
dbus_error_init(&error);
|
|
if (dbus_set_error_from_message(&error, message) == TRUE) {
|
pr_info("Failed to disconnect: %s\n", error.name);
|
dbus_error_free(&error);
|
return;
|
}
|
|
if (proxy == ble_dev) {
|
pr_info("%s: Successful disconnected ble\n", __func__);
|
} else {
|
pr_info("%s: Failed disconnected ble\n", __func__);
|
}
|
}
|
|
int ble_disconnect()
|
{
|
if (!ble_dev) {
|
pr_info("%s: ble no connect\n", __func__);
|
return -1;
|
}
|
|
if(ble_is_open()) {
|
if(!remove_ble_device())
|
return;
|
}
|
|
if (g_dbus_proxy_method_call(ble_dev, "Disconnect", NULL, ble_disconn_reply,
|
ble_dev, NULL) == FALSE) {
|
pr_info("%s: Failed to disconnect\n", __func__);
|
return -1;
|
}
|
|
pr_info("%s: Attempting to disconnect ble from %s\n", __func__, proxy_address(ble_dev));
|
return 0;
|
}
|
|
int remove_ble_device()
|
{
|
DBusMessageIter iter;
|
const char *type = NULL;
|
|
if (!ble_dev) {
|
pr_info("%s: ble no connect\n", __func__);
|
return -1;
|
}
|
|
if (g_dbus_proxy_get_property(ble_dev, "AddressType", &iter)) {
|
dbus_message_iter_get_basic(&iter, &type);
|
pr_info("%s: AddressType = %s\n", __func__, type);
|
if (!strcmp(type, "public")) {
|
return remove_device(ble_dev);
|
}
|
}
|
|
return -1;
|
}
|
|
void ble_clean()
|
{
|
ble_service_cnt = 0;
|
ble_dev = NULL;
|
}
|
|
static int disconnect_by_proxy(GDBusProxy *proxy)
|
{
|
if (!proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply,
|
proxy, NULL) == FALSE) {
|
pr_info("Failed to disconnect\n");
|
return -1;
|
}
|
|
pr_info("%s: Attempting to disconnect from %s\n", __func__, proxy_address(proxy));
|
return 0;
|
}
|
|
/*
|
* Get the Bluetooth connection status.
|
* Input parameters:
|
* Addr_buff -> if not empty, the interface will resolve the address
|
* of the current connection and store it in addr_buf.
|
* return value:
|
* 0-> not connected;
|
* 1-> is connected;
|
*/
|
int a2dp_master_status(char *addr_buf, int addr_len, char *name_buf, int name_len)
|
{
|
DBusMessageIter iter;
|
const char *address;
|
const char *name;
|
|
if (!default_dev) {
|
pr_info("no source connect\n");
|
return 0;
|
}
|
|
if (addr_buf) {
|
if (g_dbus_proxy_get_property(default_dev, "Address", &iter) == FALSE) {
|
pr_info("WARING: Bluetooth connected, but can't get address!\n");
|
return 0;
|
}
|
dbus_message_iter_get_basic(&iter, &address);
|
memset(addr_buf, 0, addr_len);
|
memcpy(addr_buf, address, (strlen(address) > addr_len) ? addr_len : strlen(address));
|
}
|
|
if (name_buf) {
|
if (g_dbus_proxy_get_property(default_dev, "Alias", &iter) == FALSE) {
|
pr_info("WARING: Bluetooth connected, but can't get device name!\n");
|
return 0;
|
}
|
|
dbus_message_iter_get_basic(&iter, &name);
|
memset(name_buf, 0, name_len);
|
memcpy(name_buf, name, (strlen(name) > name_len) ? name_len : strlen(name));
|
}
|
|
return 1;
|
}
|
|
int remove_by_address(char *t_address)
|
{
|
GDBusProxy *proxy;
|
|
if(t_address == NULL) {
|
pr_err("%s: Invalid address\n", __func__);
|
return -1;
|
}
|
|
if (check_default_ctrl() == FALSE)
|
return -1;
|
|
if (strcmp(t_address, "*") == 0) {
|
GList *list;
|
|
for (list = default_ctrl->devices; list; list = g_list_next(list)) {
|
proxy = (GDBusProxy *)list->data;
|
remove_device(proxy);
|
}
|
return 0;
|
} else if ((strlen(t_address) < 17)) {
|
pr_err("%s: %s address error!\n", __func__, t_address);
|
return -1;
|
}
|
|
proxy = find_proxy_by_address(default_ctrl->devices, t_address);
|
if (!proxy) {
|
pr_info("Device %s not available\n", t_address);
|
return -1;
|
}
|
|
return remove_device(proxy);
|
}
|
|
int a2dp_master_save_status(char *address)
|
{
|
char buff[100] = {0};
|
struct sockaddr_un serverAddr;
|
int snd_cnt = 3;
|
int sockfd;
|
int send_len = 0;
|
|
sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
if (sockfd < 0) {
|
pr_info("FUNC:%s create sockfd failed!\n", __func__);
|
return 0;
|
}
|
|
serverAddr.sun_family = AF_UNIX;
|
strcpy(serverAddr.sun_path, "/tmp/a2dp_master_status");
|
|
memset(buff, 0, sizeof(buff));
|
if (address)
|
sprintf(buff, "status:connect;address:%s;", address);
|
else
|
sprintf(buff, "status:disconnect;");
|
|
while(snd_cnt--) {
|
send_len = sendto(sockfd, buff, strlen(buff), MSG_DONTWAIT, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
|
if(send_len == strlen(buff)) {
|
pr_info("%s: send: %s(%d)\n", __func__, buff, send_len);
|
break;
|
}
|
|
usleep(1000);
|
}
|
|
close(sockfd);
|
return 0;
|
}
|
|
void a2dp_master_event_send(RK_BT_SOURCE_EVENT event, char *dev_addr, char *dev_name)
|
{
|
if(!g_bt_callback.bt_source_event_cb || !bt_source_is_open())
|
return;
|
|
if ((event == BT_SOURCE_EVENT_CONNECTED) || (event == BT_SOURCE_EVENT_DISCONNECTED))
|
g_device_state = event;
|
|
pr_info("%s: state: %d, addr: %s, name: %s.\n", __func__, event, dev_addr, dev_name);
|
|
if(!dev_addr && !dev_name) {
|
char addr[18], name[256];
|
|
memset(addr, 0, 18);
|
memset(name, 0, 256);
|
bt_get_device_addr_by_proxy(default_dev, addr, 18);
|
bt_get_device_name_by_proxy(default_dev, name, 256);
|
|
g_bt_callback.bt_source_event_cb(g_btmaster_userdata, addr, name, event);
|
} else {
|
g_bt_callback.bt_source_event_cb(g_btmaster_userdata, dev_addr, dev_name, event);
|
}
|
}
|
|
void a2dp_master_register_cb(void *userdata, RK_BT_SOURCE_CALLBACK cb)
|
{
|
g_bt_callback.bt_source_event_cb = cb;
|
g_btmaster_userdata = userdata;
|
return;
|
}
|
|
void a2dp_master_deregister_cb()
|
{
|
g_bt_callback.bt_source_event_cb = NULL;
|
g_btmaster_userdata = NULL;
|
return;
|
}
|
|
/**********************************************
|
* bt source avrcp
|
**********************************************/
|
static void save_last_device(GDBusProxy *proxy)
|
{
|
int fd;
|
const char *object_path, *address;
|
DBusMessageIter iter, class_iter;
|
dbus_uint32_t valu32;
|
char buff[512] = {0};
|
|
pr_info("%s\n", __func__);
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) {
|
pr_info("Get adapter address error");
|
return;
|
}
|
|
dbus_message_iter_get_basic(&iter, &address);
|
pr_info("Connected device address: %s\n", address);
|
|
if (g_dbus_proxy_get_property(proxy, "Class", &class_iter) == FALSE) {
|
pr_info("Get adapter Class error\n");
|
return;
|
}
|
|
dbus_message_iter_get_basic(&class_iter, &valu32);
|
pr_info("Connected device class: 0x%x\n", valu32);
|
|
object_path = g_dbus_proxy_get_path(proxy);
|
pr_info("Connected device object path: %s\n", object_path);
|
|
fd = open(BT_RECONNECT_CFG, O_RDWR | O_CREAT | O_TRUNC, 0644);
|
if (fd == -1) {
|
pr_info("Open %s error: %s\n", BT_RECONNECT_CFG, strerror(errno));
|
return;
|
}
|
|
sprintf(buff, "ADDRESS:%s;CLASS:%x;PATH:%s;", address, valu32, object_path);
|
write(fd, buff, strlen(buff));
|
fsync(fd);
|
close(fd);
|
}
|
|
static int load_last_device(char *address)
|
{
|
int fd, ret, i;
|
char buff[512] = {0};
|
char *start = NULL, *end = NULL;
|
|
pr_info("Load path %s\n", BT_RECONNECT_CFG);
|
|
ret = access(BT_RECONNECT_CFG, F_OK);
|
if (ret == -1) {
|
pr_info("%s does not exist\n", BT_RECONNECT_CFG);
|
return -1;
|
}
|
|
fd = open(BT_RECONNECT_CFG, O_RDONLY);
|
if (fd == -1) {
|
pr_info("Open %s error: %s\n", BT_RECONNECT_CFG, strerror(errno));
|
return -1;
|
}
|
|
ret = read(fd, buff, sizeof(buff));
|
if (ret < 0) {
|
pr_info("read %s error: %s\n", BT_RECONNECT_CFG, strerror(errno));
|
close(fd);
|
return -1;
|
}
|
|
start = strstr(buff, "ADDRESS:");
|
end = strstr(buff, ";");
|
if (!start || !end || (end < start)) {
|
pr_info("file %s content invalid(address): %s\n", BT_RECONNECT_CFG, buff);
|
close(fd);
|
return -1;
|
}
|
start += strlen("ADDRESS:");
|
if (address)
|
memcpy(address, start, end - start);
|
|
close(fd);
|
return 0;
|
}
|
|
static void reconn_last_device_reply(DBusMessage * message, void *user_data)
|
{
|
DBusError err;
|
|
dbus_error_init(&err);
|
if (dbus_set_error_from_message(&err, message) == TRUE) {
|
pr_info("Reconnect failed!\n");
|
dbus_error_free(&err);
|
}
|
}
|
|
int reconn_last_devices(BtDeviceType type)
|
{
|
GDBusProxy *proxy;
|
DBusMessageIter addr_iter, addrType_iter;
|
int fd, ret, reconnect = 1;
|
char buff[100] = {0};
|
char address[48] = {0};
|
enum BT_Device_Class device_class;
|
|
fd = open("/userdata/cfg/bt_reconnect", O_RDONLY);
|
if (fd > 0) {
|
ret = read(fd, buff, sizeof(buff));
|
if (ret > 0) {
|
if (strstr(buff, "bluez-reconnect:disable"))
|
reconnect = 0;
|
}
|
close(fd);
|
}
|
|
if (reconnect == 0) {
|
pr_info("%s: automatic reconnection is disabled!\n", __func__);
|
return 0;
|
}
|
|
if (bt_is_connected()) {
|
pr_info("%s: The device is connected and does not need to be reconnected!\n", __func__);
|
return 0;
|
}
|
|
ret = load_last_device(address);
|
if (ret < 0)
|
return ret;
|
|
proxy = find_device_by_address(address);
|
if (!proxy) {
|
pr_info("Invalid proxy, stop reconnecting\n");
|
return -1;
|
}
|
|
device_class = dist_dev_class(proxy);
|
if (device_class == BT_IDLE) {
|
pr_info("Invalid device_class, stop reconnecting\n");
|
return -1;
|
}
|
|
if(type == BT_DEVICES_A2DP_SINK) {
|
pr_info("%s: source reconnected(%s)\n", __func__, address);
|
memset(g_bt_source_info.reconnect_address, 0, sizeof(g_bt_source_info.reconnect_address));
|
memcpy(g_bt_source_info.reconnect_address, address, sizeof(g_bt_source_info.reconnect_address));
|
source_set_reconnect_tag(true);
|
return 0;
|
}
|
|
switch(type) {
|
case BT_DEVICES_A2DP_SINK:
|
if (device_class != BT_SINK_DEVICE)
|
reconnect = 0;
|
break;
|
case BT_DEVICES_A2DP_SOURCE:
|
if (device_class != BT_SOURCE_DEVICE)
|
reconnect = 0;
|
break;
|
case BT_DEVICES_BLE:
|
if (device_class != BT_BLE_DEVICE)
|
reconnect = 0;
|
break;
|
case BT_DEVICES_HFP:
|
if (device_class != BT_SOURCE_DEVICE)
|
reconnect = 0;
|
break;
|
case BT_DEVICES_SPP:
|
break;
|
default:
|
reconnect = 0;
|
}
|
|
if (reconnect == 0) {
|
pr_info("Unable to find a suitable reconnect device!\n");
|
return -1;
|
}
|
|
if(type == BT_DEVICES_A2DP_SINK) {
|
a2dp_master_connect(address);
|
} else {
|
if(bt_is_scaning())
|
bt_cancel_discovery(RK_BT_DISC_STOPPED_BY_USER);
|
|
if (g_dbus_proxy_method_call(proxy, "Connect", NULL,
|
reconn_last_device_reply, NULL, NULL) == FALSE) {
|
pr_info("Failed to call org.bluez.Device1.Connect\n");
|
return -1;
|
}
|
}
|
|
return 0;
|
}
|
|
int disconnect_current_devices()
|
{
|
if (!default_dev) {
|
pr_info("%s: No connected device\n", __func__);
|
return -1;
|
}
|
|
return disconnect_by_proxy(default_dev);
|
}
|
|
int get_dev_platform(char *address)
|
{
|
int vendor = -1, platform = DEV_PLATFORM_UNKNOWN;
|
char *str;
|
const char *valstr;
|
GDBusProxy *proxy;
|
DBusMessageIter iter;
|
|
if(!address) {
|
pr_info("%s: Invalid address\n", __func__);
|
return DEV_PLATFORM_UNKNOWN;
|
}
|
|
proxy = find_device_by_address(address);
|
if (!proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return DEV_PLATFORM_UNKNOWN;
|
}
|
|
if (g_dbus_proxy_get_property(proxy, "Modalias", &iter) == FALSE) {
|
pr_info("%s: WARING: can't get Modalias!\n", __func__);
|
return DEV_PLATFORM_UNKNOWN;
|
}
|
|
dbus_message_iter_get_basic(&iter, &valstr);
|
pr_info("%s: Modalias valstr = %s\n", __func__, valstr);
|
|
str = strstr(valstr, "v");
|
if(str) {
|
if(!strncasecmp(str + 1, "004c", 4))
|
vendor = IOS_VENDOR_SOURCE_BT;
|
else if(!strncasecmp(str + 1, "05ac", 4))
|
vendor = IOS_VENDOR_SOURCE_USB;
|
}
|
|
if(vendor == IOS_VENDOR_SOURCE_BT || vendor == IOS_VENDOR_SOURCE_USB)
|
platform = DEV_PLATFORM_IOS;
|
|
pr_info("%s: %s is %s\n", __func__, address,
|
platform == DEV_PLATFORM_UNKNOWN ? "Unknown Platform" : "Apple IOS");
|
|
return platform;
|
}
|
|
int get_current_dev_platform()
|
{
|
if (!default_dev) {
|
pr_info("%s: No connected device\n", __func__);
|
return DEV_PLATFORM_UNKNOWN;
|
}
|
|
return get_dev_platform(proxy_address(default_dev));
|
}
|
|
static void connect_by_address_reply(DBusMessage *message, void *user_data)
|
{
|
GDBusProxy *proxy = (GDBusProxy*)user_data;
|
DBusError error;
|
|
dbus_error_init(&error);
|
|
if (dbus_set_error_from_message(&error, message) == TRUE) {
|
pr_info("%s: Failed to connect: %s\n", __func__, error.name);
|
dbus_error_free(&error);
|
//set_default_device(NULL, NULL);
|
return bt_shell_noninteractive_quit(EXIT_FAILURE);
|
}
|
|
pr_info("%s: Connection successful\n", __func__);
|
//set_default_device(proxy, NULL);
|
|
return bt_shell_noninteractive_quit(EXIT_SUCCESS);
|
}
|
|
int connect_by_address(char *addr)
|
{
|
GDBusProxy *proxy;
|
|
if (!addr || (strlen(addr) < 17)) {
|
pr_err("%s: Invalid address\n", __func__);
|
return -1;
|
}
|
|
proxy = find_device_by_address(addr);
|
if (!proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
if(bt_is_scaning())
|
bt_cancel_discovery(RK_BT_DISC_STOPPED_BY_USER);
|
|
if (g_dbus_proxy_method_call(proxy, "Connect", NULL,
|
connect_by_address_reply, proxy, NULL) == FALSE) {
|
pr_info("%s: Failed to call org.bluez.Device1.Connect\n", __func__);
|
return -1;
|
}
|
|
pr_info("%s: Attempting to connect to %s\n", __func__, addr);
|
return 0;
|
}
|
|
int disconnect_by_address(char *addr)
|
{
|
GDBusProxy *proxy;
|
|
if (!addr || (strlen(addr) < 17)) {
|
pr_err("%s: Invalid address\n", __func__);
|
return -1;
|
}
|
|
proxy = find_device_by_address(addr);
|
if (!proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
return disconnect_by_proxy(proxy);
|
}
|
|
void bt_display_devices()
|
{
|
cmd_devices(NULL);
|
}
|
|
void bt_display_paired_devices()
|
{
|
cmd_paired_devices();
|
}
|
|
RkBtScanedDevice *bt_create_one_scaned_dev(GDBusProxy *proxy)
|
{
|
DBusMessageIter iter;
|
const char *address, *name;
|
dbus_int16_t rssi = -100;
|
dbus_bool_t is_connected = FALSE;
|
dbus_uint32_t cod = 0;
|
|
RkBtScanedDevice *new_device = (RkBtScanedDevice*)malloc(sizeof(RkBtScanedDevice));
|
if(!new_device) {
|
pr_err("%s: malloc one scaned device failed\n", __func__);
|
return NULL;
|
}
|
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter))
|
dbus_message_iter_get_basic(&iter, &address);
|
else
|
address = "<unknown>";
|
pr_info(" addr: %s\n", address);
|
|
if (g_dbus_proxy_get_property(proxy, "Alias", &iter))
|
dbus_message_iter_get_basic(&iter, &name);
|
else
|
name = "<unknown>";
|
pr_info(" name: %s\n", name);
|
|
if (g_dbus_proxy_get_property(proxy, "Connected", &iter))
|
dbus_message_iter_get_basic(&iter, &is_connected);
|
else
|
pr_info("%s: Can't get connected status\n", __func__);
|
pr_info(" Connected: %d\n", is_connected);
|
|
if(g_dbus_proxy_get_property(proxy, "Class", &iter))
|
dbus_message_iter_get_basic(&iter, &cod);
|
else
|
pr_info("%s: Can't get class of device\n", __func__);
|
pr_info(" Class: 0x%x\n", cod);
|
|
new_device->remote_address = (char *)malloc(strlen(address) + 1);
|
if(!new_device->remote_address) {
|
pr_err("%s: malloc remote_address failed\n", __func__);
|
return NULL;
|
}
|
strncpy(new_device->remote_address, address, strlen(address));
|
new_device->remote_address[strlen(address)] = '\0';
|
|
new_device->remote_name = (char *)malloc(strlen(name) + 1);
|
if(!new_device->remote_name) {
|
pr_err("%s: malloc remote_name failed\n", __func__);
|
return NULL;
|
}
|
strncpy(new_device->remote_name, name, strlen(name));
|
new_device->remote_name[strlen(name)] = '\0';
|
|
new_device->is_connected = is_connected;
|
new_device->cod = cod;
|
new_device->next = NULL;
|
|
return new_device;
|
}
|
|
static int list_scaned_dev_push_back(RkBtScanedDevice **dev_list, GDBusProxy *proxy)
|
{
|
if(dev_list == NULL) {
|
pr_info("%s: invalid dev_list\n", __func__);
|
return -1;
|
}
|
|
if(*dev_list == NULL) {
|
*dev_list = bt_create_one_scaned_dev(proxy);
|
if(*dev_list == NULL)
|
return -1;
|
} else {
|
RkBtScanedDevice *cur_dev = *dev_list;
|
while(cur_dev->next != NULL)
|
cur_dev = cur_dev->next;
|
|
RkBtScanedDevice *new_dev = bt_create_one_scaned_dev(proxy);
|
if(!new_dev)
|
return -1;
|
|
cur_dev->next = new_dev;
|
}
|
|
return 0;
|
}
|
|
int bt_get_scaned_devices(RkBtScanedDevice **dev_list, int *count, bool paired)
|
{
|
GList *ll;
|
|
*count = 0;
|
if (check_default_ctrl() == FALSE)
|
return -1;
|
|
for (ll = g_list_first(default_ctrl->devices);
|
ll; ll = g_list_next(ll)) {
|
GDBusProxy *proxy = (GDBusProxy *)ll->data;
|
|
if(paired) {
|
DBusMessageIter iter;
|
dbus_bool_t paired;
|
|
if (g_dbus_proxy_get_property(proxy, "Paired", &iter) == FALSE)
|
continue;
|
|
dbus_message_iter_get_basic(&iter, &paired);
|
if (!paired)
|
continue;
|
}
|
if(!list_scaned_dev_push_back(dev_list, proxy))
|
(*count)++;
|
}
|
|
pr_info("%s: paired = %d, count = %d\n", __func__, paired, *count);
|
return 0;
|
}
|
|
int bt_free_scaned_devices(RkBtScanedDevice *dev_list)
|
{
|
RkBtScanedDevice *dev_tmp = NULL;
|
|
if(dev_list == NULL) {
|
pr_info("%s: dev_list is null, don't need to clear\n", __func__);
|
return -1;
|
}
|
|
while(dev_list->next != NULL) {
|
pr_info("%s: free dev: %s\n", __func__, dev_list->remote_address);
|
dev_tmp = dev_list->next;
|
free(dev_list->remote_address);
|
free(dev_list->remote_name);
|
free(dev_list);
|
dev_list = dev_tmp;
|
}
|
|
if(dev_list != NULL) {
|
pr_info("%s: last free dev: %s\n", __func__, dev_list->remote_address);
|
free(dev_list->remote_address);
|
free(dev_list->remote_name);
|
free(dev_list);
|
dev_list = NULL;
|
}
|
|
return 0;
|
}
|
|
int pair_by_addr(char *addr)
|
{
|
GDBusProxy *proxy;
|
char dev_name[256];
|
|
if (!addr || (strlen(addr) < 17)) {
|
pr_err("%s: Invalid address\n", __func__);
|
return -1;
|
}
|
|
proxy = find_device_by_address(addr);
|
if (!proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
bt_get_device_name_by_proxy(proxy, dev_name, 256);
|
bt_bond_state_send(addr, dev_name, RK_BT_BOND_STATE_BONDING);
|
|
return cmd_pair(proxy);
|
}
|
|
int unpair_by_addr(char *addr)
|
{
|
GDBusProxy *proxy;
|
|
if (!addr || (strlen(addr) < 17)) {
|
pr_err("%s: Invalid address\n", __func__);
|
return -1;
|
}
|
|
pr_info("%s\n", __func__);
|
proxy = find_device_by_address(addr);
|
if (!proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
/* There is no direct unpair method, removing device will clear pairing information */
|
return remove_device(proxy);
|
}
|
|
int bt_set_device_name(char *name)
|
{
|
if (!name) {
|
pr_info("%s: Invalid bt name: %s\n", __func__, name);
|
return -1;
|
}
|
|
if (check_default_ctrl() == FALSE)
|
return -1;
|
|
if (!default_ctrl->proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
if (g_dbus_proxy_set_property_basic(default_ctrl->proxy, "Alias",
|
DBUS_TYPE_STRING, &name,
|
generic_callback, name, NULL) == FALSE) {
|
pr_info("%s: set Alias property error\n", __func__);
|
return -1;
|
}
|
|
pr_info("%s: Attempting to set device name %s\n", __func__, name);
|
return 0;
|
}
|
|
int bt_get_device_name_by_proxy(GDBusProxy *proxy,
|
char *name_buf, int name_len)
|
{
|
DBusMessageIter iter;
|
const char *name;
|
|
if (!proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
if (!name_buf || name_len <= 0) {
|
pr_info("%s: Invalid name buffer, name_len: %d\n", __func__, name_len);
|
return -1;
|
}
|
|
memset(name_buf, 0, name_len);
|
if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == FALSE) {
|
pr_info("WARING: Bluetooth connected, but can't get device name!\n");
|
return -1;
|
}
|
|
dbus_message_iter_get_basic(&iter, &name);
|
memcpy(name_buf, name, (strlen(name) > name_len) ? name_len : strlen(name));
|
|
return 0;
|
}
|
|
int bt_get_device_name(char *name_buf, int name_len)
|
{
|
if (check_default_ctrl() == FALSE)
|
return -1;
|
|
if (!default_ctrl->proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
return bt_get_device_name_by_proxy(default_ctrl->proxy, name_buf, name_len);
|
}
|
|
int bt_get_device_addr_by_proxy(GDBusProxy *proxy,
|
char *addr_buf, int addr_len)
|
{
|
DBusMessageIter iter;
|
const char *address;
|
|
if (!proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
if (!addr_buf || addr_len < 17) {
|
pr_info("%s: Invalid address buffer, addr_len: %d\n", __func__, addr_len);
|
return -1;
|
}
|
|
memset(addr_buf, 0, addr_len);
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE) {
|
pr_info("WARING: Bluetooth connected, but can't get address!\n");
|
return -1;
|
}
|
|
dbus_message_iter_get_basic(&iter, &address);
|
memcpy(addr_buf, address, (strlen(address) > addr_len) ? addr_len : strlen(address));
|
|
return 0;
|
}
|
|
int bt_get_device_addr(char *addr_buf, int addr_len)
|
{
|
if (check_default_ctrl() == FALSE)
|
return -1;
|
|
if (!default_ctrl->proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
return bt_get_device_addr_by_proxy(default_ctrl->proxy, addr_buf, addr_len);
|
}
|
|
|
int bt_get_default_dev_addr(char *addr_buf, int addr_len)
|
{
|
if (!default_dev) {
|
pr_info("%s: no connected device\n", __func__);
|
return -1;
|
}
|
|
return bt_get_device_addr_by_proxy(default_dev, addr_buf, addr_len);
|
}
|
|
static void reomve_unpaired_device ()
|
{
|
GDBusProxy *proxy;
|
DBusMessageIter iter;
|
GList *list;
|
|
if (check_default_ctrl() == FALSE)
|
return;
|
|
for (list = default_ctrl->devices; list;
|
list = g_list_next(list)) {
|
dbus_bool_t paired = FALSE;
|
dbus_bool_t connected = FALSE;
|
|
GDBusProxy *proxy = (GDBusProxy *)list->data;
|
|
if (g_dbus_proxy_get_property(proxy, "Paired", &iter))
|
dbus_message_iter_get_basic(&iter, &paired);
|
|
if (g_dbus_proxy_get_property(proxy, "Connected", &iter))
|
dbus_message_iter_get_basic(&iter, &connected);
|
|
if (paired || connected) {
|
const char *address;
|
if (g_dbus_proxy_get_property(proxy, "Address", &iter)) {
|
dbus_message_iter_get_basic(&iter, &address);
|
pr_info("%s: address(%s) is paired(%d) or connected(%d)\n", __func__, address, paired, connected);
|
}
|
continue;
|
}
|
|
remove_device(proxy);
|
}
|
|
return;
|
}
|
|
int bt_get_eir_data(char *address, char *eir_data, int eir_len)
|
{
|
DBusMessageIter iter;
|
DBusMessageIter array;
|
unsigned char *data;
|
int len, data_len = 0;
|
struct GDBusProxy *proxy;
|
|
if (!address || (strlen(address) < 17)) {
|
pr_err("%s: invalid address\n", __func__);
|
return -1;
|
}
|
|
if (!eir_data) {
|
pr_err("%s: invalid eir_data buf\n", __func__);
|
return -1;
|
}
|
|
proxy = find_device_by_address(address);
|
if (proxy == NULL)
|
return -1;
|
|
if (g_dbus_proxy_get_property(proxy, "EirData", &iter) == FALSE) {
|
pr_err("%s: get EirData data failed\n", __func__);
|
return- 1;
|
}
|
|
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
|
pr_err("%s: iter type != DBUS_TYPE_ARRAY\n", __func__);
|
return -1;
|
}
|
|
dbus_message_iter_recurse(&iter, &array);
|
|
if (!dbus_type_is_fixed(dbus_message_iter_get_arg_type(&array))) {
|
pr_err("%s: dbus type isn't fixed\n", __func__);
|
return -1;
|
}
|
|
if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_BYTE) {
|
pr_err("%s: iter type != DBUS_TYPE_BYTE\n", __func__);
|
return -1;
|
}
|
|
dbus_message_iter_get_fixed_array(&array, &data, &data_len);
|
if (data_len <= 0) {
|
pr_err("%s: get EirData data failed, len = %d\n", __func__, data_len);
|
return -1;
|
}
|
|
pr_err("%s: get EirData data, data_len = %d\n", __func__, data_len);
|
|
bt_shell_hexdump((void *)data, data_len * sizeof(*data));
|
|
len = data_len > eir_len ? eir_len : data_len;
|
memset(eir_data, 0, eir_len);
|
memcpy(eir_data, data, len);
|
|
return len;
|
}
|
|
int bt_start_discovery(unsigned int mseconds, RK_BT_SCAN_TYPE scan_type)
|
{
|
int ret;
|
|
if (bt_is_scaning()) {
|
pr_info("%s: devices discovering\n", __func__);
|
return -1;
|
}
|
|
g_bt_scan_info.is_scaning = true;
|
g_bt_scan_info.scan_type = scan_type;
|
|
reomve_unpaired_device();
|
|
pr_info("=== scan on ===\n");
|
//exec_command_system("hciconfig hci0 noscan");
|
if(cmd_scan("on") < 0) {
|
bt_discovery_state_send(RK_BT_DISC_START_FAILED);
|
}
|
|
return 0;
|
}
|
|
int bt_cancel_discovery(RK_BT_DISCOVERY_STATE state)
|
{
|
int wait_cnt = 100;
|
|
if (!g_bt_scan_info.is_scaning) {
|
pr_info("%s: discovery canceling or canceled\n", __func__);
|
return 0;
|
}
|
|
pr_info("%s thread tid = %lu\n", __func__, pthread_self());
|
|
if (bt_is_discovering()) {
|
pr_info("=== %s scan off again===\n", __func__);
|
cmd_scan("off");
|
}
|
|
return 0;
|
}
|
|
bool bt_is_scaning()
|
{
|
return bt_is_discovering() || g_bt_scan_info.is_scaning;
|
}
|
|
bool bt_is_discovering()
|
{
|
DBusMessageIter iter;
|
dbus_bool_t valbool;
|
|
if (check_default_ctrl() == FALSE)
|
return false;
|
|
if (!default_ctrl->proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return false;
|
}
|
|
if (g_dbus_proxy_get_property(default_ctrl->proxy, "Discovering", &iter) == FALSE) {
|
pr_info("WARING: Bluetooth connected, but can't get Discovering!\n");
|
return false;
|
}
|
|
dbus_message_iter_get_basic(&iter, &valbool);
|
|
return valbool;
|
}
|
|
/*
|
* / # hcitool con
|
* Connections:
|
* > ACL 64:A2:F9:68:1E:7E handle 1 state 1 lm SLAVE AUTH ENCRYPT
|
* > LE 60:9C:59:31:7F:B9 handle 16 state 1 lm SLAVE
|
*/
|
bool bt_is_connected()
|
{
|
bool ret = false;
|
char buf[1024];
|
|
memset(buf, 0, 1024);
|
exec_command("hcitool con", buf, 1024);
|
usleep(300000);
|
|
if (strstr(buf, "ACL") || strstr(buf, "LE"))
|
ret = true;
|
|
return ret;
|
}
|
|
RK_BT_PLAYROLE_TYPE bt_get_playrole_by_addr(char *addr)
|
{
|
GDBusProxy *proxy;
|
|
if (!addr || (strlen(addr) < 17)) {
|
pr_err("%s: Invalid address\n", __func__);
|
return -1;
|
}
|
|
proxy = find_device_by_address(addr);
|
if (!proxy) {
|
pr_err("%s: Invalid proxy\n", __func__);
|
return -1;
|
}
|
|
return a2dp_master_get_playrole(proxy);
|
}
|
|
void source_set_reconnect_tag(bool reconnect)
|
{
|
g_bt_source_info.is_reconnected = reconnect;
|
}
|
|
void source_stop_connecting()
|
{
|
if(g_bt_source_info.is_connecting) {
|
pr_info("%s\n", __func__);
|
if(!disconnect_by_address(g_bt_source_info.connect_address))
|
sleep(3);
|
}
|
}
|
|
bool get_device_connected_properties(char *addr)
|
{
|
GDBusProxy *proxy;
|
DBusMessageIter iter;
|
dbus_bool_t is_connected = FALSE;
|
|
if (!addr || (strlen(addr) < 17)) {
|
pr_err("%s: Invalid address\n", __func__);
|
return false;
|
}
|
|
proxy = find_device_by_address(addr);
|
if (!proxy) {
|
pr_info("%s: Invalid proxy\n", __func__);
|
return false;
|
}
|
|
if (g_dbus_proxy_get_property(proxy, "Connected", &iter))
|
dbus_message_iter_get_basic(&iter, &is_connected);
|
else
|
pr_info("%s: Can't get connected status\n", __func__);
|
|
return is_connected;
|
}
|