| /****************************************************************************** |
| * |
| * 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 <gtest/gtest.h> |
| |
| #include "AlarmTestHarness.h" |
| |
| #include <stdint.h> |
| |
| #include "device/include/controller.h" |
| #include "osi/include/allocation_tracker.h" |
| #include "osi/include/allocator.h" |
| #include "osi/include/osi.h" |
| #include "osi/include/semaphore.h" |
| #include "btsnoop.h" |
| #include "hcimsgs.h" |
| #include "hci_hal.h" |
| #include "hci_inject.h" |
| #include "hci_layer.h" |
| #include "low_power_manager.h" |
| #include "module.h" |
| #include "packet_fragmenter.h" |
| #include "test_stubs.h" |
| #include "vendor.h" |
| |
| extern const module_t hci_module; |
| |
| DECLARE_TEST_MODES( |
| start_up_async, |
| shut_down, |
| postload, |
| transmit_simple, |
| receive_simple, |
| transmit_command_no_callbacks, |
| transmit_command_command_status, |
| transmit_command_command_complete, |
| ignoring_packets_ignored_packet, |
| ignoring_packets_following_packet |
| ); |
| |
| // TODO: Ugly hack to get around another ugly hack in hci_layer.cc |
| bt_bdaddr_t btif_local_bd_addr; |
| |
| static const char *small_sample_data = "\"It is easy to see,\" replied Don Quixote"; |
| static const char *command_sample_data = "that thou art not used to this business of adventures; those are giants"; |
| static const char *ignored_data = "and if thou art afraid, away with thee out of this and betake thyself to prayer"; |
| static const char *unignored_data = "while I engage them in fierce and unequal combat"; |
| |
| static const hci_t *hci; |
| static const hci_hal_callbacks_t *hal_callbacks; |
| static thread_t *internal_thread; |
| static vendor_cb firmware_config_callback; |
| static vendor_cb sco_config_callback; |
| static vendor_cb epilog_callback; |
| static semaphore_t *done; |
| static const uint16_t test_handle = (0x1992 & 0xCFFF); |
| static const uint16_t test_handle_continuation = (0x1992 & 0xCFFF) | 0x1000; |
| static int packet_index; |
| static unsigned int data_size_sum; |
| static BT_HDR *data_to_receive; |
| |
| static void signal_work_item(UNUSED_ATTR void *context) { |
| semaphore_post(done); |
| } |
| |
| static void flush_thread(thread_t *thread) { |
| // Double flush to ensure we get the next reactor cycle |
| thread_post(thread, signal_work_item, NULL); |
| semaphore_wait(done); |
| thread_post(thread, signal_work_item, NULL); |
| semaphore_wait(done); |
| } |
| |
| // TODO move this to a common packet testing helper |
| static BT_HDR *manufacture_packet(uint16_t event, const char *data) { |
| uint16_t data_length = strlen(data); |
| uint16_t size = data_length; |
| if (event == MSG_STACK_TO_HC_HCI_ACL) { |
| size += 4; // 2 for the handle, 2 for the length; |
| } |
| |
| BT_HDR *packet = (BT_HDR *)osi_malloc(size + sizeof(BT_HDR)); |
| packet->len = size; |
| packet->offset = 0; |
| packet->layer_specific = 0; |
| |
| // The command transmit interface adds the event type automatically. |
| // Make sure it works but omitting it here. |
| if (event != MSG_STACK_TO_HC_HCI_CMD) |
| packet->event = event; |
| |
| uint8_t *packet_data = packet->data; |
| |
| if (event == MSG_STACK_TO_HC_HCI_ACL) { |
| UINT16_TO_STREAM(packet_data, test_handle); |
| UINT16_TO_STREAM(packet_data, data_length); |
| } |
| |
| for (int i = 0; i < data_length; i++) { |
| packet_data[i] = data[i]; |
| } |
| |
| if (event == MSG_STACK_TO_HC_HCI_CMD) { |
| STREAM_SKIP_UINT16(packet_data); |
| UINT8_TO_STREAM(packet_data, data_length - 3); |
| } else if (event == MSG_HC_TO_STACK_HCI_EVT) { |
| STREAM_SKIP_UINT8(packet_data); |
| UINT8_TO_STREAM(packet_data, data_length - 2); |
| } |
| |
| return packet; |
| } |
| |
| static void expect_packet(uint16_t event, int max_acl_data_size, const uint8_t *data, uint16_t data_length, const char *expected_data) { |
| int expected_data_offset; |
| int length_to_check; |
| |
| if (event == MSG_STACK_TO_HC_HCI_ACL) { |
| uint16_t handle; |
| uint16_t length; |
| STREAM_TO_UINT16(handle, data); |
| STREAM_TO_UINT16(length, data); |
| |
| if (packet_index == 0) |
| EXPECT_EQ(test_handle, handle); |
| else |
| EXPECT_EQ(test_handle_continuation, handle); |
| |
| int length_remaining = strlen(expected_data) - data_size_sum; |
| int packet_data_length = data_length - HCI_ACL_PREAMBLE_SIZE; |
| EXPECT_EQ(length_remaining, length); |
| |
| if (length_remaining < max_acl_data_size) |
| EXPECT_EQ(length, packet_data_length); |
| else |
| EXPECT_EQ(max_acl_data_size, packet_data_length); |
| |
| length_to_check = packet_data_length; |
| expected_data_offset = packet_index * max_acl_data_size; |
| packet_index++; |
| } else { |
| length_to_check = strlen(expected_data); |
| expected_data_offset = 0; |
| } |
| |
| for (int i = 0; i < length_to_check; i++) { |
| if (event == MSG_STACK_TO_HC_HCI_CMD && (i == 2)) |
| EXPECT_EQ(data_length - 3, data[i]); |
| else |
| EXPECT_EQ(expected_data[expected_data_offset + i], data[i]); |
| |
| data_size_sum++; |
| } |
| } |
| |
| STUB_FUNCTION(bool, hal_init, (const hci_hal_callbacks_t *callbacks, thread_t *working_thread)) |
| DURING(start_up_async) AT_CALL(0) { |
| hal_callbacks = callbacks; |
| internal_thread = working_thread; |
| return true; |
| } |
| |
| UNEXPECTED_CALL; |
| return false; |
| } |
| |
| STUB_FUNCTION(bool, hal_open, ()) |
| DURING(start_up_async) AT_CALL(0) return true; |
| UNEXPECTED_CALL; |
| return false; |
| } |
| |
| STUB_FUNCTION(void, hal_close, ()) |
| DURING(shut_down) AT_CALL(0) return; |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(uint16_t, hal_transmit_data, (serial_data_type_t type, uint8_t *data, uint16_t length)) |
| DURING(transmit_simple) AT_CALL(0) { |
| EXPECT_EQ(DATA_TYPE_ACL, type); |
| expect_packet(MSG_STACK_TO_HC_HCI_ACL, 1021, data, length, small_sample_data); |
| return length; |
| } |
| |
| DURING( |
| transmit_command_no_callbacks, |
| transmit_command_command_status, |
| transmit_command_command_complete |
| ) AT_CALL(0) { |
| EXPECT_EQ(DATA_TYPE_COMMAND, type); |
| expect_packet(MSG_STACK_TO_HC_HCI_CMD, 1021, data, length, command_sample_data); |
| return length; |
| } |
| |
| UNEXPECTED_CALL; |
| return 0; |
| } |
| |
| static size_t replay_data_to_receive(size_t max_size, uint8_t *buffer) { |
| for (size_t i = 0; i < max_size; i++) { |
| if (data_to_receive->offset >= data_to_receive->len) |
| break; |
| |
| buffer[i] = data_to_receive->data[data_to_receive->offset++]; |
| |
| if (i == (max_size - 1)) |
| return i + 1; // We return the length, not the index; |
| } |
| |
| return 0; |
| } |
| |
| STUB_FUNCTION(size_t, hal_read_data, (serial_data_type_t type, uint8_t *buffer, size_t max_size)) |
| DURING(receive_simple, ignoring_packets_following_packet) { |
| EXPECT_EQ(DATA_TYPE_ACL, type); |
| return replay_data_to_receive(max_size, buffer); |
| } |
| |
| DURING(ignoring_packets_ignored_packet) { |
| EXPECT_EQ(DATA_TYPE_EVENT, type); |
| return replay_data_to_receive(max_size, buffer); |
| } |
| |
| DURING( |
| transmit_command_no_callbacks, |
| transmit_command_command_status, |
| transmit_command_command_complete) { |
| EXPECT_EQ(DATA_TYPE_EVENT, type); |
| return replay_data_to_receive(max_size, buffer); |
| } |
| |
| UNEXPECTED_CALL; |
| return 0; |
| } |
| |
| STUB_FUNCTION(void, hal_packet_finished, (serial_data_type_t type)) |
| DURING(receive_simple, ignoring_packets_following_packet) AT_CALL(0) { |
| EXPECT_EQ(DATA_TYPE_ACL, type); |
| return; |
| } |
| |
| DURING(ignoring_packets_ignored_packet) AT_CALL(0) { |
| EXPECT_EQ(DATA_TYPE_EVENT, type); |
| return; |
| } |
| |
| DURING( |
| transmit_command_no_callbacks, |
| transmit_command_command_status, |
| transmit_command_command_complete |
| ) AT_CALL(0) { |
| EXPECT_EQ(DATA_TYPE_EVENT, type); |
| return; |
| } |
| |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(bool, hci_inject_open, ( |
| UNUSED_ATTR const hci_t *hci_interface)) |
| DURING(start_up_async) AT_CALL(0) return true; |
| UNEXPECTED_CALL; |
| return false; |
| } |
| |
| STUB_FUNCTION(void, hci_inject_close, ()) |
| DURING(shut_down) AT_CALL(0) return; |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(void, btsnoop_capture, (const BT_HDR *buffer, bool is_received)) |
| DURING(transmit_simple) AT_CALL(0) { |
| EXPECT_FALSE(is_received); |
| expect_packet(MSG_STACK_TO_HC_HCI_ACL, 1021, buffer->data + buffer->offset, buffer->len, small_sample_data); |
| packet_index = 0; |
| data_size_sum = 0; |
| return; |
| } |
| |
| |
| DURING( |
| transmit_command_no_callbacks, |
| transmit_command_command_status, |
| transmit_command_command_complete) { |
| AT_CALL(0) { |
| EXPECT_FALSE(is_received); |
| expect_packet(MSG_STACK_TO_HC_HCI_CMD, 1021, buffer->data + buffer->offset, buffer->len, command_sample_data); |
| packet_index = 0; |
| data_size_sum = 0; |
| return; |
| } |
| AT_CALL(1) { |
| EXPECT_TRUE(is_received); |
| // not super important to verify the contents right now |
| return; |
| } |
| } |
| |
| DURING( |
| receive_simple, |
| ignoring_packets_following_packet |
| ) AT_CALL(0) { |
| EXPECT_TRUE(is_received); |
| EXPECT_TRUE(buffer->len == data_to_receive->len); |
| const uint8_t *buffer_base = buffer->data + buffer->offset; |
| const uint8_t *expected_base = data_to_receive->data; |
| for (int i = 0; i < buffer->len; i++) { |
| EXPECT_EQ(expected_base[i], buffer_base[i]); |
| } |
| |
| return; |
| } |
| |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(void, low_power_init, (UNUSED_ATTR thread_t *thread)) |
| DURING(start_up_async) AT_CALL(0) return; |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(void, low_power_cleanup, ()) |
| DURING(shut_down) AT_CALL(0) return; |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(void, low_power_wake_assert, ()) |
| DURING( |
| transmit_simple, |
| transmit_command_no_callbacks, |
| transmit_command_command_status, |
| transmit_command_command_complete) { |
| AT_CALL(0) return; |
| } |
| |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(void, low_power_transmit_done, ()) |
| DURING( |
| transmit_simple, |
| transmit_command_no_callbacks, |
| transmit_command_command_status, |
| transmit_command_command_complete) { |
| AT_CALL(0) return; |
| } |
| |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(bool, vendor_open, (UNUSED_ATTR const uint8_t *addr, const hci_t *hci_interface)) |
| DURING(start_up_async) AT_CALL(0) { |
| // TODO(zachoverflow): check address value when it gets put into a module |
| EXPECT_EQ(hci, hci_interface); |
| return true; |
| } |
| |
| UNEXPECTED_CALL; |
| return true; |
| } |
| |
| STUB_FUNCTION(void, vendor_close, ()) |
| DURING(shut_down) AT_CALL(0) return; |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(void, vendor_set_callback, (vendor_async_opcode_t opcode, UNUSED_ATTR vendor_cb callback)) |
| DURING(start_up_async) { |
| AT_CALL(0) { |
| EXPECT_EQ(VENDOR_CONFIGURE_FIRMWARE, opcode); |
| firmware_config_callback = callback; |
| return; |
| } |
| AT_CALL(1) { |
| EXPECT_EQ(VENDOR_CONFIGURE_SCO, opcode); |
| sco_config_callback = callback; |
| return; |
| } |
| AT_CALL(2) { |
| EXPECT_EQ(VENDOR_DO_EPILOG, opcode); |
| epilog_callback = callback; |
| return; |
| } |
| } |
| |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void *param)) |
| DURING(start_up_async) { |
| #if (BT_CLEAN_TURN_ON_DISABLED == TRUE) |
| AT_CALL(0) { |
| EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode); |
| EXPECT_EQ(BT_VND_PWR_ON, *(int *)param); |
| return 0; |
| } |
| #else |
| AT_CALL(0) { |
| EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode); |
| EXPECT_EQ(BT_VND_PWR_OFF, *(int *)param); |
| return 0; |
| } |
| AT_CALL(1) { |
| EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode); |
| EXPECT_EQ(BT_VND_PWR_ON, *(int *)param); |
| return 0; |
| } |
| #endif |
| } |
| |
| DURING(shut_down) AT_CALL(0) { |
| EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode); |
| EXPECT_EQ(BT_VND_PWR_OFF, *(int *)param); |
| return 0; |
| } |
| |
| UNEXPECTED_CALL; |
| return 0; |
| } |
| |
| STUB_FUNCTION(int, vendor_send_async_command, (UNUSED_ATTR vendor_async_opcode_t opcode, UNUSED_ATTR void *param)) |
| DURING(start_up_async) AT_CALL(0) { |
| EXPECT_EQ(VENDOR_CONFIGURE_FIRMWARE, opcode); |
| firmware_config_callback(true); |
| return 0; |
| } |
| |
| DURING(postload) AT_CALL(0) { |
| EXPECT_EQ(VENDOR_CONFIGURE_SCO, opcode); |
| sco_config_callback(true); |
| return 0; |
| } |
| |
| DURING(shut_down) AT_CALL(0) { |
| EXPECT_EQ(VENDOR_DO_EPILOG, opcode); |
| epilog_callback(true); |
| return 0; |
| } |
| |
| UNEXPECTED_CALL; |
| return 0; |
| } |
| |
| STUB_FUNCTION(void, command_complete_callback, (BT_HDR *response, UNUSED_ATTR void *context)) |
| DURING(transmit_command_command_complete) AT_CALL(0) { |
| osi_free(response); |
| return; |
| } |
| |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(void, command_status_callback, (UNUSED_ATTR uint8_t status, BT_HDR *command, UNUSED_ATTR void *context)) |
| DURING(transmit_command_command_status) AT_CALL(0) { |
| osi_free(command); |
| return; |
| } |
| |
| UNEXPECTED_CALL; |
| } |
| |
| STUB_FUNCTION(uint16_t, controller_get_acl_data_size_classic, (void)) |
| return 2048; |
| } |
| |
| STUB_FUNCTION(uint16_t, controller_get_acl_data_size_ble, (void)) |
| return 2048; |
| } |
| |
| STUB_FUNCTION(void *, buffer_allocator_alloc, (size_t size)) |
| DURING(ignoring_packets_ignored_packet) { |
| AT_CALL(0) |
| return NULL; |
| |
| UNEXPECTED_CALL; |
| } |
| |
| return allocator_malloc.alloc(size); |
| } |
| |
| STUB_FUNCTION(void, buffer_allocator_free, (void *ptr)) |
| allocator_malloc.free(ptr); |
| } |
| |
| static void reset_for(TEST_MODES_T next) { |
| RESET_CALL_COUNT(vendor_open); |
| RESET_CALL_COUNT(vendor_close); |
| RESET_CALL_COUNT(vendor_set_callback); |
| RESET_CALL_COUNT(vendor_send_command); |
| RESET_CALL_COUNT(vendor_send_async_command); |
| RESET_CALL_COUNT(hal_init); |
| RESET_CALL_COUNT(hal_open); |
| RESET_CALL_COUNT(hal_close); |
| RESET_CALL_COUNT(hal_read_data); |
| RESET_CALL_COUNT(hal_packet_finished); |
| RESET_CALL_COUNT(hal_transmit_data); |
| RESET_CALL_COUNT(btsnoop_capture); |
| RESET_CALL_COUNT(hci_inject_open); |
| RESET_CALL_COUNT(hci_inject_close); |
| RESET_CALL_COUNT(low_power_init); |
| RESET_CALL_COUNT(low_power_cleanup); |
| RESET_CALL_COUNT(low_power_wake_assert); |
| RESET_CALL_COUNT(low_power_transmit_done); |
| RESET_CALL_COUNT(command_complete_callback); |
| RESET_CALL_COUNT(command_status_callback); |
| RESET_CALL_COUNT(controller_get_acl_data_size_classic); |
| RESET_CALL_COUNT(controller_get_acl_data_size_ble); |
| RESET_CALL_COUNT(buffer_allocator_alloc); |
| RESET_CALL_COUNT(buffer_allocator_free); |
| CURRENT_TEST_MODE = next; |
| } |
| |
| class HciLayerTest : public AlarmTestHarness { |
| protected: |
| virtual void SetUp() { |
| AlarmTestHarness::SetUp(); |
| module_management_start(); |
| |
| hci = hci_layer_get_test_interface( |
| &buffer_allocator, |
| &hal, |
| &btsnoop, |
| &hci_inject, |
| packet_fragmenter_get_test_interface(&controller, &allocator_malloc), |
| &vendor, |
| &low_power_manager |
| ); |
| |
| packet_index = 0; |
| data_size_sum = 0; |
| |
| vendor.open = vendor_open; |
| vendor.close = vendor_close; |
| vendor.set_callback = vendor_set_callback; |
| vendor.send_command = vendor_send_command; |
| vendor.send_async_command = vendor_send_async_command; |
| hal.init = hal_init; |
| hal.open = hal_open; |
| hal.close = hal_close; |
| hal.read_data = hal_read_data; |
| hal.packet_finished = hal_packet_finished; |
| hal.transmit_data = hal_transmit_data; |
| btsnoop.capture = btsnoop_capture; |
| hci_inject.open = hci_inject_open; |
| hci_inject.close = hci_inject_close; |
| low_power_manager.init = low_power_init; |
| low_power_manager.cleanup = low_power_cleanup; |
| low_power_manager.wake_assert = low_power_wake_assert; |
| low_power_manager.transmit_done = low_power_transmit_done; |
| controller.get_acl_data_size_classic = controller_get_acl_data_size_classic; |
| controller.get_acl_data_size_ble = controller_get_acl_data_size_ble; |
| buffer_allocator.alloc = buffer_allocator_alloc; |
| buffer_allocator.free = buffer_allocator_free; |
| |
| done = semaphore_new(0); |
| |
| reset_for(start_up_async); |
| EXPECT_TRUE(module_start_up(&hci_module)); |
| |
| EXPECT_CALL_COUNT(vendor_open, 1); |
| EXPECT_CALL_COUNT(hal_init, 1); |
| EXPECT_CALL_COUNT(low_power_init, 1); |
| EXPECT_CALL_COUNT(vendor_set_callback, 3); |
| EXPECT_CALL_COUNT(hal_open, 1); |
| EXPECT_CALL_COUNT(vendor_send_async_command, 1); |
| } |
| |
| virtual void TearDown() { |
| reset_for(shut_down); |
| module_shut_down(&hci_module); |
| |
| EXPECT_CALL_COUNT(low_power_cleanup, 1); |
| EXPECT_CALL_COUNT(hal_close, 1); |
| EXPECT_CALL_COUNT(vendor_send_command, 1); |
| EXPECT_CALL_COUNT(vendor_close, 1); |
| |
| semaphore_free(done); |
| hci_layer_cleanup_interface(); |
| module_management_stop(); |
| AlarmTestHarness::TearDown(); |
| } |
| |
| hci_hal_t hal; |
| btsnoop_t btsnoop; |
| controller_t controller; |
| hci_inject_t hci_inject; |
| vendor_t vendor; |
| low_power_manager_t low_power_manager; |
| allocator_t buffer_allocator; |
| }; |
| |
| TEST_F(HciLayerTest, test_postload) { |
| reset_for(postload); |
| hci->do_postload(); |
| |
| flush_thread(internal_thread); |
| EXPECT_CALL_COUNT(vendor_send_async_command, 1); |
| } |
| |
| TEST_F(HciLayerTest, test_transmit_simple) { |
| reset_for(transmit_simple); |
| BT_HDR *packet = manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, small_sample_data); |
| hci->transmit_downward(MSG_STACK_TO_HC_HCI_ACL, packet); |
| |
| flush_thread(internal_thread); |
| EXPECT_CALL_COUNT(hal_transmit_data, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 1); |
| EXPECT_CALL_COUNT(low_power_transmit_done, 1); |
| EXPECT_CALL_COUNT(low_power_wake_assert, 1); |
| } |
| |
| TEST_F(HciLayerTest, test_receive_simple) { |
| reset_for(receive_simple); |
| data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, small_sample_data); |
| |
| // Not running on the internal thread, unlike the real hal |
| hal_callbacks->data_ready(DATA_TYPE_ACL); |
| EXPECT_CALL_COUNT(hal_packet_finished, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 1); |
| |
| osi_free(data_to_receive); |
| } |
| |
| static BT_HDR *manufacture_command_complete(command_opcode_t opcode) { |
| BT_HDR *ret = (BT_HDR *)osi_calloc(sizeof(BT_HDR) + 5); |
| uint8_t *stream = ret->data; |
| UINT8_TO_STREAM(stream, HCI_COMMAND_COMPLETE_EVT); |
| UINT8_TO_STREAM(stream, 3); // length of the event parameters |
| UINT8_TO_STREAM(stream, 1); // the number of commands that can be sent |
| UINT16_TO_STREAM(stream, opcode); |
| ret->len = 5; |
| |
| return ret; |
| } |
| |
| static BT_HDR *manufacture_command_status(command_opcode_t opcode) { |
| BT_HDR *ret = (BT_HDR *)osi_calloc(sizeof(BT_HDR) + 6); |
| uint8_t *stream = ret->data; |
| UINT8_TO_STREAM(stream, HCI_COMMAND_STATUS_EVT); |
| UINT8_TO_STREAM(stream, 4); // length of the event parameters |
| UINT8_TO_STREAM(stream, HCI_PENDING); // status |
| UINT8_TO_STREAM(stream, 1); // the number of commands that can be sent |
| UINT16_TO_STREAM(stream, opcode); |
| ret->len = 6; |
| |
| return ret; |
| } |
| |
| TEST_F(HciLayerTest, test_transmit_command_no_callbacks) { |
| // Send a test command |
| reset_for(transmit_command_no_callbacks); |
| data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data); |
| hci->transmit_command(data_to_receive, NULL, NULL, NULL); |
| |
| flush_thread(internal_thread); |
| EXPECT_CALL_COUNT(hal_transmit_data, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 1); |
| EXPECT_CALL_COUNT(low_power_transmit_done, 1); |
| EXPECT_CALL_COUNT(low_power_wake_assert, 1); |
| |
| // Send a response |
| command_opcode_t opcode = *((uint16_t *)command_sample_data); |
| data_to_receive = manufacture_command_complete(opcode); |
| |
| hal_callbacks->data_ready(DATA_TYPE_EVENT); |
| EXPECT_CALL_COUNT(hal_packet_finished, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 2); |
| |
| osi_free(data_to_receive); |
| } |
| |
| TEST_F(HciLayerTest, test_transmit_command_command_status) { |
| // Send a test command |
| reset_for(transmit_command_command_status); |
| data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data); |
| hci->transmit_command(data_to_receive, command_complete_callback, command_status_callback, NULL); |
| |
| flush_thread(internal_thread); |
| EXPECT_CALL_COUNT(hal_transmit_data, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 1); |
| EXPECT_CALL_COUNT(low_power_transmit_done, 1); |
| EXPECT_CALL_COUNT(low_power_wake_assert, 1); |
| |
| command_opcode_t opcode = *((uint16_t *)command_sample_data); |
| |
| // Send status event response |
| data_to_receive = manufacture_command_status(opcode); |
| |
| hal_callbacks->data_ready(DATA_TYPE_EVENT); |
| EXPECT_CALL_COUNT(hal_packet_finished, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 2); |
| EXPECT_CALL_COUNT(command_status_callback, 1); |
| |
| osi_free(data_to_receive); |
| } |
| |
| TEST_F(HciLayerTest, test_transmit_command_command_complete) { |
| // Send a test command |
| reset_for(transmit_command_command_complete); |
| data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data); |
| hci->transmit_command(data_to_receive, command_complete_callback, command_status_callback, NULL); |
| |
| flush_thread(internal_thread); |
| EXPECT_CALL_COUNT(hal_transmit_data, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 1); |
| EXPECT_CALL_COUNT(low_power_transmit_done, 1); |
| EXPECT_CALL_COUNT(low_power_wake_assert, 1); |
| |
| command_opcode_t opcode = *((uint16_t *)command_sample_data); |
| |
| // Send complete event response |
| data_to_receive = manufacture_command_complete(opcode); |
| |
| hal_callbacks->data_ready(DATA_TYPE_EVENT); |
| EXPECT_CALL_COUNT(hal_packet_finished, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 2); |
| EXPECT_CALL_COUNT(command_complete_callback, 1); |
| |
| osi_free(data_to_receive); |
| } |
| |
| TEST_F(HciLayerTest, test_ignoring_packets) { |
| reset_for(ignoring_packets_ignored_packet); |
| data_to_receive = manufacture_packet(MSG_HC_TO_STACK_HCI_EVT, unignored_data); |
| |
| hal_callbacks->data_ready(DATA_TYPE_EVENT); |
| EXPECT_CALL_COUNT(buffer_allocator_alloc, 1); |
| EXPECT_CALL_COUNT(hal_packet_finished, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 0); |
| osi_free(data_to_receive); |
| |
| reset_for(ignoring_packets_following_packet); |
| data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, ignored_data); |
| |
| hal_callbacks->data_ready(DATA_TYPE_ACL); |
| EXPECT_CALL_COUNT(buffer_allocator_alloc, 1); |
| EXPECT_CALL_COUNT(hal_packet_finished, 1); |
| EXPECT_CALL_COUNT(btsnoop_capture, 1); |
| osi_free(data_to_receive); |
| } |
| |
| // TODO(zachoverflow): test post-reassembly better, stub out fragmenter instead of using it |