OSDN Git Service

Initial import of HAL-layer tests for bluedroid.
authorSharvil Nanavati <sharvil@google.com>
Thu, 10 Apr 2014 05:20:40 +0000 (22:20 -0700)
committerSharvil Nanavati <sharvil@google.com>
Sat, 3 May 2014 02:30:02 +0000 (02:30 +0000)
The test cases are in cases/, the support infrastructure for the
tests are in support/. Initially, as new test cases are being added
for different functional areas (e.g. BT socket) we'll need to also
write support functions to make those tests easier to write.
Over time, however, the support functions will be complete enough
that writing additional tests won't require also writing support
routines.

Change-Id: I54abb1011ca5132834a334cc256e3ff18cc20cbb

17 files changed:
test/suite/Android.mk [new file with mode: 0644]
test/suite/base.h [new file with mode: 0644]
test/suite/cases/adapter.c [new file with mode: 0644]
test/suite/cases/cases.c [new file with mode: 0644]
test/suite/cases/cases.h [new file with mode: 0644]
test/suite/cases/pan.c [new file with mode: 0644]
test/suite/main.c [new file with mode: 0644]
test/suite/support/adapter.c [new file with mode: 0644]
test/suite/support/adapter.h [new file with mode: 0644]
test/suite/support/callbacks.c [new file with mode: 0644]
test/suite/support/callbacks.h [new file with mode: 0644]
test/suite/support/hal.c [new file with mode: 0644]
test/suite/support/hal.h [new file with mode: 0644]
test/suite/support/pan.c [new file with mode: 0644]
test/suite/support/pan.h [new file with mode: 0644]
test/suite/support/property.c [new file with mode: 0644]
test/suite/support/property.h [new file with mode: 0644]

diff --git a/test/suite/Android.mk b/test/suite/Android.mk
new file mode 100644 (file)
index 0000000..0a66141
--- /dev/null
@@ -0,0 +1,41 @@
+#
+#  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)
diff --git a/test/suite/base.h b/test/suite/base.h
new file mode 100644 (file)
index 0000000..2d51af8
--- /dev/null
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ *  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;
diff --git a/test/suite/cases/adapter.c b/test/suite/cases/adapter.c
new file mode 100644 (file)
index 0000000..492d8f4
--- /dev/null
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ *  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;
+}
diff --git a/test/suite/cases/cases.c b/test/suite/cases/cases.c
new file mode 100644 (file)
index 0000000..20d941f
--- /dev/null
@@ -0,0 +1,53 @@
+/******************************************************************************
+ *
+ *  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);
diff --git a/test/suite/cases/cases.h b/test/suite/cases/cases.h
new file mode 100644 (file)
index 0000000..b20950b
--- /dev/null
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ *  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;
diff --git a/test/suite/cases/pan.c b/test/suite/cases/pan.c
new file mode 100644 (file)
index 0000000..b903b90
--- /dev/null
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ *  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;
+}
diff --git a/test/suite/main.c b/test/suite/main.c
new file mode 100644 (file)
index 0000000..7a3af5b
--- /dev/null
@@ -0,0 +1,114 @@
+/******************************************************************************
+ *
+ *  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;
+}
diff --git a/test/suite/support/adapter.c b/test/suite/support/adapter.c
new file mode 100644 (file)
index 0000000..0a78253
--- /dev/null
@@ -0,0 +1,72 @@
+/******************************************************************************
+ *
+ *  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();
+}
diff --git a/test/suite/support/adapter.h b/test/suite/support/adapter.h
new file mode 100644 (file)
index 0000000..0f5883f
--- /dev/null
@@ -0,0 +1,26 @@
+/******************************************************************************
+ *
+ *  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();
diff --git a/test/suite/support/callbacks.c b/test/suite/support/callbacks.c
new file mode 100644 (file)
index 0000000..2ad12cf
--- /dev/null
@@ -0,0 +1,114 @@
+/******************************************************************************
+ *
+ *  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;
+}
diff --git a/test/suite/support/callbacks.h b/test/suite/support/callbacks.h
new file mode 100644 (file)
index 0000000..102e13f
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ *  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);
diff --git a/test/suite/support/hal.c b/test/suite/support/hal.c
new file mode 100644 (file)
index 0000000..3525439
--- /dev/null
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ *  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;
+  }
+}
diff --git a/test/suite/support/hal.h b/test/suite/support/hal.h
new file mode 100644 (file)
index 0000000..11fa9f9
--- /dev/null
@@ -0,0 +1,24 @@
+/******************************************************************************
+ *
+ *  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();
diff --git a/test/suite/support/pan.c b/test/suite/support/pan.c
new file mode 100644 (file)
index 0000000..bec4142
--- /dev/null
@@ -0,0 +1,76 @@
+/******************************************************************************
+ *
+ *  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();
+}
diff --git a/test/suite/support/pan.h b/test/suite/support/pan.h
new file mode 100644 (file)
index 0000000..f43eb24
--- /dev/null
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ *  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();
diff --git a/test/suite/support/property.c b/test/suite/support/property.c
new file mode 100644 (file)
index 0000000..ea2c5c4
--- /dev/null
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ *  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);
+}
diff --git a/test/suite/support/property.h b/test/suite/support/property.h
new file mode 100644 (file)
index 0000000..a8b77c7
--- /dev/null
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ *  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);