--- /dev/null
+#
+# Copyright (C) 2014 Google, Inc.
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := bdtest
+
+LOCAL_SRC_FILES := \
+ cases/adapter.c \
+ cases/cases.c \
+ cases/pan.c \
+ support/adapter.c \
+ support/callbacks.c \
+ support/hal.c \
+ support/pan.c \
+ support/property.c \
+ main.c
+
+LOCAL_SHARED_LIBRARIES += \
+ libhardware \
+ libhardware_legacy
+
+LOCAL_CFLAGS += -std=c99 -Wall -Wno-unused-parameter -Wno-missing-field-initializers -Werror
+
+include $(BUILD_EXECUTABLE)
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <hardware/bluetooth.h>
+#include <hardware/bt_pan.h>
+#include <hardware/hardware.h>
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#define TASSERT(c, ...) if (!(c)) { fprintf(stderr, "%s:%d: ", __func__, __LINE__); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); return false; }
+
+extern const bt_interface_t *bt_interface;
+extern bt_bdaddr_t bt_remote_bdaddr;
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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 "base.h"
+#include "support/adapter.h"
+#include "support/callbacks.h"
+#include "support/property.h"
+
+bool adapter_enable_disable() {
+ int error;
+
+ CALL_AND_WAIT(error = bt_interface->enable(), adapter_state_changed);
+ TASSERT(error == BT_STATUS_SUCCESS, "Error enabling Bluetooth: %d", error);
+ TASSERT(adapter_get_state() == BT_STATE_ON, "Adapter did not turn on.");
+
+ CALL_AND_WAIT(error = bt_interface->disable(), adapter_state_changed);
+ TASSERT(error == BT_STATUS_SUCCESS, "Error disabling Bluetooth: %d", error);
+ TASSERT(adapter_get_state() == BT_STATE_OFF, "Adapter did not turn off.");
+
+ return true;
+}
+
+bool adapter_repeated_enable_disable() {
+ for (int i = 0; i < 10; ++i) {
+ if (!adapter_enable_disable()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool adapter_set_name() {
+ int error;
+ bt_property_t *name = property_new_name("set_name");
+
+ CALL_AND_WAIT(error = bt_interface->set_adapter_property(name), adapter_properties);
+ TASSERT(error == BT_STATUS_SUCCESS, "Error setting device name.");
+ TASSERT(adapter_get_property_count() == 1, "Expected 1 adapter property change, found %d instead.", adapter_get_property_count());
+ TASSERT(adapter_get_property(BT_PROPERTY_BDNAME), "The Bluetooth name property did not change.");
+ TASSERT(property_equals(adapter_get_property(BT_PROPERTY_BDNAME), name), "Bluetooth name '%s' does not match test value", property_extract_name(adapter_get_property(BT_PROPERTY_BDNAME)));
+
+ property_free(name);
+
+ return true;
+}
+
+bool adapter_get_name() {
+ int error;
+ bt_property_t *name = property_new_name("get_name");
+
+ CALL_AND_WAIT(bt_interface->set_adapter_property(name), adapter_properties);
+ CALL_AND_WAIT(error = bt_interface->get_adapter_property(BT_PROPERTY_BDNAME), adapter_properties);
+ TASSERT(error == BT_STATUS_SUCCESS, "Error getting device name.");
+ TASSERT(adapter_get_property_count() == 1, "Expected 1 adapter property change, found %d instead.", adapter_get_property_count());
+ TASSERT(adapter_get_property(BT_PROPERTY_BDNAME), "The Bluetooth name property did not change.");
+ TASSERT(property_equals(adapter_get_property(BT_PROPERTY_BDNAME), name), "Bluetooth name '%s' does not match test value", property_extract_name(adapter_get_property(BT_PROPERTY_BDNAME)));
+
+ property_free(name);
+ return true;
+}
+
+bool adapter_start_discovery() {
+ int error;
+
+ CALL_AND_WAIT(error = bt_interface->start_discovery(), discovery_state_changed);
+ TASSERT(error == BT_STATUS_SUCCESS, "Error calling start_discovery: %d", error);
+ TASSERT(adapter_get_discovery_state() == BT_DISCOVERY_STARTED, "Unable to start discovery.");
+
+ return true;
+}
+
+bool adapter_cancel_discovery() {
+ int error;
+
+ CALL_AND_WAIT(bt_interface->start_discovery(), discovery_state_changed);
+ CALL_AND_WAIT(error = bt_interface->cancel_discovery(), discovery_state_changed);
+ TASSERT(error == BT_STATUS_SUCCESS, "Error calling cancel_discovery: %d", error);
+ TASSERT(adapter_get_discovery_state() == BT_DISCOVERY_STOPPED, "Unable to stop discovery.");
+
+ return true;
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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 "base.h"
+#include "cases/cases.h"
+
+TEST_CASE_DECL(adapter_enable_disable);
+TEST_CASE_DECL(adapter_repeated_enable_disable);
+TEST_CASE_DECL(adapter_set_name);
+TEST_CASE_DECL(adapter_get_name);
+TEST_CASE_DECL(adapter_start_discovery);
+TEST_CASE_DECL(adapter_cancel_discovery);
+
+TEST_CASE_DECL(pan_enable);
+TEST_CASE_DECL(pan_connect);
+TEST_CASE_DECL(pan_disconnect);
+TEST_CASE_DECL(pan_quick_reconnect);
+
+// These are run with the Bluetooth adapter disabled.
+const test_case_t sanity_suite[] = {
+ TEST_CASE(adapter_enable_disable),
+ TEST_CASE(adapter_repeated_enable_disable),
+};
+
+// The normal test suite is run with the adapter enabled.
+const test_case_t test_suite[] = {
+ TEST_CASE(adapter_set_name),
+ TEST_CASE(adapter_get_name),
+ TEST_CASE(adapter_start_discovery),
+ TEST_CASE(adapter_cancel_discovery),
+
+ TEST_CASE(pan_enable),
+ TEST_CASE(pan_connect),
+ TEST_CASE(pan_disconnect),
+};
+
+const size_t sanity_suite_size = ARRAY_SIZE(sanity_suite);
+const size_t test_suite_size = ARRAY_SIZE(test_suite);
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "base.h"
+
+#define TEST_CASE_DECL(x) bool x()
+#define TEST_CASE(x) { x, #x }
+
+typedef struct {
+ bool (*function)();
+ const char *function_name;
+} test_case_t;
+
+extern const test_case_t test_suite[];
+extern const test_case_t sanity_suite[];
+extern const size_t test_suite_size;
+extern const size_t sanity_suite_size;
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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 "base.h"
+#include "support/callbacks.h"
+#include "support/pan.h"
+
+static const int local_role = BTPAN_ROLE_PANU;
+static const int remote_role = BTPAN_ROLE_PANNAP;
+
+bool pan_enable() {
+ int error;
+
+ // PAN is enabled by default, wait for the first control state change
+ // with default parameters set. We don't want to verify the result since
+ // the implementation could have set any parameters.
+ WAIT(pan_control_state_changed);
+
+ // Call enable explicitly and verify that the parameters match what we just set.
+ CALL_AND_WAIT(error = pan_interface->enable(local_role), pan_control_state_changed);
+ TASSERT(error == BT_STATUS_SUCCESS, "Error enabling PAN: %d", error);
+ TASSERT(pan_get_control_state() == BTPAN_STATE_ENABLED, "Control state is disabled.");
+ TASSERT(pan_get_local_role() == local_role, "Unexpected local role: %d", pan_get_local_role());
+ TASSERT(pan_get_error() == BT_STATUS_SUCCESS, "Error in control callback: %d", pan_get_error());
+
+ return true;
+}
+
+bool pan_connect() {
+ int error;
+
+ if (!pan_enable()) {
+ return false;
+ }
+
+ CALL_AND_WAIT(error = pan_interface->connect(&bt_remote_bdaddr, local_role, remote_role), pan_connection_state_changed);
+ TASSERT(error == BT_STATUS_SUCCESS, "Error connecting to remote host: %d", error);
+ TASSERT(pan_get_error() == BT_STATUS_SUCCESS, "Error connecting to BT device: %d", pan_get_error());
+ TASSERT(pan_get_connection_state() == BTPAN_STATE_CONNECTING, "Invalid PAN state after connect: %d", pan_get_connection_state());
+ TASSERT(pan_get_local_role() == local_role, "Incorrect local role: %d", pan_get_local_role());
+ TASSERT(pan_get_remote_role() == remote_role, "Incorrect remote role: %d", pan_get_remote_role());
+
+ WAIT(pan_connection_state_changed);
+ TASSERT(pan_get_error() == BT_STATUS_SUCCESS, "Error connecting to BT device: %d", pan_get_error());
+ TASSERT(pan_get_connection_state() == BTPAN_STATE_CONNECTED, "Invalid PAN state after connect: %d", pan_get_connection_state());
+ TASSERT(pan_get_local_role() == local_role, "Incorrect local role: %d", pan_get_local_role());
+ TASSERT(pan_get_remote_role() == remote_role, "Incorrect remote role: %d", pan_get_remote_role());
+
+ return true;
+}
+
+bool pan_disconnect() {
+ int error;
+
+ if (!pan_connect()) {
+ return false;
+ }
+
+ CALL_AND_WAIT(error = pan_interface->disconnect(&bt_remote_bdaddr), pan_connection_state_changed);
+ TASSERT(error == BT_STATUS_SUCCESS, "Error disconnecting from remote host: %d", error);
+ TASSERT(pan_get_error() == BT_STATUS_SUCCESS, "Error disconnecting from BT device: %d", pan_get_error());
+ TASSERT(pan_get_connection_state() == BTPAN_STATE_DISCONNECTING, "Invalid PAN state after disconnect: %d", pan_get_connection_state());
+
+ WAIT(pan_connection_state_changed);
+ TASSERT(pan_get_error() == BT_STATUS_SUCCESS, "Error disconnecting from BT device: %d", pan_get_error());
+ TASSERT(pan_get_connection_state() == BTPAN_STATE_DISCONNECTED, "Invalid PAN state after disconnect: %d", pan_get_connection_state());
+
+ return true;
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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 "base.h"
+#include "cases/cases.h"
+#include "support/callbacks.h"
+#include "support/hal.h"
+#include "support/pan.h"
+
+#define GRAY "\x1b[0;37m"
+#define GREEN "\x1b[0;32m"
+#define RED "\x1b[0;31m"
+
+const bt_interface_t *bt_interface;
+bt_bdaddr_t bt_remote_bdaddr;
+
+static bool parse_bdaddr(const char *str, bt_bdaddr_t *addr) {
+ if (!addr) {
+ return false;
+ }
+
+ int v[6];
+ if (sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x", &v[0], &v[1], &v[2], &v[3], &v[4], &v[5]) != 6) {
+ return false;
+ }
+
+ for (int i = 0; i < 6; ++i) {
+ addr->address[i] = (uint8_t)v[i];
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv) {
+ if (argc < 2 || !parse_bdaddr(argv[1], &bt_remote_bdaddr)) {
+ printf("Usage: %s <bdaddr>\n", argv[0]);
+ return -1;
+ }
+
+ if (!hal_open(callbacks_get_adapter_struct())) {
+ printf("Unable to open Bluetooth HAL.\n");
+ return 1;
+ }
+
+ if (!pan_init()) {
+ printf("Unable to initialize PAN.\n");
+ return 2;
+ }
+
+ int pass = 0;
+ int fail = 0;
+ int case_num = 0;
+
+ // Run through the sanity suite.
+ for (size_t i = 0; i < sanity_suite_size; ++i) {
+ callbacks_init();
+ if (sanity_suite[i].function()) {
+ printf("[%4d] %-64s [%sPASS%s]\n", ++case_num, sanity_suite[i].function_name, GREEN, GRAY);
+ ++pass;
+ } else {
+ printf("[%4d] %-64s [%sFAIL%s]\n", ++case_num, sanity_suite[i].function_name, RED, GRAY);
+ ++fail;
+ }
+ callbacks_cleanup();
+ }
+
+ // If there was a failure in the sanity suite, don't bother running the rest of the tests.
+ if (fail) {
+ printf("\n%sSanity suite failed with %d errors.%s\n", RED, fail, GRAY);
+ hal_close();
+ return 0;
+ }
+
+ // Run the full test suite.
+ for (size_t i = 0; i < test_suite_size; ++i) {
+ callbacks_init();
+ CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
+ if (test_suite[i].function()) {
+ printf("[%4d] %-64s [%sPASS%s]\n", ++case_num, test_suite[i].function_name, GREEN, GRAY);
+ ++pass;
+ } else {
+ printf("[%4d] %-64s [%sFAIL%s]\n", ++case_num, test_suite[i].function_name, RED, GRAY);
+ ++fail;
+ }
+ CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed);
+ callbacks_cleanup();
+ }
+
+ printf("\n");
+
+ if (fail) {
+ printf("%d/%d tests failed. See above for failed test cases.\n", fail, test_suite_size);
+ } else {
+ printf("All tests passed!\n");
+ }
+
+ hal_close();
+ return 0;
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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 "base.h"
+#include "support/adapter.h"
+#include "support/callbacks.h"
+#include "support/property.h"
+
+static bt_state_t state;
+static int property_count = 0;
+static bt_property_t *properties = NULL;
+static bt_discovery_state_t discovery_state;
+
+bt_state_t adapter_get_state() {
+ return state;
+}
+
+int adapter_get_property_count() {
+ return property_count;
+}
+
+bt_property_t *adapter_get_property(bt_property_type_t type) {
+ for (int i = 0; i < property_count; ++i) {
+ if (properties[i].type == type) {
+ return &properties[i];
+ }
+ }
+
+ return NULL;
+}
+
+bt_discovery_state_t adapter_get_discovery_state() {
+ return discovery_state;
+}
+
+// callback
+void adapter_state_changed(bt_state_t new_state) {
+ state = new_state;
+ CALLBACK_RET();
+}
+
+// callback
+void adapter_properties(bt_status_t status,
+ int num_properties,
+ bt_property_t *new_properties) {
+ property_free_array(properties, property_count);
+ properties = property_copy_array(new_properties, num_properties);
+ property_count = num_properties;
+
+ CALLBACK_RET();
+}
+
+// callback
+void discovery_state_changed(bt_discovery_state_t state) {
+ discovery_state = state;
+ CALLBACK_RET();
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "base.h"
+
+bt_state_t adapter_get_state();
+int adapter_get_property_count();
+bt_property_t *adapter_get_property(bt_property_type_t type);
+bt_discovery_state_t adapter_get_discovery_state();
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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 "base.h"
+#include "support/callbacks.h"
+
+void adapter_state_changed(bt_state_t state);
+void adapter_properties(bt_status_t status,
+ int num_properties,
+ bt_property_t *properties);
+void discovery_state_changed(bt_discovery_state_t state);
+
+void pan_control_state_changed(btpan_control_state_t state, int local_role, bt_status_t error, const char *ifname);
+void pan_connection_state_changed(btpan_connection_state_t state, bt_status_t error, const bt_bdaddr_t *bd_addr, int local_role, int remote_role);
+
+static void remote_device_properties(bt_status_t status,
+ bt_bdaddr_t *bd_addr,
+ int num_properties,
+ bt_property_t *properties) {
+ CALLBACK_RET();
+}
+
+static void thread_evt(bt_cb_thread_evt evt) {
+ CALLBACK_RET();
+}
+
+static struct {
+ const char *name;
+ sem_t semaphore;
+} callback_data[] = {
+ // Adapter callbacks
+ { "adapter_state_changed" },
+ { "adapter_properties" },
+ { "remote_device_properties" },
+ {},
+ { "discovery_state_changed" },
+ {},
+ {},
+ {},
+ {},
+ { "thread_evt" },
+ {},
+ {},
+
+ // PAN callbacks
+ { "pan_control_state_changed" },
+ { "pan_connection_state_changed" },
+};
+
+static bt_callbacks_t bt_callbacks = {
+ sizeof(bt_callbacks_t),
+ adapter_state_changed, // adapter_state_changed_callback
+ adapter_properties, // adapter_properties_callback
+ remote_device_properties, // remote_device_properties_callback
+ NULL, // device_found_callback
+ discovery_state_changed, // discovery_state_changed_callback
+ NULL, // pin_request_callback
+ NULL, // ssp_request_callback
+ NULL, // bond_state_changed_callback
+ NULL, // acl_state_changed_callback
+ thread_evt, // callback_thread_event
+ NULL, // dut_mode_recv_callback
+ NULL, // le_test_mode_callback
+};
+
+static btpan_callbacks_t pan_callbacks = {
+ sizeof(btpan_callbacks_t),
+ pan_control_state_changed, // btpan_control_state_callback
+ pan_connection_state_changed, // btpan_connection_state_callback
+};
+
+void callbacks_init() {
+ for (size_t i = 0; i < ARRAY_SIZE(callback_data); ++i) {
+ sem_init(&callback_data[i].semaphore, 0, 0);
+ }
+}
+
+void callbacks_cleanup() {
+ for (size_t i = 0; i < ARRAY_SIZE(callback_data); ++i) {
+ sem_destroy(&callback_data[i].semaphore);
+ }
+}
+
+bt_callbacks_t *callbacks_get_adapter_struct() {
+ return &bt_callbacks;
+}
+
+btpan_callbacks_t *callbacks_get_pan_struct() {
+ return &pan_callbacks;
+}
+
+sem_t *callbacks_get_semaphore(const char *name) {
+ for (size_t i = 0; i < ARRAY_SIZE(callback_data); ++i) {
+ if (callback_data[i].name && !strcmp(name, callback_data[i].name)) {
+ return &callback_data[i].semaphore;
+ }
+ }
+ return NULL;
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "base.h"
+
+#include <semaphore.h>
+
+#define WAIT(callback) \
+ do { \
+ sem_t *semaphore = callbacks_get_semaphore(#callback); \
+ sem_wait(semaphore); \
+ } while (0)
+
+#define CALL_AND_WAIT(expression, callback) \
+ do { \
+ sem_t *semaphore = callbacks_get_semaphore(#callback); \
+ while (!sem_trywait(semaphore)); \
+ expression; \
+ sem_wait(semaphore); \
+ } while(0)
+
+// To be called from every exit point of the callback. This macro
+// takes 0 or 1 arguments, the return value of the callback.
+#define CALLBACK_RET(...) do { \
+ sem_t *semaphore = callbacks_get_semaphore(__func__); \
+ sem_post(semaphore); \
+ return __VA_ARGS__; \
+ } while (0)
+
+void callbacks_init();
+void callbacks_cleanup();
+
+bt_callbacks_t *callbacks_get_adapter_struct();
+btpan_callbacks_t *callbacks_get_pan_struct();
+sem_t *callbacks_get_semaphore(const char *name);
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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 "base.h"
+#include "support/hal.h"
+
+static const bluetooth_device_t *bt_device;
+
+bool hal_open(bt_callbacks_t *callbacks) {
+ hw_module_t *module;
+ if (hw_get_module(BT_STACK_MODULE_ID, (hw_module_t const **)&module)) {
+ return false;
+ }
+
+ hw_device_t *device;
+ if (module->methods->open(module, BT_STACK_MODULE_ID, &device)) {
+ return false;
+ }
+
+ bt_device = (bluetooth_device_t *)device;
+ bt_interface = bt_device->get_bluetooth_interface();
+ if (!bt_interface) {
+ bt_device->common.close((hw_device_t *)&bt_device->common);
+ bt_device = NULL;
+ return false;
+ }
+
+ return bt_interface->init(callbacks) == BT_STATUS_SUCCESS;
+}
+
+void hal_close() {
+ if (bt_interface) {
+ bt_interface->cleanup();
+ bt_interface = NULL;
+ }
+
+ if (bt_device) {
+ bt_device->common.close((hw_device_t *)&bt_device->common);
+ bt_device = NULL;
+ }
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "base.h"
+
+bool hal_open(bt_callbacks_t *callbacks);
+void hal_close();
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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 "base.h"
+#include "support/callbacks.h"
+#include "support/pan.h"
+
+const btpan_interface_t *pan_interface;
+
+static btpan_control_state_t pan_control_state;
+static btpan_connection_state_t pan_connection_state;
+static int pan_local_role;
+static int pan_remote_role;
+static bt_status_t pan_error;
+static char *pan_ifname;
+
+bool pan_init() {
+ pan_interface = bt_interface->get_profile_interface(BT_PROFILE_PAN_ID);
+ return pan_interface->init(callbacks_get_pan_struct()) == BT_STATUS_SUCCESS;
+}
+
+btpan_control_state_t pan_get_control_state() {
+ return pan_control_state;
+}
+
+btpan_connection_state_t pan_get_connection_state() {
+ return pan_connection_state;
+}
+
+int pan_get_local_role() {
+ return pan_local_role;
+}
+
+int pan_get_remote_role() {
+ return pan_remote_role;
+}
+
+bt_status_t pan_get_error() {
+ return pan_error;
+}
+
+// callback
+void pan_control_state_changed(btpan_control_state_t state, int local_role, bt_status_t error, const char *ifname) {
+ free(pan_ifname);
+
+ pan_control_state = state;
+ pan_local_role = local_role;
+ pan_error = error;
+ pan_ifname = strdup(ifname);
+
+ CALLBACK_RET();
+}
+
+// callback
+void pan_connection_state_changed(btpan_connection_state_t state, bt_status_t error, const bt_bdaddr_t *bd_addr, int local_role, int remote_role) {
+ pan_connection_state = state;
+ pan_error = error;
+ pan_local_role = local_role;
+ pan_remote_role = remote_role;
+ CALLBACK_RET();
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "base.h"
+
+extern const btpan_interface_t *pan_interface;
+
+bool pan_init();
+
+btpan_control_state_t pan_get_control_state();
+btpan_connection_state_t pan_get_connection_state();
+int pan_get_local_role();
+int pan_get_remote_role();
+bt_status_t pan_get_error();
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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 "base.h"
+#include "support/property.h"
+
+bt_property_t *property_copy_array(const bt_property_t *properties, size_t count) {
+ bt_property_t *clone = calloc(sizeof(bt_property_t), count);
+ if (!clone) {
+ return NULL;
+ }
+
+ memcpy(&clone[0], &properties[0], sizeof(bt_property_t) * count);
+ for (size_t i = 0; i < count; ++i) {
+ clone[i].val = calloc(clone[i].len, 1);
+ memcpy(clone[i].val, properties[i].val, clone[i].len);
+ }
+
+ return clone;
+}
+
+bt_property_t *property_new_name(const char *name) {
+ bt_bdname_t *bdname = calloc(sizeof(bt_bdname_t), 1);
+ bt_property_t *property = calloc(sizeof(bt_property_t), 1);
+
+ property->type = BT_PROPERTY_BDNAME;
+ property->val = bdname;
+ property->len = sizeof(bt_bdname_t);
+
+ strlcpy((char *)bdname->name, name, sizeof(bdname->name));
+
+ return property;
+}
+
+bt_property_t *property_new_discovery_timeout(uint32_t timeout) {
+ uint32_t *val = malloc(sizeof(uint32_t));
+ bt_property_t *property = malloc(sizeof(bt_property_t));
+
+ property->type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT;
+ property->val = val;
+ property->len = sizeof(uint32_t);
+
+ *val = timeout;
+
+ return property;
+}
+
+// Warning: not thread safe.
+const char *property_extract_name(const bt_property_t *property) {
+ static char name[250] = { 0 };
+ if (!property || property->type != BT_PROPERTY_BDNAME || !property->val) {
+ return NULL;
+ }
+
+ strncpy(name, (const char *)((bt_bdname_t *)property->val)->name, property->len);
+ name[sizeof(name) - 1] = '\0';
+
+ return name;
+}
+
+bool property_equals(const bt_property_t *p1, const bt_property_t *p2) {
+ // Two null properties are not the same. May need to revisit that
+ // decision when we have a test case that exercises that condition.
+ if (!p1 || !p2 || p1->type != p2->type) {
+ return false;
+ }
+
+ // Although the Bluetooth name is a 249-byte array, the implementation
+ // treats it like a variable-length array with its size specified in the
+ // property's `len` field. We special-case the equivalence of BDNAME
+ // types here by truncating the larger, zero-padded name to its string
+ // length and comparing against the shorter name.
+ //
+ // Note: it may be the case that both strings are zero-padded but that
+ // hasn't come up yet so this implementation doesn't handle it.
+ if (p1->type == BT_PROPERTY_BDNAME && p1->len != p2->len) {
+ const bt_property_t *shorter = p1, *longer = p2;
+ if (p1->len > p2->len) {
+ shorter = p2;
+ longer = p1;
+ }
+ return strlen((const char *)longer->val) == (size_t)shorter->len && !memcmp(longer->val, shorter->val, shorter->len);
+ }
+
+ return p1->len == p2->len && !memcmp(p1->val, p2->val, p1->len);
+}
+
+void property_free(bt_property_t *property) {
+ property_free_array(property, 1);
+}
+
+void property_free_array(bt_property_t *properties, size_t count) {
+ for (size_t i = 0; i < count; ++i) {
+ free(properties[i].val);
+ }
+
+ free(properties);
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "base.h"
+
+bt_property_t *property_copy_array(const bt_property_t *properties, size_t count);
+bt_property_t *property_new_name(const char *name);
+bt_property_t *property_new_discovery_timeout(uint32_t timeout);
+
+const char *property_extract_name(const bt_property_t *property);
+
+bool property_equals(const bt_property_t *p1, const bt_property_t *p2);
+
+void property_free(bt_property_t *property);
+void property_free_array(bt_property_t *properties, size_t count);