445 lines
9.1 KiB
C
445 lines
9.1 KiB
C
/*
|
|
* Copyright (C) 2013 Intel Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <unistd.h>
|
|
#include <poll.h>
|
|
#include <unistd.h>
|
|
#include <getopt.h>
|
|
|
|
#include "if-main.h"
|
|
#include "terminal.h"
|
|
#include "pollhandler.h"
|
|
#include "history.h"
|
|
|
|
const struct interface *interfaces[] = {
|
|
&audio_if,
|
|
&sco_if,
|
|
&bluetooth_if,
|
|
&av_if,
|
|
&rc_if,
|
|
&gatt_if,
|
|
&gatt_client_if,
|
|
&gatt_server_if,
|
|
&hf_if,
|
|
&hh_if,
|
|
&pan_if,
|
|
&hl_if,
|
|
&sock_if,
|
|
NULL
|
|
};
|
|
|
|
static struct method commands[];
|
|
|
|
struct method *get_method(struct method *methods, const char *name)
|
|
{
|
|
while (strcmp(methods->name, "") != 0) {
|
|
if (strcmp(methods->name, name) == 0)
|
|
return methods;
|
|
methods++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* function returns interface of given name or NULL if not found */
|
|
const struct interface *get_interface(const char *name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; interfaces[i] != NULL; ++i) {
|
|
if (strcmp(interfaces[i]->name, name) == 0)
|
|
break;
|
|
}
|
|
|
|
return interfaces[i];
|
|
}
|
|
|
|
int haltest_error(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
int ret;
|
|
va_start(args, format);
|
|
ret = terminal_vprint(format, args);
|
|
va_end(args);
|
|
return ret;
|
|
}
|
|
|
|
int haltest_info(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
int ret;
|
|
va_start(args, format);
|
|
ret = terminal_vprint(format, args);
|
|
va_end(args);
|
|
return ret;
|
|
}
|
|
|
|
int haltest_warn(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
int ret;
|
|
va_start(args, format);
|
|
ret = terminal_vprint(format, args);
|
|
va_end(args);
|
|
return ret;
|
|
}
|
|
|
|
static void help_print_interface(const struct interface *i)
|
|
{
|
|
struct method *m;
|
|
|
|
for (m = i->methods; strcmp(m->name, "") != 0; m++)
|
|
haltest_info("%s %s %s\n", i->name, m->name,
|
|
(m->help ? m->help : ""));
|
|
}
|
|
|
|
/* Help completion */
|
|
static void help_c(int argc, const char **argv, enum_func *enum_func,
|
|
void **user)
|
|
{
|
|
if (argc == 2)
|
|
*enum_func = interface_name;
|
|
}
|
|
|
|
/* Help execution */
|
|
static void help_p(int argc, const char **argv)
|
|
{
|
|
const struct method *m = commands;
|
|
const struct interface **ip = interfaces;
|
|
const struct interface *i;
|
|
|
|
if (argc == 1) {
|
|
terminal_print("haltest allows to call Android HAL methods.\n");
|
|
terminal_print("\nAvailable commands:\n");
|
|
while (0 != strcmp(m->name, "")) {
|
|
terminal_print("\t%s %s\n", m->name,
|
|
(m->help ? m->help : ""));
|
|
m++;
|
|
}
|
|
|
|
terminal_print("\nAvailable interfaces to use:\n");
|
|
while (NULL != *ip) {
|
|
terminal_print("\t%s\n", (*ip)->name);
|
|
ip++;
|
|
}
|
|
|
|
terminal_print("\nTo get help on methods for each interface type:\n");
|
|
terminal_print("\n\thelp <inerface>\n");
|
|
terminal_print("\nBasic scenario:\n\tbluetooth init\n");
|
|
terminal_print("\tbluetooth enable\n\tbluetooth start_discovery\n");
|
|
terminal_print("\tbluetooth get_profile_interface handsfree\n");
|
|
terminal_print("\thandsfree init\n\n");
|
|
return;
|
|
}
|
|
|
|
i = get_interface(argv[1]);
|
|
if (i == NULL) {
|
|
haltest_error("No such interface\n");
|
|
return;
|
|
}
|
|
|
|
help_print_interface(i);
|
|
}
|
|
|
|
/* quit/exit execution */
|
|
static void quit_p(int argc, const char **argv)
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
static int fd_stack[10];
|
|
static int fd_stack_pointer = 0;
|
|
|
|
static void stdin_handler(struct pollfd *pollfd);
|
|
|
|
static void process_file(const char *name)
|
|
{
|
|
int fd = open(name, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
haltest_error("Can't open file: %s for reading\n", name);
|
|
return;
|
|
}
|
|
|
|
if (fd_stack_pointer >= 10) {
|
|
haltest_error("To many open files\n");
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
fd_stack[fd_stack_pointer++] = fd;
|
|
poll_unregister_fd(fd_stack[fd_stack_pointer - 2], stdin_handler);
|
|
poll_register_fd(fd_stack[fd_stack_pointer - 1], POLLIN, stdin_handler);
|
|
}
|
|
|
|
static void source_p(int argc, const char **argv)
|
|
{
|
|
if (argc < 2) {
|
|
haltest_error("No file specified");
|
|
return;
|
|
}
|
|
|
|
process_file(argv[1]);
|
|
}
|
|
|
|
/* Commands available without interface */
|
|
static struct method commands[] = {
|
|
STD_METHODCH(help, "[<interface>]"),
|
|
STD_METHOD(quit),
|
|
METHOD("exit", quit_p, NULL, NULL),
|
|
STD_METHODH(source, "<file>"),
|
|
END_METHOD
|
|
};
|
|
|
|
/* Gets comman by name */
|
|
struct method *get_command(const char *name)
|
|
{
|
|
return get_method(commands, name);
|
|
}
|
|
|
|
/* Function to enumerate interface names */
|
|
const char *interface_name(void *v, int i)
|
|
{
|
|
return interfaces[i] ? interfaces[i]->name : NULL;
|
|
}
|
|
|
|
/* Function to enumerate command and interface names */
|
|
const char *command_name(void *v, int i)
|
|
{
|
|
int cmd_cnt = NELEM(commands);
|
|
|
|
if (i >= cmd_cnt)
|
|
return interface_name(v, i - cmd_cnt);
|
|
else
|
|
return commands[i].name;
|
|
}
|
|
|
|
/*
|
|
* This function changes input parameter line_buffer so it has
|
|
* null termination after each token (due to strtok)
|
|
* Output argv is filled with pointers to arguments
|
|
* returns number of tokens parsed - argc
|
|
*/
|
|
static int command_line_to_argv(char *line_buffer, char *argv[], int argv_size)
|
|
{
|
|
static const char *token_breaks = "\r\n\t ";
|
|
char *token;
|
|
int argc = 0;
|
|
|
|
token = strtok(line_buffer, token_breaks);
|
|
while (token != NULL && argc < (int) argv_size) {
|
|
argv[argc++] = token;
|
|
token = strtok(NULL, token_breaks);
|
|
}
|
|
|
|
return argc;
|
|
}
|
|
|
|
static void process_line(char *line_buffer)
|
|
{
|
|
char *argv[50];
|
|
int argc;
|
|
int i = 0;
|
|
struct method *m;
|
|
|
|
argc = command_line_to_argv(line_buffer, argv, 50);
|
|
if (argc < 1)
|
|
return;
|
|
|
|
while (interfaces[i] != NULL) {
|
|
if (strcmp(interfaces[i]->name, argv[0])) {
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (argc < 2 || strcmp(argv[1], "?") == 0) {
|
|
help_print_interface(interfaces[i]);
|
|
return;
|
|
}
|
|
|
|
m = get_method(interfaces[i]->methods, argv[1]);
|
|
if (m != NULL) {
|
|
m->func(argc, (const char **) argv);
|
|
return;
|
|
}
|
|
|
|
haltest_error("No function %s found\n", argv[1]);
|
|
return;
|
|
}
|
|
/* No interface, try commands */
|
|
m = get_command(argv[0]);
|
|
if (m == NULL)
|
|
haltest_error("No such command %s\n", argv[0]);
|
|
else
|
|
m->func(argc, (const char **) argv);
|
|
}
|
|
|
|
/* called when there is something on stdin */
|
|
static void stdin_handler(struct pollfd *pollfd)
|
|
{
|
|
char buf[10];
|
|
|
|
if (pollfd->revents & POLLIN) {
|
|
int count = read(fd_stack[fd_stack_pointer - 1], buf, 10);
|
|
|
|
if (count > 0) {
|
|
int i;
|
|
|
|
for (i = 0; i < count; ++i)
|
|
terminal_process_char(buf[i], process_line);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (fd_stack_pointer > 1)
|
|
poll_register_fd(fd_stack[fd_stack_pointer - 2], POLLIN,
|
|
stdin_handler);
|
|
if (fd_stack_pointer > 0) {
|
|
poll_unregister_fd(fd_stack[--fd_stack_pointer], stdin_handler);
|
|
|
|
if (fd_stack[fd_stack_pointer])
|
|
close(fd_stack[fd_stack_pointer]);
|
|
}
|
|
}
|
|
|
|
static void usage(void)
|
|
{
|
|
printf("haltest Android Bluetooth HAL testing tool\n"
|
|
"Usage:\n");
|
|
printf("\thaltest [options]\n");
|
|
printf("options:\n"
|
|
"\t-n, --no-init Don't call init for interfaces\n"
|
|
"\t --version Print version\n"
|
|
"\t-h, --help Show help options\n");
|
|
}
|
|
|
|
enum {
|
|
PRINT_VERSION = 1000
|
|
};
|
|
|
|
int version = 1;
|
|
int revision = 0;
|
|
|
|
static void print_version(void)
|
|
{
|
|
printf("haltest version %d.%d\n", version, revision);
|
|
}
|
|
|
|
static const struct option main_options[] = {
|
|
{ "no-init", no_argument, NULL, 'n' },
|
|
{ "help", no_argument, NULL, 'h' },
|
|
{ "version", no_argument, NULL, PRINT_VERSION },
|
|
{ NULL }
|
|
};
|
|
|
|
static bool no_init = false;
|
|
|
|
static void parse_command_line(int argc, char *argv[])
|
|
{
|
|
for (;;) {
|
|
int opt;
|
|
|
|
opt = getopt_long(argc, argv, "nh", main_options, NULL);
|
|
if (opt < 0)
|
|
break;
|
|
|
|
switch (opt) {
|
|
case 'n':
|
|
no_init = true;
|
|
break;
|
|
case 'h':
|
|
usage();
|
|
exit(0);
|
|
case PRINT_VERSION:
|
|
print_version();
|
|
exit(0);
|
|
default:
|
|
putchar('\n');
|
|
exit(-1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void init(void)
|
|
{
|
|
static const char * const inames[] = {
|
|
BT_PROFILE_HANDSFREE_ID,
|
|
BT_PROFILE_ADVANCED_AUDIO_ID,
|
|
BT_PROFILE_AV_RC_ID,
|
|
BT_PROFILE_HEALTH_ID,
|
|
BT_PROFILE_HIDHOST_ID,
|
|
BT_PROFILE_PAN_ID,
|
|
BT_PROFILE_GATT_ID,
|
|
BT_PROFILE_SOCKETS_ID
|
|
};
|
|
const struct method *m;
|
|
const char *argv[4];
|
|
char init_audio[] = "audio init";
|
|
char init_sco[] = "sco init";
|
|
char init_bt[] = "bluetooth init";
|
|
uint32_t i;
|
|
|
|
process_line(init_audio);
|
|
process_line(init_sco);
|
|
process_line(init_bt);
|
|
|
|
m = get_interface_method("bluetooth", "get_profile_interface");
|
|
|
|
for (i = 0; i < NELEM(inames); ++i) {
|
|
argv[2] = inames[i];
|
|
m->func(3, argv);
|
|
}
|
|
|
|
/* Init what is available to init */
|
|
for (i = 2; i < NELEM(interfaces) - 1; ++i) {
|
|
m = get_interface_method(interfaces[i]->name, "init");
|
|
if (m != NULL)
|
|
m->func(2, argv);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct stat rcstat;
|
|
|
|
parse_command_line(argc, argv);
|
|
|
|
terminal_setup();
|
|
|
|
if (!no_init)
|
|
init();
|
|
|
|
history_restore(".haltest_history");
|
|
|
|
fd_stack[fd_stack_pointer++] = 0;
|
|
/* Register command line handler */
|
|
poll_register_fd(0, POLLIN, stdin_handler);
|
|
|
|
if (stat(".haltestrc", &rcstat) == 0 && (rcstat.st_mode & S_IFREG) != 0)
|
|
process_file(".haltestrc");
|
|
|
|
poll_dispatch_loop();
|
|
|
|
return 0;
|
|
}
|