Skip to content

Commit

Permalink
Add bluetoothctl bluetooth driver
Browse files Browse the repository at this point in the history
  • Loading branch information
parport0 committed Jun 24, 2020
1 parent 8486c8e commit 23c08ad
Show file tree
Hide file tree
Showing 29 changed files with 904 additions and 36 deletions.
9 changes: 9 additions & 0 deletions Makefile.common
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,10 @@ ifeq ($(HAVE_EMSCRIPTEN), 1)
camera/drivers/rwebcam.o
endif

ifeq ($(HAVE_BLUETOOTH), 1)
OBJ += bluetooth/drivers/bluetoothctl.o
endif

ifeq ($(HAVE_LAKKA), 1)
OBJ += wifi/drivers/connmanctl.o
endif
Expand Down Expand Up @@ -809,6 +813,10 @@ ifeq ($(HAVE_MENU), 1)
endif
endif

ifeq ($(HAVE_BLUETOOTH), 1)
DEFINES += -DHAVE_BLUETOOTH
endif

ifeq ($(HAVE_LAKKA), 1)
DEFINES += -DHAVE_LAKKA
endif
Expand Down Expand Up @@ -1793,6 +1801,7 @@ ifeq ($(HAVE_NETWORKING), 1)
tasks/task_http.o \
tasks/task_netplay_lan_scan.o \
tasks/task_netplay_nat_traversal.o \
tasks/task_bluetooth.o \
tasks/task_wifi.o \
tasks/task_pl_thumbnail_download.o \
tasks/task_netplay_find_content.o
Expand Down
87 changes: 87 additions & 0 deletions bluetooth/bluetooth_driver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* RetroArch - A frontend for libretro.
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __BLUETOOTH_DRIVER__H
#define __BLUETOOTH_DRIVER__H

#include <stdint.h>

#include <boolean.h>
#include <retro_common_api.h>
#include <lists/string_list.h>

RETRO_BEGIN_DECLS

enum rarch_bluetooth_ctl_state
{
RARCH_BLUETOOTH_CTL_NONE = 0,
RARCH_BLUETOOTH_CTL_DESTROY,
RARCH_BLUETOOTH_CTL_DEINIT,
RARCH_BLUETOOTH_CTL_SET_ACTIVE,
RARCH_BLUETOOTH_CTL_UNSET_ACTIVE,
RARCH_BLUETOOTH_CTL_IS_ACTIVE,
RARCH_BLUETOOTH_CTL_FIND_DRIVER,
RARCH_BLUETOOTH_CTL_SET_CB,
RARCH_BLUETOOTH_CTL_STOP,
RARCH_BLUETOOTH_CTL_START,
RARCH_BLUETOOTH_CTL_INIT
};

typedef struct bluetooth_driver
{
void *(*init)(void);

void (*free)(void *data);

bool (*start)(void *data);
void (*stop)(void *data);

void (*scan)(void);
void (*get_devices)(struct string_list *list);
bool (*device_is_connected)(unsigned i);
bool (*connect_device)(unsigned i);

const char *ident;
} bluetooth_driver_t;

extern bluetooth_driver_t bluetooth_bluetoothctl;

/**
* config_get_bluetooth_driver_options:
*
* Get an enumerated list of all bluetooth driver names,
* separated by '|'.
*
* Returns: string listing of all bluetooth driver names,
* separated by '|'.
**/
const char* config_get_bluetooth_driver_options(void);

void driver_bluetooth_stop(void);

bool driver_bluetooth_start(void);

void driver_bluetooth_scan(void);

void driver_bluetooth_get_devices(struct string_list *list);

bool driver_bluetooth_device_is_connected(unsigned i);

bool driver_bluetooth_connect_device(unsigned i);

bool bluetooth_driver_ctl(enum rarch_bluetooth_ctl_state state, void *data);

RETRO_END_DECLS

#endif
203 changes: 203 additions & 0 deletions bluetooth/drivers/bluetoothctl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/* RetroArch - A frontend for libretro.
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/

#include <compat/strl.h>
#include <configuration.h>

#include "../bluetooth_driver.h"
#include "../../retroarch.h"

static bool bluetoothctl_cache[256] = {0};
static unsigned bluetoothctl_counter[256] = {0};
static struct string_list* lines = NULL;
static char command[256] = {0};

static void *bluetoothctl_init(void)
{
return (void*)-1;
}

static void bluetoothctl_free(void *data)
{
(void)data;
}

static bool bluetoothctl_start(void *data)
{
(void)data;
return true;
}

static void bluetoothctl_stop(void *data)
{
(void)data;
}

static void bluetoothctl_scan(void)
{
char line[512];
union string_list_elem_attr attr;
FILE *dev_file = NULL;

attr.i = 0;
if (lines)
free(lines);
lines = string_list_new();

pclose(popen("bluetoothctl -- power on", "r"));

pclose(popen("bluetoothctl --timeout 15 scan on", "r"));

runloop_msg_queue_push(msg_hash_to_str(MSG_BLUETOOTH_SCAN_COMPLETE),
1, 180, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT,
MESSAGE_QUEUE_CATEGORY_INFO);

dev_file = popen("bluetoothctl -- devices", "r");
while (fgets(line, 512, dev_file))
{
size_t len = strlen(line);
if (len > 0 && line[len-1] == '\n')
line[--len] = '\0';

string_list_append(lines, line, attr);
}
pclose(dev_file);
}

static void bluetoothctl_get_devices(struct string_list* devices)
{
unsigned i;
union string_list_elem_attr attr;
attr.i = 0;

if (!lines)
return;

for (i = 0; i < lines->size; i++)
{
char device[64];
const char *line = lines->elems[i].data;

/* bluetoothctl devices outputs lines of the format:
* $ bluetoothctl devices
* 'Device (mac address) (device name)'
*/
strlcpy(device, line+7, sizeof(device));
string_list_append(devices, device, attr);
}
}

static bool bluetoothctl_device_is_connected(unsigned i)
{
char ln[512] = {0};
char device[18] = {0};
const char *line = lines->elems[i].data;
FILE *command_file = NULL;

if (bluetoothctl_counter[i] == 60)
{
static struct string_list* list = NULL;
bluetoothctl_counter[i] = 0;
list = string_split(line, " ");
if (!list)
return false;

if (list->size == 0)
{
string_list_free(list);
return false;
}

strlcpy(device, list->elems[1].data, sizeof(device));
string_list_free(list);

snprintf(command, sizeof(command), "\
bluetoothctl -- info %s | grep 'Connected: yes'",
device);

command_file = popen(command, "r");

while (fgets(ln, 512, command_file))
{
bluetoothctl_cache[i] = true;
return true;
}
pclose(command_file);
bluetoothctl_cache[i] = false;
}
else
{
bluetoothctl_counter[i]++;
return bluetoothctl_cache[i];
}

return false;
}

static bool bluetoothctl_connect_device(unsigned idx)
{
unsigned i;
char device[18] = {0};
const char *line = lines->elems[idx].data;
static struct string_list* list = NULL;
/* bluetoothctl devices outputs lines of the format:
* $ bluetoothctl devices
* 'Device (mac address) (device name)'
*/
list = string_split(line, " ");
if (!list)
return false;

if (list->size == 0)
{
string_list_free(list);
return false;
}

strlcpy(device, list->elems[1].data, sizeof(device));
string_list_free(list);

snprintf(command, sizeof(command), "\
bluetoothctl -- trust %s",
device);

pclose(popen(command, "r"));

snprintf(command, sizeof(command), "\
bluetoothctl -- pair %s",
device);

pclose(popen(command, "r"));

snprintf(command, sizeof(command), "\
bluetoothctl -- connect %s",
device);

pclose(popen(command, "r"));

bluetoothctl_counter[idx] = 0;
return true;
}

bluetooth_driver_t bluetooth_bluetoothctl = {
bluetoothctl_init,
bluetoothctl_free,
bluetoothctl_start,
bluetoothctl_stop,
bluetoothctl_scan,
bluetoothctl_get_devices,
bluetoothctl_device_is_connected,
bluetoothctl_connect_device,
"bluetoothctl",
};
Loading

0 comments on commit 23c08ad

Please sign in to comment.