From 0b4428824a815bc14140345c742b4ff2f38660a2 Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Mon, 14 May 2018 15:47:54 +0200 Subject: [PATCH] Simple tool for sending RFCOMM commands One might use it as follows: $ printf "+VGS=15" |bluealsa-rfcomm 01:23:45:67:89:AB $ printf "RING\nSLEEP 3\nRING" |bluealsa-rfcomm 01:23:45:67:89:AB --- .travis.yml | 1 + LICENSE.txt | 3 +- configure.ac | 4 ++ utils/Makefile.am | 16 ++++- utils/rfcomm.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 utils/rfcomm.c diff --git a/.travis.yml b/.travis.yml index 60cfb2a05..252daa9e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ addons: - libfdk-aac-dev - libglib2.0-dev - libncurses5-dev + - libreadline-dev - libsbc-dev before_script: diff --git a/LICENSE.txt b/LICENSE.txt index d8414e4bf..b0c6144f1 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,7 @@ The MIT License -Copyright (c) 2016-2017 Arkadiusz Bokowy +Copyright (c) 2016-2018 Arkadiusz Bokowy + 2018 Wade Berrier 2017 Guillaume Zin 2017 Juha Kuikka diff --git a/configure.ac b/configure.ac index 60d3807d2..092752a69 100644 --- a/configure.ac +++ b/configure.ac @@ -75,6 +75,10 @@ AC_ARG_ENABLE([aplay], [AS_HELP_STRING([--disable-aplay], [disable building of bluealsa-aplay tool])]) AM_CONDITIONAL([ENABLE_APLAY], [test "x$enable_aplay" != "xno"]) +AC_ARG_ENABLE([rfcomm], + [AS_HELP_STRING([--disable-rfcomm], [disable building of bluealsa-rfcomm tool])]) +AM_CONDITIONAL([ENABLE_RFCOMM], [test "x$enable_rfcomm" != "xno"]) + AC_ARG_ENABLE([hcitop], [AS_HELP_STRING([--enable-hcitop], [enable building of hcitop tool])]) AM_CONDITIONAL([ENABLE_HCITOP], [test "x$enable_hcitop" = "xyes"]) diff --git a/utils/Makefile.am b/utils/Makefile.am index 77425ae7c..cf9bfb435 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -1,5 +1,5 @@ # BlueALSA - Makefile.am -# Copyright (c) 2016-2017 Arkadiusz Bokowy +# Copyright (c) 2016-2018 Arkadiusz Bokowy bin_PROGRAMS = @@ -20,6 +20,20 @@ bluealsa_aplay_LDADD = \ @GIO2_LIBS@ endif +if ENABLE_RFCOMM +bin_PROGRAMS += bluealsa-rfcomm +bluealsa_rfcomm_SOURCES = \ + ../src/shared/ctl-client.c \ + ../src/shared/log.c \ + rfcomm.c +bluealsa_rfcomm_CFLAGS = \ + -I$(top_srcdir)/src \ + @BLUEZ_CFLAGS@ +bluealsa_rfcomm_LDADD = \ + @BLUEZ_LIBS@ \ + -lreadline +endif + if ENABLE_HCITOP bin_PROGRAMS += hcitop hcitop_CFLAGS = \ diff --git a/utils/rfcomm.c b/utils/rfcomm.c new file mode 100644 index 000000000..01ab9733f --- /dev/null +++ b/utils/rfcomm.c @@ -0,0 +1,165 @@ +/* + * BlueALSA - rfcomm.c + * Copyright (c) 2016-2018 Arkadiusz Bokowy + * + * This file is a part of bluez-alsa. + * + * This project is licensed under the terms of the MIT license. + * + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "shared/ctl-client.h" +#include "shared/log.h" + +static char *strtrim(char *str) { + while (isspace(*str)) + str++; + if (*str == '\0') + return str; + char *end = &str[strlen(str) - 1]; + while (end > str && isspace(*end)) + end--; + end[1] = '\0'; + return str; +} + +static char *build_rfcomm_command(const char *cmd) { + + static char command[512]; + bool at; + + command[0] = '\0'; + if (!(at = strncmp(cmd, "AT", 2) == 0)) + strcpy(command, "\r\n"); + + strcat(command, cmd); + strcat(command, "\r"); + if (!at) + strcat(command, "\n"); + + return command; +} + +int main(int argc, char *argv[]) { + + int opt; + const char *opts = "hVi:"; + const struct option longopts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "hci", required_argument, NULL, 'i' }, + { 0, 0, 0, 0 }, + }; + + const char *ba_interface = "hci0"; + int status = EXIT_SUCCESS; + int ba_fd = -1; + bdaddr_t ba_addr; + + log_open(argv[0], false, false); + + while ((opt = getopt_long(argc, argv, opts, longopts, NULL)) != -1) + switch (opt) { + case 'h' /* --help */ : +usage: + printf("Usage:\n" + " %s [OPTION]... \n" + "\nOptions:\n" + " -h, --help\t\tprint this help and exit\n" + " -V, --version\t\tprint version and exit\n" + " -i, --hci=hciX\tHCI device to use\n", + argv[0]); + return EXIT_SUCCESS; + + case 'V' /* --version */ : + printf("%s\n", PACKAGE_VERSION); + return EXIT_SUCCESS; + + case 'i' /* --hci */ : + ba_interface = optarg; + break; + + default: + fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); + return EXIT_FAILURE; + } + + if (optind + 1 != argc) + goto usage; + + if (str2ba(argv[optind], &ba_addr) != 0) { + error("Invalid BT device address: %s", argv[optind]); + goto fail; + } + + if ((ba_fd = bluealsa_open(ba_interface)) == -1) { + error("BlueALSA connection failed: %s", strerror(errno)); + goto fail; + } + + if (isatty(fileno(stdin))) { + + char prompt[17 + 3]; + char *line; + + rl_bind_key('\t', rl_insert); + + sprintf(prompt, "%s> ", argv[optind]); + while ((line = readline(prompt)) != NULL) { + char *tmp = strtrim(line); + if (strlen(tmp) > 0) { + if (bluealsa_send_rfcomm_command(ba_fd, ba_addr, build_rfcomm_command(tmp)) == -1) + warn("Couldn't send RFCOMM command: %s", strerror(errno)); + add_history(tmp); + } + free(line); + } + + fprintf(stdout, "\n"); + + } + else { + + char line[256]; + int duration; + + while (fgets(line, sizeof(line), stdin) != NULL) { + char *tmp = strtrim(line); + if (strlen(tmp) > 0) { + if (sscanf(tmp, "%*[Ss]%*[Ll]%*2[Ee]%*[Pp] %d", &duration) == 1) { + sleep(duration); + continue; + } + if (bluealsa_send_rfcomm_command(ba_fd, ba_addr, build_rfcomm_command(tmp)) == -1) + warn("Couldn't send RFCOMM command: %s", strerror(errno)); + } + } + + } + + goto success; + +fail: + status = EXIT_FAILURE; + +success: + if (ba_fd != -1) + close(ba_fd); + return status; +}