| /* |
| * Copyright 2015 The Android Open Source Project |
| * |
| * 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 "dual_mode_controller.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <random> |
| |
| #include "crypto/crypto.h" |
| #include "log.h" |
| #include "packet/raw_builder.h" |
| |
| using bluetooth::hci::ErrorCode; |
| using bluetooth::hci::LoopbackMode; |
| using bluetooth::hci::OpCode; |
| using std::vector; |
| |
| namespace rootcanal { |
| constexpr uint16_t kNumCommandPackets = 0x01; |
| constexpr uint16_t kLeMaximumDataLength = 64; |
| constexpr uint16_t kLeMaximumDataTime = 0x148; |
| |
| // Device methods. |
| std::string DualModeController::GetTypeString() const { |
| return "Simulated Bluetooth Controller"; |
| } |
| |
| void DualModeController::ReceiveLinkLayerPacket( |
| model::packets::LinkLayerPacketView incoming, Phy::Type /*type*/, |
| int8_t rssi) { |
| link_layer_controller_.IncomingPacket(incoming, rssi); |
| } |
| |
| void DualModeController::Tick() { link_layer_controller_.Tick(); } |
| |
| void DualModeController::Close() { |
| link_layer_controller_.Close(); |
| Device::Close(); |
| } |
| |
| void DualModeController::SendCommandCompleteUnknownOpCodeEvent( |
| bluetooth::hci::OpCode op_code) const { |
| send_event_(bluetooth::hci::CommandCompleteBuilder::Create( |
| kNumCommandPackets, op_code, |
| std::make_unique<bluetooth::packet::RawBuilder>(std::vector<uint8_t>{ |
| static_cast<uint8_t>(ErrorCode::UNKNOWN_HCI_COMMAND)}))); |
| } |
| |
| DualModeController::DualModeController(ControllerProperties properties) |
| : properties_(std::move(properties)) { |
| Address public_address{}; |
| ASSERT(Address::FromString("3C:5A:B4:04:05:06", public_address)); |
| SetAddress(public_address); |
| |
| link_layer_controller_.RegisterRemoteChannel( |
| [this](std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet, |
| Phy::Type phy_type, int8_t tx_power) { |
| this->SendLinkLayerPacket(packet, phy_type, tx_power); |
| }); |
| } |
| |
| void DualModeController::ForwardToLm(CommandView command) { |
| link_layer_controller_.ForwardToLm(command); |
| } |
| |
| void DualModeController::SniffSubrating(CommandView command) { |
| auto command_view = bluetooth::hci::SniffSubratingView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| send_event_(bluetooth::hci::SniffSubratingCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| command_view.GetConnectionHandle())); |
| } |
| |
| void DualModeController::HandleAcl( |
| std::shared_ptr<std::vector<uint8_t>> packet) { |
| bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(packet); |
| auto acl_packet = bluetooth::hci::AclView::Create(raw_packet); |
| ASSERT(acl_packet.IsValid()); |
| if (loopback_mode_ == LoopbackMode::ENABLE_LOCAL) { |
| uint16_t handle = acl_packet.GetHandle(); |
| |
| std::vector<uint8_t> payload{acl_packet.GetPayload().begin(), |
| acl_packet.GetPayload().end()}; |
| send_acl_(bluetooth::hci::AclBuilder::Create( |
| handle, acl_packet.GetPacketBoundaryFlag(), |
| acl_packet.GetBroadcastFlag(), |
| std::make_unique<bluetooth::packet::RawBuilder>(payload))); |
| |
| std::vector<bluetooth::hci::CompletedPackets> completed_packets; |
| bluetooth::hci::CompletedPackets cp; |
| cp.connection_handle_ = handle; |
| cp.host_num_of_completed_packets_ = 1; |
| completed_packets.push_back(cp); |
| send_event_(bluetooth::hci::NumberOfCompletedPacketsBuilder::Create( |
| completed_packets)); |
| return; |
| } |
| |
| link_layer_controller_.SendAclToRemote(acl_packet); |
| } |
| |
| void DualModeController::HandleSco( |
| std::shared_ptr<std::vector<uint8_t>> packet) { |
| bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(packet); |
| auto sco_packet = bluetooth::hci::ScoView::Create(raw_packet); |
| ASSERT(sco_packet.IsValid()); |
| if (loopback_mode_ == LoopbackMode::ENABLE_LOCAL) { |
| uint16_t handle = sco_packet.GetHandle(); |
| |
| send_sco_(bluetooth::hci::ScoBuilder::Create( |
| handle, sco_packet.GetPacketStatusFlag(), sco_packet.GetData())); |
| |
| std::vector<bluetooth::hci::CompletedPackets> completed_packets; |
| bluetooth::hci::CompletedPackets cp; |
| cp.connection_handle_ = handle; |
| cp.host_num_of_completed_packets_ = 1; |
| completed_packets.push_back(cp); |
| if (link_layer_controller_.GetScoFlowControlEnable()) { |
| send_event_(bluetooth::hci::NumberOfCompletedPacketsBuilder::Create( |
| completed_packets)); |
| } |
| return; |
| } |
| |
| link_layer_controller_.SendScoToRemote(sco_packet); |
| } |
| |
| void DualModeController::HandleIso( |
| std::shared_ptr<std::vector<uint8_t>> packet) { |
| bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(packet); |
| auto iso = bluetooth::hci::IsoView::Create(raw_packet); |
| ASSERT(iso.IsValid()); |
| link_layer_controller_.HandleIso(iso); |
| } |
| |
| void DualModeController::HandleCommand( |
| std::shared_ptr<std::vector<uint8_t>> packet) { |
| auto command_packet = bluetooth::hci::CommandView::Create( |
| bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian>(packet)); |
| ASSERT(command_packet.IsValid()); |
| |
| OpCode op_code = command_packet.GetOpCode(); |
| const bool is_vendor_command = (static_cast<uint16_t>(op_code) >> 10) == 0x3f; |
| const bool is_known_command = |
| hci_command_op_code_to_index_.count(op_code) > 0; |
| const bool is_implemented_command = hci_command_handlers_.count(op_code) > 0; |
| |
| // HCI Read Local Supported Commands is supported by default. |
| // Vendor commands are supported when implemented. |
| bool is_supported_command = |
| (op_code == OpCode::READ_LOCAL_SUPPORTED_COMMANDS) || |
| (is_vendor_command && is_implemented_command); |
| |
| // For other commands, query the Support Commands bit mask in |
| // the controller properties. |
| if (!is_supported_command && is_known_command) { |
| int index = static_cast<int>(hci_command_op_code_to_index_.at(op_code)); |
| is_supported_command = (properties_.supported_commands[index / 10] & |
| (1U << (index % 10))) != 0; |
| } |
| |
| // Loopback mode, the commands are sent back to the host. |
| if (loopback_mode_ == LoopbackMode::ENABLE_LOCAL && |
| op_code != OpCode::RESET && |
| op_code != OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL && |
| op_code != OpCode::HOST_BUFFER_SIZE && |
| op_code != OpCode::HOST_NUMBER_OF_COMPLETED_PACKETS && |
| op_code != OpCode::READ_BUFFER_SIZE && |
| op_code != OpCode::READ_LOOPBACK_MODE && |
| op_code != OpCode::WRITE_LOOPBACK_MODE) { |
| std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = |
| std::make_unique<bluetooth::packet::RawBuilder>(255); |
| raw_builder_ptr->AddOctets(*packet); |
| send_event_(bluetooth::hci::LoopbackCommandBuilder::Create( |
| std::move(raw_builder_ptr))); |
| } |
| // Quirk to reset the host stack when a command is received before the Hci |
| // Reset command. |
| else if (properties_.quirks.hardware_error_before_reset && |
| !controller_reset_ && |
| op_code != OpCode::RESET) { |
| LOG_WARN("Received command %s before HCI Reset; sending the Hardware" |
| " Error event", OpCodeText(op_code).c_str()); |
| send_event_(bluetooth::hci::HardwareErrorBuilder::Create(0x42)); |
| } |
| // Command is both supported and implemented. |
| // Invoke the registered handler. |
| else if (is_supported_command && is_implemented_command) { |
| hci_command_handlers_.at(op_code)(this, command_packet); |
| } |
| // Command is supported but not implemented: |
| // the command needs to be implemented to fix this. |
| else if (is_supported_command) { |
| LOG_ALWAYS_FATAL( |
| "Unimplemented command %s;\n" |
| "This message will be displayed if the command is set as supported\n" |
| "in the command mask but no implementation was provided.\n" |
| "This warning will be fixed by implementing the command in " |
| "DualModeController", |
| OpCodeText(op_code).c_str()); |
| } |
| // The command is not supported. |
| // Respond with the status code Unknown Command. |
| else { |
| SendCommandCompleteUnknownOpCodeEvent(op_code); |
| uint16_t raw_op_code = static_cast<uint16_t>(op_code); |
| LOG_INFO("Unknown command, opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", |
| raw_op_code, (raw_op_code & 0xFC00) >> 10, raw_op_code & 0x03FF); |
| } |
| } |
| |
| void DualModeController::RegisterEventChannel( |
| const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& |
| send_event) { |
| send_event_ = |
| [send_event](std::shared_ptr<bluetooth::hci::EventBuilder> event) { |
| auto bytes = std::make_shared<std::vector<uint8_t>>(); |
| bluetooth::packet::BitInserter bit_inserter(*bytes); |
| bytes->reserve(event->size()); |
| event->Serialize(bit_inserter); |
| send_event(std::move(bytes)); |
| }; |
| link_layer_controller_.RegisterEventChannel(send_event_); |
| } |
| |
| void DualModeController::RegisterAclChannel( |
| const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& |
| send_acl) { |
| send_acl_ = [send_acl](std::shared_ptr<bluetooth::hci::AclBuilder> acl_data) { |
| auto bytes = std::make_shared<std::vector<uint8_t>>(); |
| bluetooth::packet::BitInserter bit_inserter(*bytes); |
| bytes->reserve(acl_data->size()); |
| acl_data->Serialize(bit_inserter); |
| send_acl(std::move(bytes)); |
| }; |
| link_layer_controller_.RegisterAclChannel(send_acl_); |
| } |
| |
| void DualModeController::RegisterScoChannel( |
| const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& |
| send_sco) { |
| send_sco_ = [send_sco](std::shared_ptr<bluetooth::hci::ScoBuilder> sco_data) { |
| auto bytes = std::make_shared<std::vector<uint8_t>>(); |
| bluetooth::packet::BitInserter bit_inserter(*bytes); |
| bytes->reserve(sco_data->size()); |
| sco_data->Serialize(bit_inserter); |
| send_sco(std::move(bytes)); |
| }; |
| link_layer_controller_.RegisterScoChannel(send_sco_); |
| } |
| |
| void DualModeController::RegisterIsoChannel( |
| const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& |
| send_iso) { |
| send_iso_ = [send_iso](std::shared_ptr<bluetooth::hci::IsoBuilder> iso_data) { |
| auto bytes = std::make_shared<std::vector<uint8_t>>(); |
| bluetooth::packet::BitInserter bit_inserter(*bytes); |
| bytes->reserve(iso_data->size()); |
| iso_data->Serialize(bit_inserter); |
| send_iso(std::move(bytes)); |
| }; |
| link_layer_controller_.RegisterIsoChannel(send_iso_); |
| } |
| |
| void DualModeController::Reset(CommandView command) { |
| auto command_view = bluetooth::hci::ResetView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.Reset(); |
| if (loopback_mode_ == LoopbackMode::ENABLE_LOCAL) { |
| loopback_mode_ = LoopbackMode::NO_LOOPBACK; |
| } |
| |
| controller_reset_ = true; |
| send_event_(bluetooth::hci::ResetCompleteBuilder::Create(kNumCommandPackets, |
| ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadBufferSize(CommandView command) { |
| auto command_view = bluetooth::hci::ReadBufferSizeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| send_event_(bluetooth::hci::ReadBufferSizeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| properties_.acl_data_packet_length, properties_.sco_data_packet_length, |
| properties_.total_num_acl_data_packets, |
| properties_.total_num_sco_data_packets)); |
| } |
| |
| void DualModeController::ReadFailedContactCounter(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadFailedContactCounterView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t connection_handle = command_view.GetConnectionHandle(); |
| uint16_t failed_contact_counter = 0; |
| ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) |
| ? ErrorCode::SUCCESS |
| : ErrorCode::UNKNOWN_CONNECTION; |
| |
| send_event_(bluetooth::hci::ReadFailedContactCounterCompleteBuilder::Create( |
| kNumCommandPackets, status, connection_handle, failed_contact_counter)); |
| } |
| |
| void DualModeController::ResetFailedContactCounter(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadFailedContactCounterView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t connection_handle = command_view.GetConnectionHandle(); |
| ErrorCode status = link_layer_controller_.HasAclConnection(connection_handle) |
| ? ErrorCode::SUCCESS |
| : ErrorCode::UNKNOWN_CONNECTION; |
| |
| send_event_(bluetooth::hci::ResetFailedContactCounterCompleteBuilder::Create( |
| kNumCommandPackets, status, connection_handle)); |
| } |
| |
| void DualModeController::ReadRssi(CommandView command) { |
| auto command_view = bluetooth::hci::ReadRssiView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t connection_handle = command_view.GetConnectionHandle(); |
| int8_t rssi = 0; |
| |
| ErrorCode status = link_layer_controller_.ReadRssi(connection_handle, &rssi); |
| send_event_(bluetooth::hci::ReadRssiCompleteBuilder::Create( |
| kNumCommandPackets, status, connection_handle, rssi)); |
| } |
| |
| void DualModeController::ReadEncryptionKeySize(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadEncryptionKeySizeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| send_event_(bluetooth::hci::ReadEncryptionKeySizeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| command_view.GetConnectionHandle(), |
| link_layer_controller_.GetEncryptionKeySize())); |
| } |
| |
| void DualModeController::HostBufferSize(CommandView command) { |
| auto command_view = bluetooth::hci::HostBufferSizeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::HostBufferSizeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadLocalVersionInformation(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadLocalVersionInformationView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| bluetooth::hci::LocalVersionInformation local_version_information; |
| local_version_information.hci_version_ = properties_.hci_version; |
| local_version_information.lmp_version_ = properties_.lmp_version; |
| local_version_information.hci_revision_ = properties_.hci_subversion; |
| local_version_information.lmp_subversion_ = properties_.lmp_subversion; |
| local_version_information.manufacturer_name_ = properties_.company_identifier; |
| |
| send_event_( |
| bluetooth::hci::ReadLocalVersionInformationCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, local_version_information)); |
| } |
| |
| void DualModeController::ReadRemoteVersionInformation(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadRemoteVersionInformationView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto status = link_layer_controller_.SendCommandToRemoteByHandle( |
| OpCode::READ_REMOTE_VERSION_INFORMATION, command.GetPayload(), |
| command_view.GetConnectionHandle()); |
| |
| send_event_(bluetooth::hci::ReadRemoteVersionInformationStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::ReadBdAddr(CommandView command) { |
| auto command_view = bluetooth::hci::ReadBdAddrView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::ReadBdAddrCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, GetAddress())); |
| } |
| |
| void DualModeController::ReadLocalSupportedCommands(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadLocalSupportedCommandsView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::ReadLocalSupportedCommandsCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, properties_.supported_commands)); |
| } |
| |
| void DualModeController::ReadLocalSupportedFeatures(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadLocalSupportedFeaturesView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| send_event_(bluetooth::hci::ReadLocalSupportedFeaturesCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| link_layer_controller_.GetLmpFeatures())); |
| } |
| |
| void DualModeController::ReadLocalSupportedCodecsV1(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadLocalSupportedCodecsV1View::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::ReadLocalSupportedCodecsV1CompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| properties_.supported_standard_codecs, |
| properties_.supported_vendor_specific_codecs)); |
| } |
| |
| void DualModeController::ReadLocalExtendedFeatures(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadLocalExtendedFeaturesView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint8_t page_number = command_view.GetPageNumber(); |
| |
| send_event_(bluetooth::hci::ReadLocalExtendedFeaturesCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, page_number, |
| link_layer_controller_.GetMaxLmpFeaturesPageNumber(), |
| link_layer_controller_.GetLmpFeatures(page_number))); |
| } |
| |
| void DualModeController::ReadRemoteExtendedFeatures(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadRemoteExtendedFeaturesView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto status = link_layer_controller_.SendCommandToRemoteByHandle( |
| OpCode::READ_REMOTE_EXTENDED_FEATURES, command_view.GetPayload(), |
| command_view.GetConnectionHandle()); |
| |
| send_event_(bluetooth::hci::ReadRemoteExtendedFeaturesStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::SwitchRole(CommandView command) { |
| auto command_view = bluetooth::hci::SwitchRoleView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto status = link_layer_controller_.SwitchRole(command_view.GetBdAddr(), |
| command_view.GetRole()); |
| |
| send_event_(bluetooth::hci::SwitchRoleStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::ReadRemoteSupportedFeatures(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadRemoteSupportedFeaturesView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto status = link_layer_controller_.SendCommandToRemoteByHandle( |
| OpCode::READ_REMOTE_SUPPORTED_FEATURES, command_view.GetPayload(), |
| command_view.GetConnectionHandle()); |
| |
| send_event_(bluetooth::hci::ReadRemoteSupportedFeaturesStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::ReadClockOffset(CommandView command) { |
| auto command_view = bluetooth::hci::ReadClockOffsetView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t handle = command_view.GetConnectionHandle(); |
| |
| auto status = link_layer_controller_.SendCommandToRemoteByHandle( |
| OpCode::READ_CLOCK_OFFSET, command_view.GetPayload(), handle); |
| |
| send_event_(bluetooth::hci::ReadClockOffsetStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| // Deprecated command, removed in v4.2. |
| // Support is provided to satisfy PTS tester requirements. |
| void DualModeController::AddScoConnection(CommandView command) { |
| auto command_view = bluetooth::hci::AddScoConnectionView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto status = link_layer_controller_.AddScoConnection( |
| command_view.GetConnectionHandle(), command_view.GetPacketType(), |
| ScoDatapath::NORMAL); |
| |
| send_event_(bluetooth::hci::AddScoConnectionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::SetupSynchronousConnection(CommandView command) { |
| auto command_view = |
| bluetooth::hci::SetupSynchronousConnectionView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto status = link_layer_controller_.SetupSynchronousConnection( |
| command_view.GetConnectionHandle(), command_view.GetTransmitBandwidth(), |
| command_view.GetReceiveBandwidth(), command_view.GetMaxLatency(), |
| command_view.GetVoiceSetting(), |
| static_cast<uint8_t>(command_view.GetRetransmissionEffort()), |
| command_view.GetPacketType(), ScoDatapath::NORMAL); |
| |
| send_event_(bluetooth::hci::SetupSynchronousConnectionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::AcceptSynchronousConnection(CommandView command) { |
| auto command_view = |
| bluetooth::hci::AcceptSynchronousConnectionView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto status = link_layer_controller_.AcceptSynchronousConnection( |
| command_view.GetBdAddr(), command_view.GetTransmitBandwidth(), |
| command_view.GetReceiveBandwidth(), command_view.GetMaxLatency(), |
| command_view.GetVoiceSetting(), |
| static_cast<uint8_t>(command_view.GetRetransmissionEffort()), |
| command_view.GetPacketType()); |
| |
| send_event_(bluetooth::hci::AcceptSynchronousConnectionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::EnhancedSetupSynchronousConnection( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::EnhancedSetupSynchronousConnectionView::Create(command); |
| auto status = ErrorCode::SUCCESS; |
| ASSERT(command_view.IsValid()); |
| |
| // The Host shall set the Transmit_Coding_Format and Receive_Coding_Formats |
| // to be equal. |
| auto transmit_coding_format = command_view.GetTransmitCodingFormat(); |
| auto receive_coding_format = command_view.GetReceiveCodingFormat(); |
| if (transmit_coding_format.coding_format_ != |
| receive_coding_format.coding_format_ || |
| transmit_coding_format.company_id_ != receive_coding_format.company_id_ || |
| transmit_coding_format.vendor_specific_codec_id_ != |
| receive_coding_format.vendor_specific_codec_id_) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Transmit_Coding_Format " |
| "(%s)" |
| " and Receive_Coding_Format (%s) as they are not equal", |
| transmit_coding_format.ToString().c_str(), |
| receive_coding_format.ToString().c_str()); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // The Host shall either set the Input_Bandwidth and Output_Bandwidth |
| // to be equal, or shall set one of them to be zero and the other non-zero. |
| auto input_bandwidth = command_view.GetInputBandwidth(); |
| auto output_bandwidth = command_view.GetOutputBandwidth(); |
| if (input_bandwidth != output_bandwidth && input_bandwidth != 0 && |
| output_bandwidth != 0) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Input_Bandwidth (%u)" |
| " and Output_Bandwidth (%u) as they are not equal and different from 0", |
| input_bandwidth, output_bandwidth); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // The Host shall set the Input_Coding_Format and Output_Coding_Format |
| // to be equal. |
| auto input_coding_format = command_view.GetInputCodingFormat(); |
| auto output_coding_format = command_view.GetOutputCodingFormat(); |
| if (input_coding_format.coding_format_ != |
| output_coding_format.coding_format_ || |
| input_coding_format.company_id_ != output_coding_format.company_id_ || |
| input_coding_format.vendor_specific_codec_id_ != |
| output_coding_format.vendor_specific_codec_id_) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Input_Coding_Format (%s)" |
| " and Output_Coding_Format (%s) as they are not equal", |
| input_coding_format.ToString().c_str(), |
| output_coding_format.ToString().c_str()); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // Root-Canal does not implement audio data transport paths other than the |
| // default HCI transport - other transports will receive spoofed data |
| ScoDatapath datapath = ScoDatapath::NORMAL; |
| if (command_view.GetInputDataPath() != bluetooth::hci::ScoDataPath::HCI || |
| command_view.GetOutputDataPath() != bluetooth::hci::ScoDataPath::HCI) { |
| LOG_WARN( |
| "EnhancedSetupSynchronousConnection: Input_Data_Path (%u)" |
| " and/or Output_Data_Path (%u) are not over HCI, so data will be " |
| "spoofed", |
| static_cast<unsigned>(command_view.GetInputDataPath()), |
| static_cast<unsigned>(command_view.GetOutputDataPath())); |
| datapath = ScoDatapath::SPOOFED; |
| } |
| |
| // Either both the Transmit_Coding_Format and Input_Coding_Format shall be |
| // “transparent” or neither shall be. If both are “transparent”, the |
| // Transmit_Bandwidth and the Input_Bandwidth shall be the same and the |
| // Controller shall not modify the data sent to the remote device. |
| auto transmit_bandwidth = command_view.GetTransmitBandwidth(); |
| auto receive_bandwidth = command_view.GetReceiveBandwidth(); |
| if (transmit_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && |
| input_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && |
| transmit_bandwidth != input_bandwidth) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Transmit_Bandwidth (%u)" |
| " and Input_Bandwidth (%u) as they are not equal", |
| transmit_bandwidth, input_bandwidth); |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: the Transmit_Bandwidth and " |
| "Input_Bandwidth shall be equal when both Transmit_Coding_Format " |
| "and Input_Coding_Format are 'transparent'"); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| if ((transmit_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT) != |
| (input_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT)) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Transmit_Coding_Format " |
| "(%s) and Input_Coding_Format (%s) as they are incompatible", |
| transmit_coding_format.ToString().c_str(), |
| input_coding_format.ToString().c_str()); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // Either both the Receive_Coding_Format and Output_Coding_Format shall |
| // be “transparent” or neither shall be. If both are “transparent”, the |
| // Receive_Bandwidth and the Output_Bandwidth shall be the same and the |
| // Controller shall not modify the data sent to the Host. |
| if (receive_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && |
| output_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && |
| receive_bandwidth != output_bandwidth) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Receive_Bandwidth (%u)" |
| " and Output_Bandwidth (%u) as they are not equal", |
| receive_bandwidth, output_bandwidth); |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: the Receive_Bandwidth and " |
| "Output_Bandwidth shall be equal when both Receive_Coding_Format " |
| "and Output_Coding_Format are 'transparent'"); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| if ((receive_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT) != |
| (output_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT)) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Receive_Coding_Format " |
| "(%s) and Output_Coding_Format (%s) as they are incompatible", |
| receive_coding_format.ToString().c_str(), |
| output_coding_format.ToString().c_str()); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| if (status == ErrorCode::SUCCESS) { |
| status = link_layer_controller_.SetupSynchronousConnection( |
| command_view.GetConnectionHandle(), transmit_bandwidth, |
| receive_bandwidth, command_view.GetMaxLatency(), |
| link_layer_controller_.GetVoiceSetting(), |
| static_cast<uint8_t>(command_view.GetRetransmissionEffort()), |
| command_view.GetPacketType(), datapath); |
| } |
| |
| send_event_( |
| bluetooth::hci::EnhancedSetupSynchronousConnectionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::EnhancedAcceptSynchronousConnection( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::EnhancedAcceptSynchronousConnectionView::Create(command); |
| auto status = ErrorCode::SUCCESS; |
| ASSERT(command_view.IsValid()); |
| |
| // The Host shall set the Transmit_Coding_Format and Receive_Coding_Formats |
| // to be equal. |
| auto transmit_coding_format = command_view.GetTransmitCodingFormat(); |
| auto receive_coding_format = command_view.GetReceiveCodingFormat(); |
| if (transmit_coding_format.coding_format_ != |
| receive_coding_format.coding_format_ || |
| transmit_coding_format.company_id_ != receive_coding_format.company_id_ || |
| transmit_coding_format.vendor_specific_codec_id_ != |
| receive_coding_format.vendor_specific_codec_id_) { |
| LOG_INFO( |
| "EnhancedAcceptSynchronousConnection: rejected Transmit_Coding_Format " |
| "(%s)" |
| " and Receive_Coding_Format (%s) as they are not equal", |
| transmit_coding_format.ToString().c_str(), |
| receive_coding_format.ToString().c_str()); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // The Host shall either set the Input_Bandwidth and Output_Bandwidth |
| // to be equal, or shall set one of them to be zero and the other non-zero. |
| auto input_bandwidth = command_view.GetInputBandwidth(); |
| auto output_bandwidth = command_view.GetOutputBandwidth(); |
| if (input_bandwidth != output_bandwidth && input_bandwidth != 0 && |
| output_bandwidth != 0) { |
| LOG_INFO( |
| "EnhancedAcceptSynchronousConnection: rejected Input_Bandwidth (%u)" |
| " and Output_Bandwidth (%u) as they are not equal and different from 0", |
| input_bandwidth, output_bandwidth); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // The Host shall set the Input_Coding_Format and Output_Coding_Format |
| // to be equal. |
| auto input_coding_format = command_view.GetInputCodingFormat(); |
| auto output_coding_format = command_view.GetOutputCodingFormat(); |
| if (input_coding_format.coding_format_ != |
| output_coding_format.coding_format_ || |
| input_coding_format.company_id_ != output_coding_format.company_id_ || |
| input_coding_format.vendor_specific_codec_id_ != |
| output_coding_format.vendor_specific_codec_id_) { |
| LOG_INFO( |
| "EnhancedAcceptSynchronousConnection: rejected Input_Coding_Format (%s)" |
| " and Output_Coding_Format (%s) as they are not equal", |
| input_coding_format.ToString().c_str(), |
| output_coding_format.ToString().c_str()); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // Root-Canal does not implement audio data transport paths other than the |
| // default HCI transport. |
| if (command_view.GetInputDataPath() != bluetooth::hci::ScoDataPath::HCI || |
| command_view.GetOutputDataPath() != bluetooth::hci::ScoDataPath::HCI) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: Input_Data_Path (%u)" |
| " and/or Output_Data_Path (%u) are not over HCI, so data will be " |
| "spoofed", |
| static_cast<unsigned>(command_view.GetInputDataPath()), |
| static_cast<unsigned>(command_view.GetOutputDataPath())); |
| } |
| |
| // Either both the Transmit_Coding_Format and Input_Coding_Format shall be |
| // “transparent” or neither shall be. If both are “transparent”, the |
| // Transmit_Bandwidth and the Input_Bandwidth shall be the same and the |
| // Controller shall not modify the data sent to the remote device. |
| auto transmit_bandwidth = command_view.GetTransmitBandwidth(); |
| auto receive_bandwidth = command_view.GetReceiveBandwidth(); |
| if (transmit_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && |
| input_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && |
| transmit_bandwidth != input_bandwidth) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Transmit_Bandwidth (%u)" |
| " and Input_Bandwidth (%u) as they are not equal", |
| transmit_bandwidth, input_bandwidth); |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: the Transmit_Bandwidth and " |
| "Input_Bandwidth shall be equal when both Transmit_Coding_Format " |
| "and Input_Coding_Format are 'transparent'"); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| if ((transmit_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT) != |
| (input_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT)) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Transmit_Coding_Format " |
| "(%s) and Input_Coding_Format (%s) as they are incompatible", |
| transmit_coding_format.ToString().c_str(), |
| input_coding_format.ToString().c_str()); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| // Either both the Receive_Coding_Format and Output_Coding_Format shall |
| // be “transparent” or neither shall be. If both are “transparent”, the |
| // Receive_Bandwidth and the Output_Bandwidth shall be the same and the |
| // Controller shall not modify the data sent to the Host. |
| if (receive_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && |
| output_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT && |
| receive_bandwidth != output_bandwidth) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Receive_Bandwidth (%u)" |
| " and Output_Bandwidth (%u) as they are not equal", |
| receive_bandwidth, output_bandwidth); |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: the Receive_Bandwidth and " |
| "Output_Bandwidth shall be equal when both Receive_Coding_Format " |
| "and Output_Coding_Format are 'transparent'"); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| if ((receive_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT) != |
| (output_coding_format.coding_format_ == |
| bluetooth::hci::ScoCodingFormatValues::TRANSPARENT)) { |
| LOG_INFO( |
| "EnhancedSetupSynchronousConnection: rejected Receive_Coding_Format " |
| "(%s) and Output_Coding_Format (%s) as they are incompatible", |
| receive_coding_format.ToString().c_str(), |
| output_coding_format.ToString().c_str()); |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } |
| |
| if (status == ErrorCode::SUCCESS) { |
| status = link_layer_controller_.AcceptSynchronousConnection( |
| command_view.GetBdAddr(), transmit_bandwidth, receive_bandwidth, |
| command_view.GetMaxLatency(), link_layer_controller_.GetVoiceSetting(), |
| static_cast<uint8_t>(command_view.GetRetransmissionEffort()), |
| command_view.GetPacketType()); |
| } |
| |
| send_event_( |
| bluetooth::hci::EnhancedAcceptSynchronousConnectionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::RejectSynchronousConnection(CommandView command) { |
| auto command_view = |
| bluetooth::hci::RejectSynchronousConnectionView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto status = link_layer_controller_.RejectSynchronousConnection( |
| command_view.GetBdAddr(), (uint16_t)command_view.GetReason()); |
| |
| send_event_(bluetooth::hci::RejectSynchronousConnectionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::ReadInquiryResponseTransmitPowerLevel( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadInquiryResponseTransmitPowerLevelView::Create( |
| command); |
| ASSERT(command_view.IsValid()); |
| |
| uint8_t tx_power = 20; // maximum |
| send_event_( |
| bluetooth::hci::ReadInquiryResponseTransmitPowerLevelCompleteBuilder:: |
| Create(kNumCommandPackets, ErrorCode::SUCCESS, tx_power)); |
| } |
| |
| void DualModeController::EnhancedFlush(CommandView command) { |
| auto command_view = bluetooth::hci::EnhancedFlushView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto handle = command_view.GetConnectionHandle(); |
| send_event_(bluetooth::hci::EnhancedFlushStatusBuilder::Create( |
| ErrorCode::SUCCESS, kNumCommandPackets)); |
| |
| // TODO: When adding a queue of ACL packets. |
| // Send the Enhanced Flush Complete event after discarding |
| // all L2CAP packets identified by the Packet Type. |
| if (link_layer_controller_.IsEventUnmasked( |
| bluetooth::hci::EventCode::ENHANCED_FLUSH_COMPLETE)) { |
| send_event_(bluetooth::hci::EnhancedFlushCompleteBuilder::Create(handle)); |
| } |
| } |
| |
| void DualModeController::SetEventMaskPage2(CommandView command) { |
| auto command_view = bluetooth::hci::SetEventMaskPage2View::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetEventMaskPage2(command_view.GetEventMaskPage2()); |
| send_event_(bluetooth::hci::SetEventMaskPage2CompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadLocalOobData(CommandView command) { |
| auto command_view = bluetooth::hci::ReadLocalOobDataView::Create(command); |
| link_layer_controller_.ReadLocalOobData(); |
| } |
| |
| void DualModeController::ReadLocalOobExtendedData(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadLocalOobExtendedDataView::Create(command); |
| link_layer_controller_.ReadLocalOobExtendedData(); |
| } |
| |
| void DualModeController::WriteSimplePairingMode(CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteSimplePairingModeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto enabled = |
| command_view.GetSimplePairingMode() == bluetooth::hci::Enable::ENABLED; |
| link_layer_controller_.SetSecureSimplePairingSupport(enabled); |
| send_event_(bluetooth::hci::WriteSimplePairingModeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ChangeConnectionPacketType(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ChangeConnectionPacketTypeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t handle = command_view.GetConnectionHandle(); |
| uint16_t packet_type = static_cast<uint16_t>(command_view.GetPacketType()); |
| |
| auto status = |
| link_layer_controller_.ChangeConnectionPacketType(handle, packet_type); |
| send_event_(bluetooth::hci::ChangeConnectionPacketTypeStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::WriteLeHostSupport(CommandView command) { |
| auto command_view = bluetooth::hci::WriteLeHostSupportView::Create(command); |
| ASSERT(command_view.IsValid()); |
| auto le_support = |
| command_view.GetLeSupportedHost() == bluetooth::hci::Enable::ENABLED; |
| link_layer_controller_.SetLeHostSupport(le_support); |
| send_event_(bluetooth::hci::WriteLeHostSupportCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::WriteSecureConnectionsHostSupport( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteSecureConnectionsHostSupportView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetSecureConnectionsSupport( |
| command_view.GetSecureConnectionsHostSupport() == |
| bluetooth::hci::Enable::ENABLED); |
| send_event_( |
| bluetooth::hci::WriteSecureConnectionsHostSupportCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::SetEventMask(CommandView command) { |
| auto command_view = bluetooth::hci::SetEventMaskView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetEventMask(command_view.GetEventMask()); |
| send_event_(bluetooth::hci::SetEventMaskCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadInquiryMode(CommandView command) { |
| auto command_view = bluetooth::hci::ReadInquiryModeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| bluetooth::hci::InquiryMode inquiry_mode = |
| bluetooth::hci::InquiryMode::STANDARD; |
| send_event_(bluetooth::hci::ReadInquiryModeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, inquiry_mode)); |
| } |
| |
| void DualModeController::WriteInquiryMode(CommandView command) { |
| auto command_view = bluetooth::hci::WriteInquiryModeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetInquiryMode( |
| static_cast<uint8_t>(command_view.GetInquiryMode())); |
| send_event_(bluetooth::hci::WriteInquiryModeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadPageScanType(CommandView command) { |
| auto command_view = bluetooth::hci::ReadPageScanTypeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| bluetooth::hci::PageScanType page_scan_type = |
| bluetooth::hci::PageScanType::STANDARD; |
| send_event_(bluetooth::hci::ReadPageScanTypeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, page_scan_type)); |
| } |
| |
| void DualModeController::WritePageScanType(CommandView command) { |
| auto command_view = bluetooth::hci::WritePageScanTypeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::WritePageScanTypeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadInquiryScanType(CommandView command) { |
| auto command_view = bluetooth::hci::ReadInquiryScanTypeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| bluetooth::hci::InquiryScanType inquiry_scan_type = |
| bluetooth::hci::InquiryScanType::STANDARD; |
| send_event_(bluetooth::hci::ReadInquiryScanTypeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, inquiry_scan_type)); |
| } |
| |
| void DualModeController::WriteInquiryScanType(CommandView command) { |
| auto command_view = bluetooth::hci::WriteInquiryScanTypeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::WriteInquiryScanTypeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ChangeConnectionLinkKey(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ChangeConnectionLinkKeyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t handle = command_view.GetConnectionHandle(); |
| |
| auto status = link_layer_controller_.ChangeConnectionLinkKey(handle); |
| |
| send_event_(bluetooth::hci::ChangeConnectionLinkKeyStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::CentralLinkKey(CommandView command) { |
| auto command_view = bluetooth::hci::CentralLinkKeyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint8_t key_flag = static_cast<uint8_t>(command_view.GetKeyFlag()); |
| |
| auto status = link_layer_controller_.CentralLinkKey(key_flag); |
| |
| send_event_(bluetooth::hci::CentralLinkKeyStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::WriteAuthenticationEnable(CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteAuthenticationEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetAuthenticationEnable( |
| command_view.GetAuthenticationEnable()); |
| send_event_(bluetooth::hci::WriteAuthenticationEnableCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadAuthenticationEnable(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadAuthenticationEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::ReadAuthenticationEnableCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| static_cast<bluetooth::hci::AuthenticationEnable>( |
| link_layer_controller_.GetAuthenticationEnable()))); |
| } |
| |
| void DualModeController::WriteClassOfDevice(CommandView command) { |
| auto command_view = bluetooth::hci::WriteClassOfDeviceView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetClassOfDevice(command_view.GetClassOfDevice()); |
| send_event_(bluetooth::hci::WriteClassOfDeviceCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadPageTimeout(CommandView command) { |
| auto command_view = bluetooth::hci::ReadPageTimeoutView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t page_timeout = link_layer_controller_.GetPageTimeout(); |
| send_event_(bluetooth::hci::ReadPageTimeoutCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, page_timeout)); |
| } |
| |
| void DualModeController::WritePageTimeout(CommandView command) { |
| auto command_view = bluetooth::hci::WritePageTimeoutView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetPageTimeout(command_view.GetPageTimeout()); |
| send_event_(bluetooth::hci::WritePageTimeoutCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::HoldMode(CommandView command) { |
| auto command_view = bluetooth::hci::HoldModeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t handle = command_view.GetConnectionHandle(); |
| uint16_t hold_mode_max_interval = command_view.GetHoldModeMaxInterval(); |
| uint16_t hold_mode_min_interval = command_view.GetHoldModeMinInterval(); |
| |
| auto status = link_layer_controller_.HoldMode(handle, hold_mode_max_interval, |
| hold_mode_min_interval); |
| |
| send_event_(bluetooth::hci::HoldModeStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::SniffMode(CommandView command) { |
| auto command_view = bluetooth::hci::SniffModeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t handle = command_view.GetConnectionHandle(); |
| uint16_t sniff_max_interval = command_view.GetSniffMaxInterval(); |
| uint16_t sniff_min_interval = command_view.GetSniffMinInterval(); |
| uint16_t sniff_attempt = command_view.GetSniffAttempt(); |
| uint16_t sniff_timeout = command_view.GetSniffTimeout(); |
| |
| auto status = link_layer_controller_.SniffMode(handle, sniff_max_interval, |
| sniff_min_interval, |
| sniff_attempt, sniff_timeout); |
| |
| send_event_(bluetooth::hci::SniffModeStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::ExitSniffMode(CommandView command) { |
| auto command_view = bluetooth::hci::ExitSniffModeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto status = |
| link_layer_controller_.ExitSniffMode(command_view.GetConnectionHandle()); |
| |
| send_event_(bluetooth::hci::ExitSniffModeStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::QosSetup(CommandView command) { |
| auto command_view = bluetooth::hci::QosSetupView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t handle = command_view.GetConnectionHandle(); |
| uint8_t service_type = static_cast<uint8_t>(command_view.GetServiceType()); |
| uint32_t token_rate = command_view.GetTokenRate(); |
| uint32_t peak_bandwidth = command_view.GetPeakBandwidth(); |
| uint32_t latency = command_view.GetLatency(); |
| uint32_t delay_variation = command_view.GetDelayVariation(); |
| |
| auto status = |
| link_layer_controller_.QosSetup(handle, service_type, token_rate, |
| peak_bandwidth, latency, delay_variation); |
| |
| send_event_(bluetooth::hci::QosSetupStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::RoleDiscovery(CommandView command) { |
| auto command_view = bluetooth::hci::RoleDiscoveryView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t handle = command_view.GetConnectionHandle(); |
| |
| auto role = bluetooth::hci::Role::CENTRAL; |
| auto status = link_layer_controller_.RoleDiscovery(handle, &role); |
| |
| send_event_(bluetooth::hci::RoleDiscoveryCompleteBuilder::Create( |
| kNumCommandPackets, status, handle, role)); |
| } |
| |
| void DualModeController::ReadDefaultLinkPolicySettings(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadDefaultLinkPolicySettingsView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t settings = link_layer_controller_.ReadDefaultLinkPolicySettings(); |
| send_event_( |
| bluetooth::hci::ReadDefaultLinkPolicySettingsCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, settings)); |
| } |
| |
| void DualModeController::WriteDefaultLinkPolicySettings(CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteDefaultLinkPolicySettingsView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.WriteDefaultLinkPolicySettings( |
| command_view.GetDefaultLinkPolicySettings()); |
| send_event_( |
| bluetooth::hci::WriteDefaultLinkPolicySettingsCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::FlowSpecification(CommandView command) { |
| auto command_view = bluetooth::hci::FlowSpecificationView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t handle = command_view.GetConnectionHandle(); |
| uint8_t flow_direction = |
| static_cast<uint8_t>(command_view.GetFlowDirection()); |
| uint8_t service_type = static_cast<uint8_t>(command_view.GetServiceType()); |
| uint32_t token_rate = command_view.GetTokenRate(); |
| uint32_t token_bucket_size = command_view.GetTokenBucketSize(); |
| uint32_t peak_bandwidth = command_view.GetPeakBandwidth(); |
| uint32_t access_latency = command_view.GetAccessLatency(); |
| |
| auto status = link_layer_controller_.FlowSpecification( |
| handle, flow_direction, service_type, token_rate, token_bucket_size, |
| peak_bandwidth, access_latency); |
| |
| send_event_(bluetooth::hci::FlowSpecificationStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::ReadLinkPolicySettings(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadLinkPolicySettingsView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t handle = command_view.GetConnectionHandle(); |
| uint16_t settings; |
| |
| auto status = |
| link_layer_controller_.ReadLinkPolicySettings(handle, &settings); |
| |
| send_event_(bluetooth::hci::ReadLinkPolicySettingsCompleteBuilder::Create( |
| kNumCommandPackets, status, handle, settings)); |
| } |
| |
| void DualModeController::WriteLinkPolicySettings(CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteLinkPolicySettingsView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t handle = command_view.GetConnectionHandle(); |
| uint16_t settings = command_view.GetLinkPolicySettings(); |
| |
| auto status = |
| link_layer_controller_.WriteLinkPolicySettings(handle, settings); |
| |
| send_event_(bluetooth::hci::WriteLinkPolicySettingsCompleteBuilder::Create( |
| kNumCommandPackets, status, handle)); |
| } |
| |
| void DualModeController::WriteLinkSupervisionTimeout(CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteLinkSupervisionTimeoutView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t handle = command_view.GetConnectionHandle(); |
| uint16_t timeout = command_view.GetLinkSupervisionTimeout(); |
| |
| auto status = |
| link_layer_controller_.WriteLinkSupervisionTimeout(handle, timeout); |
| send_event_( |
| bluetooth::hci::WriteLinkSupervisionTimeoutCompleteBuilder::Create( |
| kNumCommandPackets, status, handle)); |
| } |
| |
| void DualModeController::ReadLocalName(CommandView command) { |
| auto command_view = bluetooth::hci::ReadLocalNameView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::ReadLocalNameCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| link_layer_controller_.GetLocalName())); |
| } |
| |
| void DualModeController::WriteLocalName(CommandView command) { |
| auto command_view = bluetooth::hci::WriteLocalNameView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetLocalName(command_view.GetLocalName()); |
| send_event_(bluetooth::hci::WriteLocalNameCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::WriteExtendedInquiryResponse(CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteExtendedInquiryResponseView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetExtendedInquiryResponse(std::vector<uint8_t>( |
| command_view.GetPayload().begin() + 1, command_view.GetPayload().end())); |
| send_event_( |
| bluetooth::hci::WriteExtendedInquiryResponseCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::RefreshEncryptionKey(CommandView command) { |
| auto command_view = bluetooth::hci::RefreshEncryptionKeyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t handle = command_view.GetConnectionHandle(); |
| send_event_(bluetooth::hci::RefreshEncryptionKeyStatusBuilder::Create( |
| ErrorCode::SUCCESS, kNumCommandPackets)); |
| // TODO: Support this in the link layer |
| send_event_(bluetooth::hci::EncryptionKeyRefreshCompleteBuilder::Create( |
| ErrorCode::SUCCESS, handle)); |
| } |
| |
| void DualModeController::WriteVoiceSetting(CommandView command) { |
| auto command_view = bluetooth::hci::WriteVoiceSettingView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| link_layer_controller_.SetVoiceSetting(command_view.GetVoiceSetting()); |
| |
| send_event_(bluetooth::hci::WriteVoiceSettingCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadNumberOfSupportedIac(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadNumberOfSupportedIacView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::ReadNumberOfSupportedIacCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, properties_.num_supported_iac)); |
| } |
| |
| void DualModeController::ReadCurrentIacLap(CommandView command) { |
| auto command_view = bluetooth::hci::ReadCurrentIacLapView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::ReadCurrentIacLapCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| link_layer_controller_.ReadCurrentIacLap())); |
| } |
| |
| void DualModeController::WriteCurrentIacLap(CommandView command) { |
| auto command_view = bluetooth::hci::WriteCurrentIacLapView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.WriteCurrentIacLap(command_view.GetLapsToWrite()); |
| send_event_(bluetooth::hci::WriteCurrentIacLapCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadPageScanActivity(CommandView command) { |
| auto command_view = bluetooth::hci::ReadPageScanActivityView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t interval = 0x1000; |
| uint16_t window = 0x0012; |
| send_event_(bluetooth::hci::ReadPageScanActivityCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, interval, window)); |
| } |
| |
| void DualModeController::WritePageScanActivity(CommandView command) { |
| auto command_view = |
| bluetooth::hci::WritePageScanActivityView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::WritePageScanActivityCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadInquiryScanActivity(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadInquiryScanActivityView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t interval = 0x1000; |
| uint16_t window = 0x0012; |
| send_event_(bluetooth::hci::ReadInquiryScanActivityCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, interval, window)); |
| } |
| |
| void DualModeController::WriteInquiryScanActivity(CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteInquiryScanActivityView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::WriteInquiryScanActivityCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadScanEnable(CommandView command) { |
| auto command_view = bluetooth::hci::ReadScanEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| bool inquiry_scan = link_layer_controller_.GetInquiryScanEnable(); |
| bool page_scan = link_layer_controller_.GetPageScanEnable(); |
| |
| bluetooth::hci::ScanEnable scan_enable = |
| inquiry_scan && page_scan |
| ? bluetooth::hci::ScanEnable::INQUIRY_AND_PAGE_SCAN |
| : inquiry_scan ? bluetooth::hci::ScanEnable::INQUIRY_SCAN_ONLY |
| : page_scan ? bluetooth::hci::ScanEnable::PAGE_SCAN_ONLY |
| : bluetooth::hci::ScanEnable::NO_SCANS; |
| |
| send_event_(bluetooth::hci::ReadScanEnableCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, scan_enable)); |
| } |
| |
| void DualModeController::WriteScanEnable(CommandView command) { |
| auto command_view = bluetooth::hci::WriteScanEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| bluetooth::hci::ScanEnable scan_enable = command_view.GetScanEnable(); |
| bool inquiry_scan = |
| scan_enable == bluetooth::hci::ScanEnable::INQUIRY_AND_PAGE_SCAN || |
| scan_enable == bluetooth::hci::ScanEnable::INQUIRY_SCAN_ONLY; |
| bool page_scan = |
| scan_enable == bluetooth::hci::ScanEnable::INQUIRY_AND_PAGE_SCAN || |
| scan_enable == bluetooth::hci::ScanEnable::PAGE_SCAN_ONLY; |
| |
| LOG_INFO("%s | WriteScanEnable %s", GetAddress().ToString().c_str(), |
| bluetooth::hci::ScanEnableText(scan_enable).c_str()); |
| |
| link_layer_controller_.SetInquiryScanEnable(inquiry_scan); |
| link_layer_controller_.SetPageScanEnable(page_scan); |
| send_event_(bluetooth::hci::WriteScanEnableCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadSynchronousFlowControlEnable(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadSynchronousFlowControlEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| auto enabled = bluetooth::hci::Enable::DISABLED; |
| if (link_layer_controller_.GetScoFlowControlEnable()) { |
| enabled = bluetooth::hci::Enable::ENABLED; |
| } |
| send_event_( |
| bluetooth::hci::ReadSynchronousFlowControlEnableCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, enabled)); |
| } |
| |
| void DualModeController::WriteSynchronousFlowControlEnable( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteSynchronousFlowControlEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| auto enabled = command_view.GetEnable() == bluetooth::hci::Enable::ENABLED; |
| link_layer_controller_.SetScoFlowControlEnable(enabled); |
| send_event_( |
| bluetooth::hci::WriteSynchronousFlowControlEnableCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::SetEventFilter(CommandView command) { |
| auto command_view = bluetooth::hci::SetEventFilterView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::SetEventFilterCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::Inquiry(CommandView command) { |
| auto command_view = bluetooth::hci::InquiryView::Create(command); |
| ASSERT(command_view.IsValid()); |
| auto max_responses = command_view.GetNumResponses(); |
| auto length = command_view.GetInquiryLength(); |
| if (max_responses > 0xff || length < 1 || length > 0x30) { |
| send_event_(bluetooth::hci::InquiryStatusBuilder::Create( |
| ErrorCode::INVALID_HCI_COMMAND_PARAMETERS, kNumCommandPackets)); |
| return; |
| } |
| link_layer_controller_.SetInquiryLAP(command_view.GetLap().lap_); |
| link_layer_controller_.SetInquiryMaxResponses(max_responses); |
| link_layer_controller_.StartInquiry(std::chrono::milliseconds(length * 1280)); |
| |
| send_event_(bluetooth::hci::InquiryStatusBuilder::Create(ErrorCode::SUCCESS, |
| kNumCommandPackets)); |
| } |
| |
| void DualModeController::InquiryCancel(CommandView command) { |
| auto command_view = bluetooth::hci::InquiryCancelView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.InquiryCancel(); |
| send_event_(bluetooth::hci::InquiryCancelCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::AcceptConnectionRequest(CommandView command) { |
| auto command_view = |
| bluetooth::hci::AcceptConnectionRequestView::Create(command); |
| ASSERT(command_view.IsValid()); |
| Address addr = command_view.GetBdAddr(); |
| bool try_role_switch = |
| command_view.GetRole() == |
| bluetooth::hci::AcceptConnectionRequestRole::BECOME_CENTRAL; |
| auto status = |
| link_layer_controller_.AcceptConnectionRequest(addr, try_role_switch); |
| send_event_(bluetooth::hci::AcceptConnectionRequestStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::RejectConnectionRequest(CommandView command) { |
| auto command_view = |
| bluetooth::hci::RejectConnectionRequestView::Create(command); |
| ASSERT(command_view.IsValid()); |
| Address addr = command_view.GetBdAddr(); |
| uint8_t reason = static_cast<uint8_t>(command_view.GetReason()); |
| auto status = link_layer_controller_.RejectConnectionRequest(addr, reason); |
| send_event_(bluetooth::hci::RejectConnectionRequestStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::DeleteStoredLinkKey(CommandView command) { |
| auto command_view = bluetooth::hci::DeleteStoredLinkKeyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| send_event_(bluetooth::hci::DeleteStoredLinkKeyCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, 0)); |
| } |
| |
| void DualModeController::RemoteNameRequest(CommandView command) { |
| auto command_view = bluetooth::hci::RemoteNameRequestView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| Address remote_addr = command_view.GetBdAddr(); |
| |
| auto status = link_layer_controller_.SendCommandToRemoteByAddress( |
| OpCode::REMOTE_NAME_REQUEST, command_view.GetPayload(), GetAddress(), |
| remote_addr); |
| |
| send_event_(bluetooth::hci::RemoteNameRequestStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeSetEventMask(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetEventMaskView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.SetLeEventMask(command_view.GetLeEventMask()); |
| send_event_(bluetooth::hci::LeSetEventMaskCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::LeSetHostFeature(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetHostFeatureView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| ErrorCode status = link_layer_controller_.LeSetHostFeature( |
| static_cast<uint8_t>(command_view.GetBitNumber()), |
| static_cast<uint8_t>(command_view.GetBitValue())); |
| send_event_(bluetooth::hci::LeSetHostFeatureCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeReadBufferSizeV1(CommandView command) { |
| auto command_view = bluetooth::hci::LeReadBufferSizeV1View::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| bluetooth::hci::LeBufferSize le_buffer_size; |
| le_buffer_size.le_data_packet_length_ = properties_.le_acl_data_packet_length; |
| le_buffer_size.total_num_le_packets_ = |
| properties_.total_num_le_acl_data_packets; |
| |
| send_event_(bluetooth::hci::LeReadBufferSizeV1CompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, le_buffer_size)); |
| } |
| |
| void DualModeController::LeReadBufferSizeV2(CommandView command) { |
| auto command_view = bluetooth::hci::LeReadBufferSizeV2View::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| bluetooth::hci::LeBufferSize le_buffer_size; |
| le_buffer_size.le_data_packet_length_ = properties_.le_acl_data_packet_length; |
| le_buffer_size.total_num_le_packets_ = |
| properties_.total_num_le_acl_data_packets; |
| bluetooth::hci::LeBufferSize iso_buffer_size; |
| iso_buffer_size.le_data_packet_length_ = properties_.iso_data_packet_length; |
| iso_buffer_size.total_num_le_packets_ = |
| properties_.total_num_iso_data_packets; |
| |
| send_event_(bluetooth::hci::LeReadBufferSizeV2CompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, le_buffer_size, iso_buffer_size)); |
| } |
| |
| void DualModeController::LeSetAddressResolutionEnable(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetAddressResolutionEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetAddressResolutionEnable( |
| command_view.GetAddressResolutionEnable() == |
| bluetooth::hci::Enable::ENABLED); |
| send_event_( |
| bluetooth::hci::LeSetAddressResolutionEnableCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetResolvablePrivateAddressTimeout( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetResolvablePrivateAddressTimeoutView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = |
| link_layer_controller_.LeSetResolvablePrivateAddressTimeout( |
| command_view.GetRpaTimeout()); |
| send_event_( |
| bluetooth::hci::LeSetResolvablePrivateAddressTimeoutCompleteBuilder:: |
| Create(kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeReadLocalSupportedFeatures(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadLocalSupportedFeaturesView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint64_t le_features = link_layer_controller_.GetLeSupportedFeatures(); |
| LOG_INFO("%s | LeReadLocalSupportedFeatures (%016llx)", |
| GetAddress().ToString().c_str(), |
| static_cast<unsigned long long>(le_features)); |
| |
| send_event_( |
| bluetooth::hci::LeReadLocalSupportedFeaturesCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, le_features)); |
| } |
| |
| void DualModeController::LeSetRandomAddress(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetRandomAddressView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetRandomAddress( |
| command_view.GetRandomAddress()); |
| send_event_(bluetooth::hci::LeSetRandomAddressCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetAdvertisingParameters(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetAdvertisingParametersView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetAdvertisingParameters( |
| command_view.GetAdvertisingIntervalMin(), |
| command_view.GetAdvertisingIntervalMax(), |
| command_view.GetAdvertisingType(), command_view.GetOwnAddressType(), |
| command_view.GetPeerAddressType(), command_view.GetPeerAddress(), |
| command_view.GetAdvertisingChannelMap(), |
| command_view.GetAdvertisingFilterPolicy()); |
| send_event_(bluetooth::hci::LeSetAdvertisingParametersCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeReadAdvertisingPhysicalChannelTxPower( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadAdvertisingPhysicalChannelTxPowerView::Create( |
| command); |
| ASSERT(command_view.IsValid()); |
| send_event_( |
| bluetooth::hci::LeReadAdvertisingPhysicalChannelTxPowerCompleteBuilder:: |
| Create(kNumCommandPackets, ErrorCode::SUCCESS, |
| properties_.le_advertising_physical_channel_tx_power)); |
| } |
| |
| void DualModeController::LeSetAdvertisingData(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetAdvertisingDataView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetAdvertisingData( |
| command_view.GetAdvertisingData()); |
| send_event_(bluetooth::hci::LeSetAdvertisingDataCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetScanResponseData(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetScanResponseDataView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetScanResponseData( |
| command_view.GetAdvertisingData()); |
| send_event_(bluetooth::hci::LeSetScanResponseDataCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetAdvertisingEnable(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetAdvertisingEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| LOG_INFO( |
| "%s | LeSetAdvertisingEnable (%d)", GetAddress().ToString().c_str(), |
| command_view.GetAdvertisingEnable() == bluetooth::hci::Enable::ENABLED); |
| |
| ErrorCode status = link_layer_controller_.LeSetAdvertisingEnable( |
| command_view.GetAdvertisingEnable() == bluetooth::hci::Enable::ENABLED); |
| send_event_(bluetooth::hci::LeSetAdvertisingEnableCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetScanParameters(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetScanParametersView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| ErrorCode status = link_layer_controller_.LeSetScanParameters( |
| command_view.GetLeScanType(), command_view.GetLeScanInterval(), |
| command_view.GetLeScanWindow(), command_view.GetOwnAddressType(), |
| command_view.GetScanningFilterPolicy()); |
| send_event_(bluetooth::hci::LeSetScanParametersCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetScanEnable(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetScanEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| LOG_INFO("%s | LeSetScanEnable (%d)", GetAddress().ToString().c_str(), |
| command_view.GetLeScanEnable() == bluetooth::hci::Enable::ENABLED); |
| |
| ErrorCode status = link_layer_controller_.LeSetScanEnable( |
| command_view.GetLeScanEnable() == bluetooth::hci::Enable::ENABLED, |
| command_view.GetFilterDuplicates() == bluetooth::hci::Enable::ENABLED); |
| send_event_(bluetooth::hci::LeSetScanEnableCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeCreateConnection(CommandView command) { |
| auto command_view = bluetooth::hci::LeCreateConnectionView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeCreateConnection( |
| command_view.GetLeScanInterval(), command_view.GetLeScanWindow(), |
| command_view.GetInitiatorFilterPolicy(), |
| AddressWithType{ |
| command_view.GetPeerAddress(), |
| command_view.GetPeerAddressType(), |
| }, |
| command_view.GetOwnAddressType(), command_view.GetConnIntervalMin(), |
| command_view.GetConnIntervalMax(), command_view.GetConnLatency(), |
| command_view.GetSupervisionTimeout(), command_view.GetMinimumCeLength(), |
| command_view.GetMaximumCeLength()); |
| send_event_(bluetooth::hci::LeCreateConnectionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeCreateConnectionCancel(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeCreateConnectionCancelView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeCreateConnectionCancel(); |
| send_event_(bluetooth::hci::LeCreateConnectionCancelCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeConnectionUpdate(CommandView command) { |
| auto command_view = bluetooth::hci::LeConnectionUpdateView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeConnectionUpdate( |
| command_view.GetConnectionHandle(), command_view.GetConnIntervalMin(), |
| command_view.GetConnIntervalMax(), command_view.GetConnLatency(), |
| command_view.GetSupervisionTimeout()); |
| |
| send_event_(bluetooth::hci::LeConnectionUpdateStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::CreateConnection(CommandView command) { |
| auto command_view = bluetooth::hci::CreateConnectionView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| Address address = command_view.GetBdAddr(); |
| uint16_t packet_type = command_view.GetPacketType(); |
| uint8_t page_scan_mode = |
| static_cast<uint8_t>(command_view.GetPageScanRepetitionMode()); |
| uint16_t clock_offset = (command_view.GetClockOffsetValid() == |
| bluetooth::hci::ClockOffsetValid::VALID |
| ? command_view.GetClockOffset() |
| : 0); |
| uint8_t allow_role_switch = |
| static_cast<uint8_t>(command_view.GetAllowRoleSwitch()); |
| |
| auto status = link_layer_controller_.CreateConnection( |
| address, packet_type, page_scan_mode, clock_offset, allow_role_switch); |
| |
| send_event_(bluetooth::hci::CreateConnectionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::CreateConnectionCancel(CommandView command) { |
| auto command_view = |
| bluetooth::hci::CreateConnectionCancelView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| Address address = command_view.GetBdAddr(); |
| |
| auto status = link_layer_controller_.CreateConnectionCancel(address); |
| |
| send_event_(bluetooth::hci::CreateConnectionCancelCompleteBuilder::Create( |
| kNumCommandPackets, status, address)); |
| } |
| |
| void DualModeController::Disconnect(CommandView command) { |
| auto command_view = bluetooth::hci::DisconnectView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t handle = command_view.GetConnectionHandle(); |
| |
| auto status = link_layer_controller_.Disconnect( |
| handle, ErrorCode(command_view.GetReason())); |
| |
| send_event_(bluetooth::hci::DisconnectStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeReadFilterAcceptListSize(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadFilterAcceptListSizeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::LeReadFilterAcceptListSizeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| properties_.le_filter_accept_list_size)); |
| } |
| |
| void DualModeController::LeClearFilterAcceptList(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeClearFilterAcceptListView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeClearFilterAcceptList(); |
| send_event_(bluetooth::hci::LeClearFilterAcceptListCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeAddDeviceToFilterAcceptList(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeAddDeviceToFilterAcceptListView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeAddDeviceToFilterAcceptList( |
| command_view.GetAddressType(), command_view.GetAddress()); |
| send_event_( |
| bluetooth::hci::LeAddDeviceToFilterAcceptListCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeRemoveDeviceFromFilterAcceptList( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeRemoveDeviceFromFilterAcceptListView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeRemoveDeviceFromFilterAcceptList( |
| command_view.GetAddressType(), command_view.GetAddress()); |
| send_event_( |
| bluetooth::hci::LeRemoveDeviceFromFilterAcceptListCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeClearResolvingList(CommandView command) { |
| auto command_view = bluetooth::hci::LeClearResolvingListView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeClearResolvingList(); |
| send_event_(bluetooth::hci::LeClearResolvingListCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeReadResolvingListSize(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadResolvingListSizeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::LeReadResolvingListSizeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| properties_.le_resolving_list_size)); |
| } |
| |
| void DualModeController::LeReadPeerResolvableAddress(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadPeerResolvableAddressView::Create(command); |
| ASSERT(command_view.IsValid()); |
| Address peer_resolvable_address; |
| ErrorCode status = link_layer_controller_.LeReadPeerResolvableAddress( |
| command_view.GetPeerIdentityAddressType(), |
| command_view.GetPeerIdentityAddress(), &peer_resolvable_address); |
| send_event_( |
| bluetooth::hci::LeReadPeerResolvableAddressCompleteBuilder::Create( |
| kNumCommandPackets, status, peer_resolvable_address)); |
| } |
| |
| void DualModeController::LeReadLocalResolvableAddress(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadLocalResolvableAddressView::Create(command); |
| ASSERT(command_view.IsValid()); |
| Address local_resolvable_address; |
| ErrorCode status = link_layer_controller_.LeReadLocalResolvableAddress( |
| command_view.GetPeerIdentityAddressType(), |
| command_view.GetPeerIdentityAddress(), &local_resolvable_address); |
| send_event_( |
| bluetooth::hci::LeReadLocalResolvableAddressCompleteBuilder::Create( |
| kNumCommandPackets, status, local_resolvable_address)); |
| } |
| |
| void DualModeController::LeReadMaximumDataLength(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadMaximumDataLengthView::Create(command); |
| ASSERT(command_view.IsValid()); |
| bluetooth::hci::LeMaximumDataLength data_length; |
| data_length.supported_max_rx_octets_ = kLeMaximumDataLength; |
| data_length.supported_max_rx_time_ = kLeMaximumDataTime; |
| data_length.supported_max_tx_octets_ = kLeMaximumDataLength + 10; |
| data_length.supported_max_tx_time_ = kLeMaximumDataTime + 10; |
| send_event_(bluetooth::hci::LeReadMaximumDataLengthCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, data_length)); |
| } |
| |
| void DualModeController::LeReadPhy(CommandView command) { |
| auto command_view = bluetooth::hci::LeReadPhyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint16_t connection_handle = command_view.GetConnectionHandle(); |
| bluetooth::hci::PhyType tx_phy{}; |
| bluetooth::hci::PhyType rx_phy{}; |
| ErrorCode status = |
| link_layer_controller_.LeReadPhy(connection_handle, &tx_phy, &rx_phy); |
| send_event_(bluetooth::hci::LeReadPhyCompleteBuilder::Create( |
| kNumCommandPackets, status, connection_handle, tx_phy, rx_phy)); |
| } |
| |
| void DualModeController::LeSetDefaultPhy(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetDefaultPhyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetDefaultPhy( |
| command_view.GetAllPhysNoTransmitPreference(), |
| command_view.GetAllPhysNoReceivePreference(), command_view.GetTxPhys(), |
| command_view.GetRxPhys()); |
| send_event_(bluetooth::hci::LeSetDefaultPhyCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetPhy(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetPhyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetPhy( |
| command_view.GetConnectionHandle(), |
| command_view.GetAllPhysNoTransmitPreference(), |
| command_view.GetAllPhysNoReceivePreference(), command_view.GetTxPhys(), |
| command_view.GetRxPhys(), command_view.GetPhyOptions()); |
| send_event_(bluetooth::hci::LeSetPhyStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeReadSuggestedDefaultDataLength(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadSuggestedDefaultDataLengthView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_( |
| bluetooth::hci::LeReadSuggestedDefaultDataLengthCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| link_layer_controller_.GetLeSuggestedMaxTxOctets(), |
| link_layer_controller_.GetLeSuggestedMaxTxTime())); |
| } |
| |
| void DualModeController::LeWriteSuggestedDefaultDataLength( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeWriteSuggestedDefaultDataLengthView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t max_tx_octets = command_view.GetTxOctets(); |
| uint16_t max_tx_time = command_view.GetTxTime(); |
| ErrorCode status = ErrorCode::SUCCESS; |
| if (max_tx_octets > 0xFB || max_tx_octets < 0x1B || max_tx_time < 0x148 || |
| max_tx_time > 0x4290) { |
| status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS; |
| } else { |
| link_layer_controller_.SetLeSuggestedMaxTxOctets(max_tx_octets); |
| link_layer_controller_.SetLeSuggestedMaxTxTime(max_tx_time); |
| } |
| |
| send_event_( |
| bluetooth::hci::LeWriteSuggestedDefaultDataLengthCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeAddDeviceToResolvingList(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeAddDeviceToResolvingListView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeAddDeviceToResolvingList( |
| command_view.GetPeerIdentityAddressType(), |
| command_view.GetPeerIdentityAddress(), command_view.GetPeerIrk(), |
| command_view.GetLocalIrk()); |
| send_event_(bluetooth::hci::LeAddDeviceToResolvingListCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeRemoveDeviceFromResolvingList(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeRemoveDeviceFromResolvingListView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeRemoveDeviceFromResolvingList( |
| command_view.GetPeerIdentityAddressType(), |
| command_view.GetPeerIdentityAddress()); |
| send_event_( |
| bluetooth::hci::LeRemoveDeviceFromResolvingListCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetPeriodicAdvertisingParameters( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetPeriodicAdvertisingParametersView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetPeriodicAdvertisingParameters( |
| command_view.GetAdvertisingHandle(), |
| command_view.GetPeriodicAdvertisingIntervalMin(), |
| command_view.GetPeriodicAdvertisingIntervalMax(), |
| command_view.GetIncludeTxPower()); |
| send_event_( |
| bluetooth::hci::LeSetPeriodicAdvertisingParametersCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetPeriodicAdvertisingData(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetPeriodicAdvertisingDataView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetPeriodicAdvertisingData( |
| command_view.GetAdvertisingHandle(), command_view.GetOperation(), |
| command_view.GetAdvertisingData()); |
| send_event_( |
| bluetooth::hci::LeSetPeriodicAdvertisingDataCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetPeriodicAdvertisingEnable(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetPeriodicAdvertisingEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetPeriodicAdvertisingEnable( |
| command_view.GetEnable(), command_view.GetIncludeAdi(), |
| command_view.GetAdvertisingHandle()); |
| send_event_( |
| bluetooth::hci::LeSetPeriodicAdvertisingEnableCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LePeriodicAdvertisingCreateSync(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LePeriodicAdvertisingCreateSyncView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LePeriodicAdvertisingCreateSync( |
| command_view.GetOptions(), command_view.GetAdvertisingSid(), |
| command_view.GetAdvertiserAddressType(), |
| command_view.GetAdvertiserAddress(), command_view.GetSkip(), |
| command_view.GetSyncTimeout(), command_view.GetSyncCteType()); |
| send_event_( |
| bluetooth::hci::LePeriodicAdvertisingCreateSyncStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LePeriodicAdvertisingCreateSyncCancel( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LePeriodicAdvertisingCreateSyncCancelView::Create( |
| command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = |
| link_layer_controller_.LePeriodicAdvertisingCreateSyncCancel(); |
| send_event_( |
| bluetooth::hci::LePeriodicAdvertisingCreateSyncCancelCompleteBuilder:: |
| Create(kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LePeriodicAdvertisingTerminateSync( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LePeriodicAdvertisingTerminateSyncView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LePeriodicAdvertisingTerminateSync( |
| command_view.GetSyncHandle()); |
| send_event_( |
| bluetooth::hci::LePeriodicAdvertisingTerminateSyncCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeAddDeviceToPeriodicAdvertiserList( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeAddDeviceToPeriodicAdvertiserListView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeAddDeviceToPeriodicAdvertiserList( |
| command_view.GetAdvertiserAddressType(), |
| command_view.GetAdvertiserAddress(), command_view.GetAdvertisingSid()); |
| send_event_( |
| bluetooth::hci::LeAddDeviceToPeriodicAdvertiserListCompleteBuilder:: |
| Create(kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeRemoveDeviceFromPeriodicAdvertiserList( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeRemoveDeviceFromPeriodicAdvertiserListView::Create( |
| command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = |
| link_layer_controller_.LeRemoveDeviceFromPeriodicAdvertiserList( |
| command_view.GetAdvertiserAddressType(), |
| command_view.GetAdvertiserAddress(), |
| command_view.GetAdvertisingSid()); |
| send_event_( |
| bluetooth::hci::LeRemoveDeviceFromPeriodicAdvertiserListCompleteBuilder:: |
| Create(kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeClearPeriodicAdvertiserList(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeClearPeriodicAdvertiserListView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeClearPeriodicAdvertiserList(); |
| send_event_( |
| bluetooth::hci::LeClearPeriodicAdvertiserListCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeReadPeriodicAdvertiserListSize(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadPeriodicAdvertiserListSizeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_( |
| bluetooth::hci::LeReadPeriodicAdvertiserListSizeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| properties_.le_periodic_advertiser_list_size)); |
| } |
| |
| void DualModeController::LeSetExtendedScanParameters(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetExtendedScanParametersView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetExtendedScanParameters( |
| command_view.GetOwnAddressType(), command_view.GetScanningFilterPolicy(), |
| command_view.GetScanningPhys(), command_view.GetParameters()); |
| send_event_( |
| bluetooth::hci::LeSetExtendedScanParametersCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetExtendedScanEnable(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetExtendedScanEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetExtendedScanEnable( |
| command_view.GetEnable() == bluetooth::hci::Enable::ENABLED, |
| command_view.GetFilterDuplicates(), command_view.GetDuration(), |
| command_view.GetPeriod()); |
| send_event_(bluetooth::hci::LeSetExtendedScanEnableCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeExtendedCreateConnection(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeExtendedCreateConnectionView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeExtendedCreateConnection( |
| command_view.GetInitiatorFilterPolicy(), command_view.GetOwnAddressType(), |
| AddressWithType{ |
| command_view.GetPeerAddress(), |
| command_view.GetPeerAddressType(), |
| }, |
| command_view.GetInitiatingPhys(), command_view.GetPhyScanParameters()); |
| send_event_(bluetooth::hci::LeExtendedCreateConnectionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeSetPrivacyMode(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetPrivacyModeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetPrivacyMode( |
| command_view.GetPeerIdentityAddressType(), |
| command_view.GetPeerIdentityAddress(), command_view.GetPrivacyMode()); |
| send_event_(bluetooth::hci::LeSetPrivacyModeCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeReadIsoTxSync(CommandView command) { |
| auto command_view = bluetooth::hci::LeReadIsoTxSyncView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.LeReadIsoTxSync(command_view.GetConnectionHandle()); |
| } |
| |
| void DualModeController::LeSetCigParameters(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetCigParametersView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.LeSetCigParameters( |
| command_view.GetCigId(), command_view.GetSduIntervalMToS(), |
| command_view.GetSduIntervalSToM(), |
| command_view.GetPeripheralsClockAccuracy(), command_view.GetPacking(), |
| command_view.GetFraming(), command_view.GetMaxTransportLatencyMToS(), |
| command_view.GetMaxTransportLatencySToM(), command_view.GetCisConfig()); |
| } |
| |
| void DualModeController::LeCreateCis(CommandView command) { |
| auto command_view = bluetooth::hci::LeCreateCisView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = |
| link_layer_controller_.LeCreateCis(command_view.GetCisConfig()); |
| send_event_(bluetooth::hci::LeCreateCisStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeRemoveCig(CommandView command) { |
| auto command_view = bluetooth::hci::LeRemoveCigView::Create(command); |
| ASSERT(command_view.IsValid()); |
| uint8_t cig = command_view.GetCigId(); |
| ErrorCode status = link_layer_controller_.LeRemoveCig(cig); |
| send_event_(bluetooth::hci::LeRemoveCigCompleteBuilder::Create( |
| kNumCommandPackets, status, cig)); |
| } |
| |
| void DualModeController::LeAcceptCisRequest(CommandView command) { |
| auto command_view = bluetooth::hci::LeAcceptCisRequestView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeAcceptCisRequest( |
| command_view.GetConnectionHandle()); |
| send_event_(bluetooth::hci::LeAcceptCisRequestStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeRejectCisRequest(CommandView command) { |
| auto command_view = bluetooth::hci::LeRejectCisRequestView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.LeRejectCisRequest(command_view.GetConnectionHandle(), |
| command_view.GetReason()); |
| } |
| |
| void DualModeController::LeCreateBig(CommandView command) { |
| auto command_view = bluetooth::hci::LeCreateBigView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeCreateBig( |
| command_view.GetBigHandle(), command_view.GetAdvertisingHandle(), |
| command_view.GetNumBis(), command_view.GetSduInterval(), |
| command_view.GetMaxSdu(), command_view.GetMaxTransportLatency(), |
| command_view.GetRtn(), command_view.GetPhy(), command_view.GetPacking(), |
| command_view.GetFraming(), command_view.GetEncryption(), |
| command_view.GetBroadcastCode()); |
| send_event_(bluetooth::hci::LeCreateBigStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeTerminateBig(CommandView command) { |
| auto command_view = bluetooth::hci::LeTerminateBigView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeTerminateBig( |
| command_view.GetBigHandle(), command_view.GetReason()); |
| send_event_(bluetooth::hci::LeTerminateBigStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeBigCreateSync(CommandView command) { |
| auto command_view = bluetooth::hci::LeBigCreateSyncView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeBigCreateSync( |
| command_view.GetBigHandle(), command_view.GetSyncHandle(), |
| command_view.GetEncryption(), command_view.GetBroadcastCode(), |
| command_view.GetMse(), command_view.GetBigSyncTimeout(), |
| command_view.GetBis()); |
| send_event_(bluetooth::hci::LeBigCreateSyncStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeBigTerminateSync(CommandView command) { |
| auto command_view = bluetooth::hci::LeBigTerminateSyncView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.LeBigTerminateSync(command_view.GetBigHandle()); |
| } |
| |
| void DualModeController::LeRequestPeerSca(CommandView command) { |
| auto command_view = bluetooth::hci::LeRequestPeerScaView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeRequestPeerSca( |
| command_view.GetConnectionHandle()); |
| send_event_(bluetooth::hci::LeRequestPeerScaStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeSetupIsoDataPath(CommandView command) { |
| auto command_view = bluetooth::hci::LeSetupIsoDataPathView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.LeSetupIsoDataPath( |
| command_view.GetConnectionHandle(), command_view.GetDataPathDirection(), |
| command_view.GetDataPathId(), command_view.GetCodecId(), |
| command_view.GetControllerDelay(), command_view.GetCodecConfiguration()); |
| } |
| |
| void DualModeController::LeRemoveIsoDataPath(CommandView command) { |
| auto command_view = bluetooth::hci::LeRemoveIsoDataPathView::Create(command); |
| ASSERT(command_view.IsValid()); |
| link_layer_controller_.LeRemoveIsoDataPath( |
| command_view.GetConnectionHandle(), |
| command_view.GetRemoveDataPathDirection()); |
| } |
| |
| void DualModeController::LeReadRemoteFeatures(CommandView command) { |
| auto command_view = bluetooth::hci::LeReadRemoteFeaturesView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t handle = command_view.GetConnectionHandle(); |
| |
| auto status = link_layer_controller_.SendCommandToRemoteByHandle( |
| OpCode::LE_READ_REMOTE_FEATURES, command_view.GetPayload(), handle); |
| |
| send_event_(bluetooth::hci::LeReadRemoteFeaturesStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeEncrypt(CommandView command) { |
| auto command_view = bluetooth::hci::LeEncryptView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| auto encrypted_data = rootcanal::crypto::aes_128( |
| command_view.GetKey(), command_view.GetPlaintextData()); |
| |
| send_event_(bluetooth::hci::LeEncryptCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, encrypted_data)); |
| } |
| |
| static std::random_device rd{}; |
| static std::mt19937_64 s_mt{rd()}; |
| |
| void DualModeController::LeRand(CommandView command) { |
| auto command_view = bluetooth::hci::LeRandView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint64_t random_val = s_mt(); |
| |
| send_event_(bluetooth::hci::LeRandCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, random_val)); |
| } |
| |
| void DualModeController::LeReadSupportedStates(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadSupportedStatesView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::LeReadSupportedStatesCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, properties_.le_supported_states)); |
| } |
| |
| void DualModeController::LeRemoteConnectionParameterRequestReply( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeRemoteConnectionParameterRequestReplyView::Create( |
| command); |
| ASSERT(command_view.IsValid()); |
| auto status = link_layer_controller_.LeRemoteConnectionParameterRequestReply( |
| command_view.GetConnectionHandle(), command_view.GetIntervalMin(), |
| command_view.GetIntervalMax(), command_view.GetTimeout(), |
| command_view.GetLatency(), command_view.GetMinimumCeLength(), |
| command_view.GetMaximumCeLength()); |
| send_event_( |
| bluetooth::hci::LeRemoteConnectionParameterRequestReplyCompleteBuilder:: |
| Create(kNumCommandPackets, status, |
| command_view.GetConnectionHandle())); |
| } |
| |
| void DualModeController::LeRemoteConnectionParameterRequestNegativeReply( |
| CommandView command) { |
| auto command_view = bluetooth::hci:: |
| LeRemoteConnectionParameterRequestNegativeReplyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| auto status = |
| link_layer_controller_.LeRemoteConnectionParameterRequestNegativeReply( |
| command_view.GetConnectionHandle(), command_view.GetReason()); |
| send_event_( |
| bluetooth::hci:: |
| LeRemoteConnectionParameterRequestNegativeReplyCompleteBuilder:: |
| Create(kNumCommandPackets, status, |
| command_view.GetConnectionHandle())); |
| } |
| |
| void DualModeController::LeGetVendorCapabilities(CommandView command) { |
| auto command_view = bluetooth::hci::LeGetVendorCapabilitiesView::Create( |
| bluetooth::hci::VendorCommandView::Create(command)); |
| ASSERT(command_view.IsValid()); |
| |
| if (!properties_.supports_le_get_vendor_capabilities_command) { |
| SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_GET_VENDOR_CAPABILITIES); |
| return; |
| } |
| |
| // Ensure a minimal size for vendor capabilities. |
| vector<uint8_t> vendor_capabilities = properties_.le_vendor_capabilities; |
| if (vendor_capabilities.size() < 8) { |
| vendor_capabilities.resize(8); |
| } |
| |
| std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr = |
| std::make_unique<bluetooth::packet::RawBuilder>(); |
| raw_builder_ptr->AddOctets1(static_cast<uint8_t>(ErrorCode::SUCCESS)); |
| raw_builder_ptr->AddOctets(vendor_capabilities); |
| |
| send_event_(bluetooth::hci::CommandCompleteBuilder::Create( |
| kNumCommandPackets, OpCode::LE_GET_VENDOR_CAPABILITIES, |
| std::move(raw_builder_ptr))); |
| } |
| |
| void DualModeController::LeMultiAdv(CommandView command) { |
| auto command_view = bluetooth::hci::LeMultiAdvtView::Create(command); |
| ASSERT(command_view.IsValid()); |
| SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_MULTI_ADVT); |
| } |
| |
| void DualModeController::LeAdvertisingFilter(CommandView command) { |
| auto command_view = bluetooth::hci::LeAdvFilterView::Create(command); |
| ASSERT(command_view.IsValid()); |
| SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_ADV_FILTER); |
| } |
| |
| void DualModeController::LeEnergyInfo(CommandView command) { |
| auto command_view = bluetooth::hci::LeEnergyInfoView::Create( |
| bluetooth::hci::VendorCommandView::Create(command)); |
| ASSERT(command_view.IsValid()); |
| SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_ENERGY_INFO); |
| } |
| |
| // CSR vendor command. |
| // Implement the command specific to the CSR controller |
| // used specifically by the PTS tool to pass certification tests. |
| void DualModeController::CsrVendorCommand(CommandView command) { |
| // The byte order is little endian. |
| // The command parameters are formatted as |
| // |
| // 00 | 0xc2 |
| // 01 02 | action |
| // read = 0 |
| // write = 2 |
| // 03 04 | (value length / 2) + 5 |
| // 04 05 | sequence number |
| // 06 07 | varid |
| // 08 09 | 00 00 |
| // 0a .. | value |
| // |
| // BlueZ has a reference implementation of the CSR vendor command. |
| |
| std::vector<uint8_t> parameters(command.GetPayload().begin(), |
| command.GetPayload().end()); |
| |
| uint16_t type = 0; |
| uint16_t length = 0; |
| uint16_t varid = 0; |
| |
| if (parameters.empty()) { |
| LOG_INFO("Empty CSR vendor command"); |
| goto complete; |
| } |
| |
| if (parameters[0] != 0xc2 || parameters.size() < 11) { |
| LOG_INFO( |
| "Unsupported CSR vendor command with code %02x " |
| "and parameter length %zu", |
| static_cast<int>(parameters[0]), parameters.size()); |
| goto complete; |
| } |
| |
| type = (uint16_t)parameters[1] | ((uint16_t)parameters[2] << 8); |
| length = (uint16_t)parameters[3] | ((uint16_t)parameters[4] << 8); |
| varid = (uint16_t)parameters[7] | ((uint16_t)parameters[8] << 8); |
| length = 2 * (length - 5); |
| |
| if (parameters.size() < (11 + length) || |
| (varid == CsrVarid::CSR_VARID_PS && length < 6)) { |
| LOG_INFO("Invalid CSR vendor command parameter length %zu, expected %u", |
| parameters.size(), 11 + length); |
| goto complete; |
| } |
| |
| if (varid == CsrVarid::CSR_VARID_PS) { |
| // Subcommand to read or write PSKEY of the selected identifier |
| // instead of VARID. |
| uint16_t pskey = (uint16_t)parameters[11] | ((uint16_t)parameters[12] << 8); |
| uint16_t length = |
| (uint16_t)parameters[13] | ((uint16_t)parameters[14] << 8); |
| length = 2 * length; |
| |
| if (parameters.size() < (17 + length)) { |
| LOG_INFO("Invalid CSR vendor command parameter length %zu, expected %u", |
| parameters.size(), 17 + length); |
| goto complete; |
| } |
| |
| std::vector<uint8_t> value(parameters.begin() + 17, |
| parameters.begin() + 17 + length); |
| |
| LOG_INFO("CSR vendor command type=%04x length=%04x pskey=%04x", type, |
| length, pskey); |
| |
| if (type == 0) { |
| CsrReadPskey(static_cast<CsrPskey>(pskey), value); |
| std::copy(value.begin(), value.end(), parameters.begin() + 17); |
| } else { |
| CsrWritePskey(static_cast<CsrPskey>(pskey), value); |
| } |
| |
| } else { |
| // Subcommand to read or write VARID of the selected identifier. |
| std::vector<uint8_t> value(parameters.begin() + 11, |
| parameters.begin() + 11 + length); |
| |
| LOG_INFO("CSR vendor command type=%04x length=%04x varid=%04x", type, |
| length, varid); |
| |
| if (type == 0) { |
| CsrReadVarid(static_cast<CsrVarid>(varid), value); |
| std::copy(value.begin(), value.end(), parameters.begin() + 11); |
| } else { |
| CsrWriteVarid(static_cast<CsrVarid>(varid), value); |
| } |
| } |
| |
| complete: |
| // Overwrite the command type. |
| parameters[1] = 0x1; |
| parameters[2] = 0x0; |
| send_event_(bluetooth::hci::EventBuilder::Create( |
| bluetooth::hci::EventCode::VENDOR_SPECIFIC, |
| std::make_unique<bluetooth::packet::RawBuilder>(std::move(parameters)))); |
| } |
| |
| // NOLINTNEXTLINE(readability-convert-member-functions-to-static) |
| void DualModeController::CsrReadVarid(CsrVarid varid, |
| std::vector<uint8_t>& value) { |
| switch (varid) { |
| case CsrVarid::CSR_VARID_BUILDID: |
| // Return the extact Build ID returned by the official PTS dongle. |
| ASSERT(value.size() >= 2); |
| value[0] = 0xe8; |
| value[1] = 0x30; |
| break; |
| |
| default: |
| LOG_INFO("Unsupported read of CSR varid 0x%04x", varid); |
| break; |
| } |
| } |
| |
| // NOLINTNEXTLINE(readability-convert-member-functions-to-static) |
| void DualModeController::CsrWriteVarid(CsrVarid varid, |
| std::vector<uint8_t> const& value) { |
| LOG_INFO("Unsupported write of CSR varid 0x%04x", varid); |
| } |
| |
| // NOLINTNEXTLINE(readability-convert-member-functions-to-static) |
| void DualModeController::CsrReadPskey(CsrPskey pskey, |
| std::vector<uint8_t>& value) { |
| switch (pskey) { |
| case CsrPskey::CSR_PSKEY_ENC_KEY_LMIN: |
| ASSERT(!value.empty()); |
| value[0] = 7; |
| break; |
| |
| case CsrPskey::CSR_PSKEY_ENC_KEY_LMAX: |
| ASSERT(!value.empty()); |
| value[0] = 16; |
| break; |
| |
| case CSR_PSKEY_HCI_LMP_LOCAL_VERSION: |
| // Return the extact version returned by the official PTS dongle. |
| ASSERT(value.size() >= 2); |
| value[0] = 0x08; |
| value[1] = 0x08; |
| break; |
| |
| default: |
| LOG_INFO("Unsupported read of CSR pskey 0x%04x", pskey); |
| break; |
| } |
| } |
| |
| void DualModeController::CsrWritePskey(CsrPskey pskey, |
| std::vector<uint8_t> const& value) { |
| switch (pskey) { |
| case CsrPskey::CSR_PSKEY_LOCAL_SUPPORTED_FEATURES: |
| ASSERT(value.size() >= 8); |
| LOG_INFO("CSR Vendor updating the Local Supported Features"); |
| properties_.lmp_features[0] = |
| ((uint64_t)value[0] << 0) | ((uint64_t)value[1] << 8) | |
| ((uint64_t)value[2] << 16) | ((uint64_t)value[3] << 24) | |
| ((uint64_t)value[4] << 32) | ((uint64_t)value[5] << 40) | |
| ((uint64_t)value[6] << 48) | ((uint64_t)value[7] << 56); |
| break; |
| |
| default: |
| LOG_INFO("Unsupported write of CSR pskey 0x%04x", pskey); |
| break; |
| } |
| } |
| |
| void DualModeController::LeSetAdvertisingSetRandomAddress(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetAdvertisingSetRandomAddressView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetAdvertisingSetRandomAddress( |
| command_view.GetAdvertisingHandle(), command_view.GetRandomAddress()); |
| send_event_( |
| bluetooth::hci::LeSetAdvertisingSetRandomAddressCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetExtendedAdvertisingParameters( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetExtendedAdvertisingParametersView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetExtendedAdvertisingParameters( |
| command_view.GetAdvertisingHandle(), |
| command_view.GetAdvertisingEventProperties(), |
| command_view.GetPrimaryAdvertisingIntervalMin(), |
| command_view.GetPrimaryAdvertisingIntervalMax(), |
| command_view.GetPrimaryAdvertisingChannelMap(), |
| command_view.GetOwnAddressType(), command_view.GetPeerAddressType(), |
| command_view.GetPeerAddress(), command_view.GetAdvertisingFilterPolicy(), |
| command_view.GetAdvertisingTxPower(), |
| command_view.GetPrimaryAdvertisingPhy(), |
| command_view.GetSecondaryAdvertisingMaxSkip(), |
| command_view.GetSecondaryAdvertisingPhy(), |
| command_view.GetAdvertisingSid(), |
| command_view.GetScanRequestNotificationEnable() == Enable::ENABLED); |
| // The selected TX power is always the requested TX power |
| // at the moment. |
| send_event_( |
| bluetooth::hci::LeSetExtendedAdvertisingParametersCompleteBuilder::Create( |
| kNumCommandPackets, status, command_view.GetAdvertisingTxPower())); |
| } |
| |
| void DualModeController::LeSetExtendedAdvertisingData(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetExtendedAdvertisingDataView::Create(command); |
| ASSERT(command_view.IsValid()); |
| auto raw_command_view = |
| bluetooth::hci::LeSetExtendedAdvertisingDataView::Create(command); |
| ASSERT(raw_command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetExtendedAdvertisingData( |
| command_view.GetAdvertisingHandle(), command_view.GetOperation(), |
| command_view.GetFragmentPreference(), |
| raw_command_view.GetAdvertisingData()); |
| send_event_( |
| bluetooth::hci::LeSetExtendedAdvertisingDataCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetExtendedScanResponseData(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetExtendedScanResponseDataView::Create(command); |
| ASSERT(command_view.IsValid()); |
| auto raw_command_view = |
| bluetooth::hci::LeSetExtendedScanResponseDataView::Create(command); |
| ASSERT(raw_command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetExtendedScanResponseData( |
| command_view.GetAdvertisingHandle(), command_view.GetOperation(), |
| command_view.GetFragmentPreference(), |
| raw_command_view.GetScanResponseData()); |
| send_event_( |
| bluetooth::hci::LeSetExtendedScanResponseDataCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeSetExtendedAdvertisingEnable(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeSetExtendedAdvertisingEnableView::Create(command); |
| ASSERT(command_view.IsValid()); |
| ErrorCode status = link_layer_controller_.LeSetExtendedAdvertisingEnable( |
| command_view.GetEnable() == bluetooth::hci::Enable::ENABLED, |
| command_view.GetEnabledSets()); |
| send_event_( |
| bluetooth::hci::LeSetExtendedAdvertisingEnableCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeReadMaximumAdvertisingDataLength( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadMaximumAdvertisingDataLengthView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_( |
| bluetooth::hci::LeReadMaximumAdvertisingDataLengthCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| properties_.le_max_advertising_data_length)); |
| } |
| |
| void DualModeController::LeReadNumberOfSupportedAdvertisingSets( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeReadNumberOfSupportedAdvertisingSetsView::Create( |
| command); |
| ASSERT(command_view.IsValid()); |
| send_event_( |
| bluetooth::hci::LeReadNumberOfSupportedAdvertisingSetsCompleteBuilder:: |
| Create(kNumCommandPackets, ErrorCode::SUCCESS, |
| properties_.le_num_supported_advertising_sets)); |
| } |
| |
| void DualModeController::LeRemoveAdvertisingSet(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeRemoveAdvertisingSetView::Create(command); |
| ASSERT(command_view.IsValid()); |
| auto status = link_layer_controller_.LeRemoveAdvertisingSet( |
| command_view.GetAdvertisingHandle()); |
| send_event_(bluetooth::hci::LeRemoveAdvertisingSetCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeClearAdvertisingSets(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeClearAdvertisingSetsView::Create(command); |
| ASSERT(command_view.IsValid()); |
| auto status = link_layer_controller_.LeClearAdvertisingSets(); |
| send_event_(bluetooth::hci::LeClearAdvertisingSetsCompleteBuilder::Create( |
| kNumCommandPackets, status)); |
| } |
| |
| void DualModeController::LeExtendedScanParams(CommandView command) { |
| auto command_view = bluetooth::hci::LeExtendedScanParamsView::Create(command); |
| ASSERT(command_view.IsValid()); |
| SendCommandCompleteUnknownOpCodeEvent(OpCode::LE_EXTENDED_SCAN_PARAMS); |
| } |
| |
| void DualModeController::LeStartEncryption(CommandView command) { |
| auto command_view = bluetooth::hci::LeStartEncryptionView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| ErrorCode status = link_layer_controller_.LeEnableEncryption( |
| command_view.GetConnectionHandle(), command_view.GetRand(), |
| command_view.GetEdiv(), command_view.GetLtk()); |
| |
| send_event_(bluetooth::hci::LeStartEncryptionStatusBuilder::Create( |
| status, kNumCommandPackets)); |
| } |
| |
| void DualModeController::LeLongTermKeyRequestReply(CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeLongTermKeyRequestReplyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t handle = command_view.GetConnectionHandle(); |
| ErrorCode status = link_layer_controller_.LeLongTermKeyRequestReply( |
| handle, command_view.GetLongTermKey()); |
| |
| send_event_(bluetooth::hci::LeLongTermKeyRequestReplyCompleteBuilder::Create( |
| kNumCommandPackets, status, handle)); |
| } |
| |
| void DualModeController::LeLongTermKeyRequestNegativeReply( |
| CommandView command) { |
| auto command_view = |
| bluetooth::hci::LeLongTermKeyRequestNegativeReplyView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| uint16_t handle = command_view.GetConnectionHandle(); |
| ErrorCode status = |
| link_layer_controller_.LeLongTermKeyRequestNegativeReply(handle); |
| |
| send_event_( |
| bluetooth::hci::LeLongTermKeyRequestNegativeReplyCompleteBuilder::Create( |
| kNumCommandPackets, status, handle)); |
| } |
| |
| void DualModeController::ReadClassOfDevice(CommandView command) { |
| auto command_view = bluetooth::hci::ReadClassOfDeviceView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| send_event_(bluetooth::hci::ReadClassOfDeviceCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| link_layer_controller_.GetClassOfDevice())); |
| } |
| |
| void DualModeController::ReadVoiceSetting(CommandView command) { |
| auto command_view = bluetooth::hci::ReadVoiceSettingView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| send_event_(bluetooth::hci::ReadVoiceSettingCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| link_layer_controller_.GetVoiceSetting())); |
| } |
| |
| void DualModeController::ReadConnectionAcceptTimeout(CommandView command) { |
| auto command_view = |
| bluetooth::hci::ReadConnectionAcceptTimeoutView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| send_event_( |
| bluetooth::hci::ReadConnectionAcceptTimeoutCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, |
| link_layer_controller_.GetConnectionAcceptTimeout())); |
| } |
| |
| void DualModeController::WriteConnectionAcceptTimeout(CommandView command) { |
| auto command_view = |
| bluetooth::hci::WriteConnectionAcceptTimeoutView::Create(command); |
| ASSERT(command_view.IsValid()); |
| |
| link_layer_controller_.SetConnectionAcceptTimeout( |
| command_view.GetConnAcceptTimeout()); |
| |
| send_event_( |
| bluetooth::hci::WriteConnectionAcceptTimeoutCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| void DualModeController::ReadLoopbackMode(CommandView command) { |
| auto command_view = bluetooth::hci::ReadLoopbackModeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| send_event_(bluetooth::hci::ReadLoopbackModeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS, loopback_mode_)); |
| } |
| |
| void DualModeController::WriteLoopbackMode(CommandView command) { |
| auto command_view = bluetooth::hci::WriteLoopbackModeView::Create(command); |
| ASSERT(command_view.IsValid()); |
| loopback_mode_ = command_view.GetLoopbackMode(); |
| // ACL channel |
| uint16_t acl_handle = 0x123; |
| send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( |
| ErrorCode::SUCCESS, acl_handle, GetAddress(), |
| bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED)); |
| // SCO channel |
| uint16_t sco_handle = 0x345; |
| send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create( |
| ErrorCode::SUCCESS, sco_handle, GetAddress(), |
| bluetooth::hci::LinkType::SCO, bluetooth::hci::Enable::DISABLED)); |
| send_event_(bluetooth::hci::WriteLoopbackModeCompleteBuilder::Create( |
| kNumCommandPackets, ErrorCode::SUCCESS)); |
| } |
| |
| // Note: the list does not contain all defined opcodes. |
| // Notable exceptions: |
| // - Vendor commands |
| // - Read Local Supported Commands command |
| const std::unordered_map<OpCode, OpCodeIndex> |
| DualModeController::hci_command_op_code_to_index_{ |
| // LINK_CONTROL |
| {OpCode::INQUIRY, OpCodeIndex::INQUIRY}, |
| {OpCode::INQUIRY_CANCEL, OpCodeIndex::INQUIRY_CANCEL}, |
| {OpCode::PERIODIC_INQUIRY_MODE, OpCodeIndex::PERIODIC_INQUIRY_MODE}, |
| {OpCode::EXIT_PERIODIC_INQUIRY_MODE, |
| OpCodeIndex::EXIT_PERIODIC_INQUIRY_MODE}, |
| {OpCode::CREATE_CONNECTION, OpCodeIndex::CREATE_CONNECTION}, |
| {OpCode::DISCONNECT, OpCodeIndex::DISCONNECT}, |
| {OpCode::ADD_SCO_CONNECTION, OpCodeIndex::ADD_SCO_CONNECTION}, |
| {OpCode::CREATE_CONNECTION_CANCEL, |
| OpCodeIndex::CREATE_CONNECTION_CANCEL}, |
| {OpCode::ACCEPT_CONNECTION_REQUEST, |
| OpCodeIndex::ACCEPT_CONNECTION_REQUEST}, |
| {OpCode::REJECT_CONNECTION_REQUEST, |
| OpCodeIndex::REJECT_CONNECTION_REQUEST}, |
| {OpCode::LINK_KEY_REQUEST_REPLY, OpCodeIndex::LINK_KEY_REQUEST_REPLY}, |
| {OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, |
| OpCodeIndex::LINK_KEY_REQUEST_NEGATIVE_REPLY}, |
| {OpCode::PIN_CODE_REQUEST_REPLY, OpCodeIndex::PIN_CODE_REQUEST_REPLY}, |
| {OpCode::PIN_CODE_REQUEST_NEGATIVE_REPLY, |
| OpCodeIndex::PIN_CODE_REQUEST_NEGATIVE_REPLY}, |
| {OpCode::CHANGE_CONNECTION_PACKET_TYPE, |
| OpCodeIndex::CHANGE_CONNECTION_PACKET_TYPE}, |
| {OpCode::AUTHENTICATION_REQUESTED, |
| OpCodeIndex::AUTHENTICATION_REQUESTED}, |
| {OpCode::SET_CONNECTION_ENCRYPTION, |
| OpCodeIndex::SET_CONNECTION_ENCRYPTION}, |
| {OpCode::CHANGE_CONNECTION_LINK_KEY, |
| OpCodeIndex::CHANGE_CONNECTION_LINK_KEY}, |
| {OpCode::CENTRAL_LINK_KEY, OpCodeIndex::CENTRAL_LINK_KEY}, |
| {OpCode::REMOTE_NAME_REQUEST, OpCodeIndex::REMOTE_NAME_REQUEST}, |
| {OpCode::REMOTE_NAME_REQUEST_CANCEL, |
| OpCodeIndex::REMOTE_NAME_REQUEST_CANCEL}, |
| {OpCode::READ_REMOTE_SUPPORTED_FEATURES, |
| OpCodeIndex::READ_REMOTE_SUPPORTED_FEATURES}, |
| {OpCode::READ_REMOTE_EXTENDED_FEATURES, |
| OpCodeIndex::READ_REMOTE_EXTENDED_FEATURES}, |
| {OpCode::READ_REMOTE_VERSION_INFORMATION, |
| OpCodeIndex::READ_REMOTE_VERSION_INFORMATION}, |
| {OpCode::READ_CLOCK_OFFSET, OpCodeIndex::READ_CLOCK_OFFSET}, |
| {OpCode::READ_LMP_HANDLE, OpCodeIndex::READ_LMP_HANDLE}, |
| {OpCode::SETUP_SYNCHRONOUS_CONNECTION, |
| OpCodeIndex::SETUP_SYNCHRONOUS_CONNECTION}, |
| {OpCode::ACCEPT_SYNCHRONOUS_CONNECTION, |
| OpCodeIndex::ACCEPT_SYNCHRONOUS_CONNECTION}, |
| {OpCode::REJECT_SYNCHRONOUS_CONNECTION, |
| OpCodeIndex::REJECT_SYNCHRONOUS_CONNECTION}, |
| {OpCode::IO_CAPABILITY_REQUEST_REPLY, |
| OpCodeIndex::IO_CAPABILITY_REQUEST_REPLY}, |
| {OpCode::USER_CONFIRMATION_REQUEST_REPLY, |
| OpCodeIndex::USER_CONFIRMATION_REQUEST_REPLY}, |
| {OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, |
| OpCodeIndex::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY}, |
| {OpCode::USER_PASSKEY_REQUEST_REPLY, |
| OpCodeIndex::USER_PASSKEY_REQUEST_REPLY}, |
| {OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY, |
| OpCodeIndex::USER_PASSKEY_REQUEST_NEGATIVE_REPLY}, |
| {OpCode::REMOTE_OOB_DATA_REQUEST_REPLY, |
| OpCodeIndex::REMOTE_OOB_DATA_REQUEST_REPLY}, |
| {OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, |
| OpCodeIndex::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY}, |
| {OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, |
| OpCodeIndex::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY}, |
| {OpCode::ENHANCED_SETUP_SYNCHRONOUS_CONNECTION, |
| OpCodeIndex::ENHANCED_SETUP_SYNCHRONOUS_CONNECTION}, |
| {OpCode::ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION, |
| OpCodeIndex::ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION}, |
| {OpCode::TRUNCATED_PAGE, OpCodeIndex::TRUNCATED_PAGE}, |
| {OpCode::TRUNCATED_PAGE_CANCEL, OpCodeIndex::TRUNCATED_PAGE_CANCEL}, |
| {OpCode::SET_CONNECTIONLESS_PERIPHERAL_BROADCAST, |
| OpCodeIndex::SET_CONNECTIONLESS_PERIPHERAL_BROADCAST}, |
| {OpCode::SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE, |
| OpCodeIndex::SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE}, |
| {OpCode::START_SYNCHRONIZATION_TRAIN, |
| OpCodeIndex::START_SYNCHRONIZATION_TRAIN}, |
| {OpCode::RECEIVE_SYNCHRONIZATION_TRAIN, |
| OpCodeIndex::RECEIVE_SYNCHRONIZATION_TRAIN}, |
| {OpCode::REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY, |
| OpCodeIndex::REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY}, |
| |
| // LINK_POLICY |
| {OpCode::HOLD_MODE, OpCodeIndex::HOLD_MODE}, |
| {OpCode::SNIFF_MODE, OpCodeIndex::SNIFF_MODE}, |
| {OpCode::EXIT_SNIFF_MODE, OpCodeIndex::EXIT_SNIFF_MODE}, |
| {OpCode::QOS_SETUP, OpCodeIndex::QOS_SETUP}, |
| {OpCode::ROLE_DISCOVERY, OpCodeIndex::ROLE_DISCOVERY}, |
| {OpCode::SWITCH_ROLE, OpCodeIndex::SWITCH_ROLE}, |
| {OpCode::READ_LINK_POLICY_SETTINGS, |
| OpCodeIndex::READ_LINK_POLICY_SETTINGS}, |
| {OpCode::WRITE_LINK_POLICY_SETTINGS, |
| OpCodeIndex::WRITE_LINK_POLICY_SETTINGS}, |
| {OpCode::READ_DEFAULT_LINK_POLICY_SETTINGS, |
| OpCodeIndex::READ_DEFAULT_LINK_POLICY_SETTINGS}, |
| {OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS, |
| OpCodeIndex::WRITE_DEFAULT_LINK_POLICY_SETTINGS}, |
| {OpCode::FLOW_SPECIFICATION, OpCodeIndex::FLOW_SPECIFICATION}, |
| {OpCode::SNIFF_SUBRATING, OpCodeIndex::SNIFF_SUBRATING}, |
| |
| // CONTROLLER_AND_BASEBAND |
| {OpCode::SET_EVENT_MASK, OpCodeIndex::SET_EVENT_MASK}, |
| {OpCode::RESET, OpCodeIndex::RESET}, |
| {OpCode::SET_EVENT_FILTER, OpCodeIndex::SET_EVENT_FILTER}, |
| {OpCode::FLUSH, OpCodeIndex::FLUSH}, |
| {OpCode::READ_PIN_TYPE, OpCodeIndex::READ_PIN_TYPE}, |
| {OpCode::WRITE_PIN_TYPE, OpCodeIndex::WRITE_PIN_TYPE}, |
| {OpCode::READ_STORED_LINK_KEY, OpCodeIndex::READ_STORED_LINK_KEY}, |
| {OpCode::WRITE_STORED_LINK_KEY, OpCodeIndex::WRITE_STORED_LINK_KEY}, |
| {OpCode::DELETE_STORED_LINK_KEY, OpCodeIndex::DELETE_STORED_LINK_KEY}, |
| {OpCode::WRITE_LOCAL_NAME, OpCodeIndex::WRITE_LOCAL_NAME}, |
| {OpCode::READ_LOCAL_NAME, OpCodeIndex::READ_LOCAL_NAME}, |
| {OpCode::READ_CONNECTION_ACCEPT_TIMEOUT, |
| OpCodeIndex::READ_CONNECTION_ACCEPT_TIMEOUT}, |
| {OpCode::WRITE_CONNECTION_ACCEPT_TIMEOUT, |
| OpCodeIndex::WRITE_CONNECTION_ACCEPT_TIMEOUT}, |
| {OpCode::READ_PAGE_TIMEOUT, OpCodeIndex::READ_PAGE_TIMEOUT}, |
| {OpCode::WRITE_PAGE_TIMEOUT, OpCodeIndex::WRITE_PAGE_TIMEOUT}, |
| {OpCode::READ_SCAN_ENABLE, OpCodeIndex::READ_SCAN_ENABLE}, |
| {OpCode::WRITE_SCAN_ENABLE, OpCodeIndex::WRITE_SCAN_ENABLE}, |
| {OpCode::READ_PAGE_SCAN_ACTIVITY, OpCodeIndex::READ_PAGE_SCAN_ACTIVITY}, |
| {OpCode::WRITE_PAGE_SCAN_ACTIVITY, |
| OpCodeIndex::WRITE_PAGE_SCAN_ACTIVITY}, |
| {OpCode::READ_INQUIRY_SCAN_ACTIVITY, |
| OpCodeIndex::READ_INQUIRY_SCAN_ACTIVITY}, |
| {OpCode::WRITE_INQUIRY_SCAN_ACTIVITY, |
| OpCodeIndex::WRITE_INQUIRY_SCAN_ACTIVITY}, |
| {OpCode::READ_AUTHENTICATION_ENABLE, |
| OpCodeIndex::READ_AUTHENTICATION_ENABLE}, |
| {OpCode::WRITE_AUTHENTICATION_ENABLE, |
| OpCodeIndex::WRITE_AUTHENTICATION_ENABLE}, |
| {OpCode::READ_CLASS_OF_DEVICE, OpCodeIndex::READ_CLASS_OF_DEVICE}, |
| {OpCode::WRITE_CLASS_OF_DEVICE, OpCodeIndex::WRITE_CLASS_OF_DEVICE}, |
| {OpCode::READ_VOICE_SETTING, OpCodeIndex::READ_VOICE_SETTING}, |
| {OpCode::WRITE_VOICE_SETTING, OpCodeIndex::WRITE_VOICE_SETTING}, |
| {OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT, |
| OpCodeIndex::READ_AUTOMATIC_FLUSH_TIMEOUT}, |
| {OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT, |
| OpCodeIndex::WRITE_AUTOMATIC_FLUSH_TIMEOUT}, |
| {OpCode::READ_NUM_BROADCAST_RETRANSMITS, |
| OpCodeIndex::READ_NUM_BROADCAST_RETRANSMITS}, |
| {OpCode::WRITE_NUM_BROADCAST_RETRANSMITS, |
| OpCodeIndex::WRITE_NUM_BROADCAST_RETRANSMITS}, |
| {OpCode::READ_HOLD_MODE_ACTIVITY, OpCodeIndex::READ_HOLD_MODE_ACTIVITY}, |
| {OpCode::WRITE_HOLD_MODE_ACTIVITY, |
| OpCodeIndex::WRITE_HOLD_MODE_ACTIVITY}, |
| {OpCode::READ_TRANSMIT_POWER_LEVEL, |
| OpCodeIndex::READ_TRANSMIT_POWER_LEVEL}, |
| {OpCode::READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE, |
| OpCodeIndex::READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE}, |
| {OpCode::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE, |
| OpCodeIndex::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE}, |
| {OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL, |
| OpCodeIndex::SET_CONTROLLER_TO_HOST_FLOW_CONTROL}, |
| {OpCode::HOST_BUFFER_SIZE, OpCodeIndex::HOST_BUFFER_SIZE}, |
| {OpCode::HOST_NUMBER_OF_COMPLETED_PACKETS, |
| OpCodeIndex::HOST_NUMBER_OF_COMPLETED_PACKETS}, |
| {OpCode::READ_LINK_SUPERVISION_TIMEOUT, |
| OpCodeIndex::READ_LINK_SUPERVISION_TIMEOUT}, |
| {OpCode::WRITE_LINK_SUPERVISION_TIMEOUT, |
| OpCodeIndex::WRITE_LINK_SUPERVISION_TIMEOUT}, |
| {OpCode::READ_NUMBER_OF_SUPPORTED_IAC, |
| OpCodeIndex::READ_NUMBER_OF_SUPPORTED_IAC}, |
| {OpCode::READ_CURRENT_IAC_LAP, OpCodeIndex::READ_CURRENT_IAC_LAP}, |
| {OpCode::WRITE_CURRENT_IAC_LAP, OpCodeIndex::WRITE_CURRENT_IAC_LAP}, |
| {OpCode::SET_AFH_HOST_CHANNEL_CLASSIFICATION, |
| OpCodeIndex::SET_AFH_HOST_CHANNEL_CLASSIFICATION}, |
| {OpCode::READ_INQUIRY_SCAN_TYPE, OpCodeIndex::READ_INQUIRY_SCAN_TYPE}, |
| {OpCode::WRITE_INQUIRY_SCAN_TYPE, OpCodeIndex::WRITE_INQUIRY_SCAN_TYPE}, |
| {OpCode::READ_INQUIRY_MODE, OpCodeIndex::READ_INQUIRY_MODE}, |
| {OpCode::WRITE_INQUIRY_MODE, OpCodeIndex::WRITE_INQUIRY_MODE}, |
| {OpCode::READ_PAGE_SCAN_TYPE, OpCodeIndex::READ_PAGE_SCAN_TYPE}, |
| {OpCode::WRITE_PAGE_SCAN_TYPE, OpCodeIndex::WRITE_PAGE_SCAN_TYPE}, |
| {OpCode::READ_AFH_CHANNEL_ASSESSMENT_MODE, |
| OpCodeIndex::READ_AFH_CHANNEL_ASSESSMENT_MODE}, |
| {OpCode::WRITE_AFH_CHANNEL_ASSESSMENT_MODE, |
| OpCodeIndex::WRITE_AFH_CHANNEL_ASSESSMENT_MODE}, |
| {OpCode::READ_EXTENDED_INQUIRY_RESPONSE, |
| OpCodeIndex::READ_EXTENDED_INQUIRY_RESPONSE}, |
| {OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE, |
| OpCodeIndex::WRITE_EXTENDED_INQUIRY_RESPONSE}, |
| {OpCode::REFRESH_ENCRYPTION_KEY, OpCodeIndex::REFRESH_ENCRYPTION_KEY}, |
| {OpCode::READ_SIMPLE_PAIRING_MODE, |
| OpCodeIndex::READ_SIMPLE_PAIRING_MODE}, |
| {OpCode::WRITE_SIMPLE_PAIRING_MODE, |
| OpCodeIndex::WRITE_SIMPLE_PAIRING_MODE}, |
| {OpCode::READ_LOCAL_OOB_DATA, OpCodeIndex::READ_LOCAL_OOB_DATA}, |
| {OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL, |
| OpCodeIndex::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL}, |
| {OpCode::WRITE_INQUIRY_TRANSMIT_POWER_LEVEL, |
| OpCodeIndex::WRITE_INQUIRY_TRANSMIT_POWER_LEVEL}, |
| {OpCode::READ_DEFAULT_ERRONEOUS_DATA_REPORTING, |
| OpCodeIndex::READ_DEFAULT_ERRONEOUS_DATA_REPORTING}, |
| {OpCode::WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING, |
| OpCodeIndex::WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING}, |
| {OpCode::ENHANCED_FLUSH, OpCodeIndex::ENHANCED_FLUSH}, |
| {OpCode::SEND_KEYPRESS_NOTIFICATION, |
| OpCodeIndex::SEND_KEYPRESS_NOTIFICATION}, |
| {OpCode::SET_EVENT_MASK_PAGE_2, OpCodeIndex::SET_EVENT_MASK_PAGE_2}, |
| {OpCode::READ_FLOW_CONTROL_MODE, OpCodeIndex::READ_FLOW_CONTROL_MODE}, |
| {OpCode::WRITE_FLOW_CONTROL_MODE, OpCodeIndex::WRITE_FLOW_CONTROL_MODE}, |
| {OpCode::READ_ENHANCED_TRANSMIT_POWER_LEVEL, |
| OpCodeIndex::READ_ENHANCED_TRANSMIT_POWER_LEVEL}, |
| {OpCode::READ_LE_HOST_SUPPORT, OpCodeIndex::READ_LE_HOST_SUPPORT}, |
| {OpCode::WRITE_LE_HOST_SUPPORT, OpCodeIndex::WRITE_LE_HOST_SUPPORT}, |
| {OpCode::SET_MWS_CHANNEL_PARAMETERS, |
| OpCodeIndex::SET_MWS_CHANNEL_PARAMETERS}, |
| {OpCode::SET_EXTERNAL_FRAME_CONFIGURATION, |
| OpCodeIndex::SET_EXTERNAL_FRAME_CONFIGURATION}, |
| {OpCode::SET_MWS_SIGNALING, OpCodeIndex::SET_MWS_SIGNALING}, |
| {OpCode::SET_MWS_TRANSPORT_LAYER, OpCodeIndex::SET_MWS_TRANSPORT_LAYER}, |
| {OpCode::SET_MWS_SCAN_FREQUENCY_TABLE, |
| OpCodeIndex::SET_MWS_SCAN_FREQUENCY_TABLE}, |
| {OpCode::SET_MWS_PATTERN_CONFIGURATION, |
| OpCodeIndex::SET_MWS_PATTERN_CONFIGURATION}, |
| {OpCode::SET_RESERVED_LT_ADDR, OpCodeIndex::SET_RESERVED_LT_ADDR}, |
| {OpCode::DELETE_RESERVED_LT_ADDR, OpCodeIndex::DELETE_RESERVED_LT_ADDR}, |
| {OpCode::SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_DATA, |
| OpCodeIndex::SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_DATA}, |
| {OpCode::READ_SYNCHRONIZATION_TRAIN_PARAMETERS, |
| OpCodeIndex::READ_SYNCHRONIZATION_TRAIN_PARAMETERS}, |
| {OpCode::WRITE_SYNCHRONIZATION_TRAIN_PARAMETERS, |
| OpCodeIndex::WRITE_SYNCHRONIZATION_TRAIN_PARAMETERS}, |
| {OpCode::READ_SECURE_CONNECTIONS_HOST_SUPPORT, |
| OpCodeIndex::READ_SECURE_CONNECTIONS_HOST_SUPPORT}, |
| {OpCode::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT, |
| OpCodeIndex::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT}, |
| {OpCode::READ_AUTHENTICATED_PAYLOAD_TIMEOUT, |
| OpCodeIndex::READ_AUTHENTICATED_PAYLOAD_TIMEOUT}, |
| {OpCode::WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT, |
| OpCodeIndex::WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT}, |
| {OpCode::READ_LOCAL_OOB_EXTENDED_DATA, |
| OpCodeIndex::READ_LOCAL_OOB_EXTENDED_DATA}, |
| {OpCode::READ_EXTENDED_PAGE_TIMEOUT, |
| OpCodeIndex::READ_EXTENDED_PAGE_TIMEOUT}, |
| {OpCode::WRITE_EXTENDED_PAGE_TIMEOUT, |
| OpCodeIndex::WRITE_EXTENDED_PAGE_TIMEOUT}, |
| {OpCode::READ_EXTENDED_INQUIRY_LENGTH, |
| OpCodeIndex::READ_EXTENDED_INQUIRY_LENGTH}, |
| {OpCode::WRITE_EXTENDED_INQUIRY_LENGTH, |
| OpCodeIndex::WRITE_EXTENDED_INQUIRY_LENGTH}, |
| {OpCode::SET_ECOSYSTEM_BASE_INTERVAL, |
| OpCodeIndex::SET_ECOSYSTEM_BASE_INTERVAL}, |
| {OpCode::CONFIGURE_DATA_PATH, OpCodeIndex::CONFIGURE_DATA_PATH}, |
| {OpCode::SET_MIN_ENCRYPTION_KEY_SIZE, |
| OpCodeIndex::SET_MIN_ENCRYPTION_KEY_SIZE}, |
| |
| // INFORMATIONAL_PARAMETERS |
| {OpCode::READ_LOCAL_VERSION_INFORMATION, |
| OpCodeIndex::READ_LOCAL_VERSION_INFORMATION}, |
| {OpCode::READ_LOCAL_SUPPORTED_FEATURES, |
| OpCodeIndex::READ_LOCAL_SUPPORTED_FEATURES}, |
| {OpCode::READ_LOCAL_EXTENDED_FEATURES, |
| OpCodeIndex::READ_LOCAL_EXTENDED_FEATURES}, |
| {OpCode::READ_BUFFER_SIZE, OpCodeIndex::READ_BUFFER_SIZE}, |
| {OpCode::READ_BD_ADDR, OpCodeIndex::READ_BD_ADDR}, |
| {OpCode::READ_DATA_BLOCK_SIZE, OpCodeIndex::READ_DATA_BLOCK_SIZE}, |
| {OpCode::READ_LOCAL_SUPPORTED_CODECS_V1, |
| OpCodeIndex::READ_LOCAL_SUPPORTED_CODECS_V1}, |
| {OpCode::READ_LOCAL_SIMPLE_PAIRING_OPTIONS, |
| OpCodeIndex::READ_LOCAL_SIMPLE_PAIRING_OPTIONS}, |
| {OpCode::READ_LOCAL_SUPPORTED_CODECS_V2, |
| OpCodeIndex::READ_LOCAL_SUPPORTED_CODECS_V2}, |
| {OpCode::READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES, |
| OpCodeIndex::READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES}, |
| {OpCode::READ_LOCAL_SUPPORTED_CONTROLLER_DELAY, |
| OpCodeIndex::READ_LOCAL_SUPPORTED_CONTROLLER_DELAY}, |
| |
| // STATUS_PARAMETERS |
| {OpCode::READ_FAILED_CONTACT_COUNTER, |
| OpCodeIndex::READ_FAILED_CONTACT_COUNTER}, |
| {OpCode::RESET_FAILED_CONTACT_COUNTER, |
| OpCodeIndex::RESET_FAILED_CONTACT_COUNTER}, |
| {OpCode::READ_LINK_QUALITY, OpCodeIndex::READ_LINK_QUALITY}, |
| {OpCode::READ_RSSI, OpCodeIndex::READ_RSSI}, |
| {OpCode::READ_AFH_CHANNEL_MAP, OpCodeIndex::READ_AFH_CHANNEL_MAP}, |
| {OpCode::READ_CLOCK, OpCodeIndex::READ_CLOCK}, |
| {OpCode::READ_ENCRYPTION_KEY_SIZE, |
| OpCodeIndex::READ_ENCRYPTION_KEY_SIZE}, |
| {OpCode::GET_MWS_TRANSPORT_LAYER_CONFIGURATION, |
| OpCodeIndex::GET_MWS_TRANSPORT_LAYER_CONFIGURATION}, |
| {OpCode::SET_TRIGGERED_CLOCK_CAPTURE, |
| OpCodeIndex::SET_TRIGGERED_CLOCK_CAPTURE}, |
| |
| // TESTING |
| {OpCode::READ_LOOPBACK_MODE, OpCodeIndex::READ_LOOPBACK_MODE}, |
| {OpCode::WRITE_LOOPBACK_MODE, OpCodeIndex::WRITE_LOOPBACK_MODE}, |
| {OpCode::ENABLE_DEVICE_UNDER_TEST_MODE, |
| OpCodeIndex::ENABLE_DEVICE_UNDER_TEST_MODE}, |
| {OpCode::WRITE_SIMPLE_PAIRING_DEBUG_MODE, |
| OpCodeIndex::WRITE_SIMPLE_PAIRING_DEBUG_MODE}, |
| {OpCode::WRITE_SECURE_CONNECTIONS_TEST_MODE, |
| OpCodeIndex::WRITE_SECURE_CONNECTIONS_TEST_MODE}, |
| |
| // LE_CONTROLLER |
| {OpCode::LE_SET_EVENT_MASK, OpCodeIndex::LE_SET_EVENT_MASK}, |
| {OpCode::LE_READ_BUFFER_SIZE_V1, OpCodeIndex::LE_READ_BUFFER_SIZE_V1}, |
| {OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES, |
| OpCodeIndex::LE_READ_LOCAL_SUPPORTED_FEATURES}, |
| {OpCode::LE_SET_RANDOM_ADDRESS, OpCodeIndex::LE_SET_RANDOM_ADDRESS}, |
| {OpCode::LE_SET_ADVERTISING_PARAMETERS, |
| OpCodeIndex::LE_SET_ADVERTISING_PARAMETERS}, |
| {OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER, |
| OpCodeIndex::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER}, |
| {OpCode::LE_SET_ADVERTISING_DATA, OpCodeIndex::LE_SET_ADVERTISING_DATA}, |
| {OpCode::LE_SET_SCAN_RESPONSE_DATA, |
| OpCodeIndex::LE_SET_SCAN_RESPONSE_DATA}, |
| {OpCode::LE_SET_ADVERTISING_ENABLE, |
| OpCodeIndex::LE_SET_ADVERTISING_ENABLE}, |
| {OpCode::LE_SET_SCAN_PARAMETERS, OpCodeIndex::LE_SET_SCAN_PARAMETERS}, |
| {OpCode::LE_SET_SCAN_ENABLE, OpCodeIndex::LE_SET_SCAN_ENABLE}, |
| {OpCode::LE_CREATE_CONNECTION, OpCodeIndex::LE_CREATE_CONNECTION}, |
| {OpCode::LE_CREATE_CONNECTION_CANCEL, |
| OpCodeIndex::LE_CREATE_CONNECTION_CANCEL}, |
| {OpCode::LE_READ_FILTER_ACCEPT_LIST_SIZE, |
| OpCodeIndex::LE_READ_FILTER_ACCEPT_LIST_SIZE}, |
| {OpCode::LE_CLEAR_FILTER_ACCEPT_LIST, |
| OpCodeIndex::LE_CLEAR_FILTER_ACCEPT_LIST}, |
| {OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST, |
| OpCodeIndex::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST}, |
| {OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST, |
| OpCodeIndex::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST}, |
| {OpCode::LE_CONNECTION_UPDATE, OpCodeIndex::LE_CONNECTION_UPDATE}, |
| {OpCode::LE_SET_HOST_CHANNEL_CLASSIFICATION, |
| OpCodeIndex::LE_SET_HOST_CHANNEL_CLASSIFICATION}, |
| {OpCode::LE_READ_CHANNEL_MAP, OpCodeIndex::LE_READ_CHANNEL_MAP}, |
| {OpCode::LE_READ_REMOTE_FEATURES, OpCodeIndex::LE_READ_REMOTE_FEATURES}, |
| {OpCode::LE_ENCRYPT, OpCodeIndex::LE_ENCRYPT}, |
| {OpCode::LE_RAND, OpCodeIndex::LE_RAND}, |
| {OpCode::LE_START_ENCRYPTION, OpCodeIndex::LE_START_ENCRYPTION}, |
| {OpCode::LE_LONG_TERM_KEY_REQUEST_REPLY, |
| OpCodeIndex::LE_LONG_TERM_KEY_REQUEST_REPLY}, |
| {OpCode::LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY, |
| OpCodeIndex::LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY}, |
| {OpCode::LE_READ_SUPPORTED_STATES, |
| OpCodeIndex::LE_READ_SUPPORTED_STATES}, |
| {OpCode::LE_RECEIVER_TEST_V1, OpCodeIndex::LE_RECEIVER_TEST_V1}, |
| {OpCode::LE_TRANSMITTER_TEST_V1, OpCodeIndex::LE_TRANSMITTER_TEST_V1}, |
| {OpCode::LE_TEST_END, OpCodeIndex::LE_TEST_END}, |
| {OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY, |
| OpCodeIndex::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY}, |
| {OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY, |
| OpCodeIndex::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY}, |
| {OpCode::LE_SET_DATA_LENGTH, OpCodeIndex::LE_SET_DATA_LENGTH}, |
| {OpCode::LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH, |
| OpCodeIndex::LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH}, |
| {OpCode::LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH, |
| OpCodeIndex::LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH}, |
| {OpCode::LE_READ_LOCAL_P_256_PUBLIC_KEY, |
| OpCodeIndex::LE_READ_LOCAL_P_256_PUBLIC_KEY}, |
| {OpCode::LE_GENERATE_DHKEY_V1, OpCodeIndex::LE_GENERATE_DHKEY_V1}, |
| {OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST, |
| OpCodeIndex::LE_ADD_DEVICE_TO_RESOLVING_LIST}, |
| {OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST, |
| OpCodeIndex::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST}, |
| {OpCode::LE_CLEAR_RESOLVING_LIST, OpCodeIndex::LE_CLEAR_RESOLVING_LIST}, |
| {OpCode::LE_READ_RESOLVING_LIST_SIZE, |
| OpCodeIndex::LE_READ_RESOLVING_LIST_SIZE}, |
| {OpCode::LE_READ_PEER_RESOLVABLE_ADDRESS, |
| OpCodeIndex::LE_READ_PEER_RESOLVABLE_ADDRESS}, |
| {OpCode::LE_READ_LOCAL_RESOLVABLE_ADDRESS, |
| OpCodeIndex::LE_READ_LOCAL_RESOLVABLE_ADDRESS}, |
| {OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE, |
| OpCodeIndex::LE_SET_ADDRESS_RESOLUTION_ENABLE}, |
| {OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT, |
| OpCodeIndex::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT}, |
| {OpCode::LE_READ_MAXIMUM_DATA_LENGTH, |
| OpCodeIndex::LE_READ_MAXIMUM_DATA_LENGTH}, |
| {OpCode::LE_READ_PHY, OpCodeIndex::LE_READ_PHY}, |
| {OpCode::LE_SET_DEFAULT_PHY, OpCodeIndex::LE_SET_DEFAULT_PHY}, |
| {OpCode::LE_SET_PHY, OpCodeIndex::LE_SET_PHY}, |
| {OpCode::LE_RECEIVER_TEST_V2, OpCodeIndex::LE_RECEIVER_TEST_V2}, |
| {OpCode::LE_TRANSMITTER_TEST_V2, OpCodeIndex::LE_TRANSMITTER_TEST_V2}, |
| {OpCode::LE_SET_ADVERTISING_SET_RANDOM_ADDRESS, |
| OpCodeIndex::LE_SET_ADVERTISING_SET_RANDOM_ADDRESS}, |
| {OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS, |
| OpCodeIndex::LE_SET_EXTENDED_ADVERTISING_PARAMETERS}, |
| {OpCode::LE_SET_EXTENDED_ADVERTISING_DATA, |
| OpCodeIndex::LE_SET_EXTENDED_ADVERTISING_DATA}, |
| {OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA, |
| OpCodeIndex::LE_SET_EXTENDED_SCAN_RESPONSE_DATA}, |
| {OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, |
| OpCodeIndex::LE_SET_EXTENDED_ADVERTISING_ENABLE}, |
| {OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH, |
| OpCodeIndex::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH}, |
| {OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS, |
| OpCodeIndex::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS}, |
| {OpCode::LE_REMOVE_ADVERTISING_SET, |
| OpCodeIndex::LE_REMOVE_ADVERTISING_SET}, |
| {OpCode::LE_CLEAR_ADVERTISING_SETS, |
| OpCodeIndex::LE_CLEAR_ADVERTISING_SETS}, |
| {OpCode::LE_SET_PERIODIC_ADVERTISING_PARAMETERS, |
| OpCodeIndex::LE_SET_PERIODIC_ADVERTISING_PARAMETERS}, |
| {OpCode::LE_SET_PERIODIC_ADVERTISING_DATA, |
| OpCodeIndex::LE_SET_PERIODIC_ADVERTISING_DATA}, |
| {OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE, |
| OpCodeIndex::LE_SET_PERIODIC_ADVERTISING_ENABLE}, |
| {OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, |
| OpCodeIndex::LE_SET_EXTENDED_SCAN_PARAMETERS}, |
| {OpCode::LE_SET_EXTENDED_SCAN_ENABLE, |
| OpCodeIndex::LE_SET_EXTENDED_SCAN_ENABLE}, |
| {OpCode::LE_EXTENDED_CREATE_CONNECTION, |
| OpCodeIndex::LE_EXTENDED_CREATE_CONNECTION}, |
| {OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC, |
| OpCodeIndex::LE_PERIODIC_ADVERTISING_CREATE_SYNC}, |
| {OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL, |
| OpCodeIndex::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL}, |
| {OpCode::LE_PERIODIC_ADVERTISING_TERMINATE_SYNC, |
| OpCodeIndex::LE_PERIODIC_ADVERTISING_TERMINATE_SYNC}, |
| {OpCode::LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST, |
| OpCodeIndex::LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST}, |
| {OpCode::LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST, |
| OpCodeIndex::LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST}, |
| {OpCode::LE_CLEAR_PERIODIC_ADVERTISER_LIST, |
| OpCodeIndex::LE_CLEAR_PERIODIC_ADVERTISER_LIST}, |
| {OpCode::LE_READ_PERIODIC_ADVERTISER_LIST_SIZE, |
| OpCodeIndex::LE_READ_PERIODIC_ADVERTISER_LIST_SIZE}, |
| {OpCode::LE_READ_TRANSMIT_POWER, OpCodeIndex::LE_READ_TRANSMIT_POWER}, |
| {OpCode::LE_READ_RF_PATH_COMPENSATION_POWER, |
| OpCodeIndex::LE_READ_RF_PATH_COMPENSATION_POWER}, |
| {OpCode::LE_WRITE_RF_PATH_COMPENSATION_POWER, |
| OpCodeIndex::LE_WRITE_RF_PATH_COMPENSATION_POWER}, |
| {OpCode::LE_SET_PRIVACY_MODE, OpCodeIndex::LE_SET_PRIVACY_MODE}, |
| {OpCode::LE_RECEIVER_TEST_V3, OpCodeIndex::LE_RECEIVER_TEST_V3}, |
| {OpCode::LE_TRANSMITTER_TEST_V3, OpCodeIndex::LE_TRANSMITTER_TEST_V3}, |
| {OpCode::LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS, |
| OpCodeIndex::LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS}, |
| {OpCode::LE_SET_CONNECTIONLESS_CTE_TRANSMIT_ENABLE, |
| OpCodeIndex::LE_SET_CONNECTIONLESS_CTE_TRANSMIT_ENABLE}, |
| {OpCode::LE_SET_CONNECTIONLESS_IQ_SAMPLING_ENABLE, |
| OpCodeIndex::LE_SET_CONNECTIONLESS_IQ_SAMPLING_ENABLE}, |
| {OpCode::LE_SET_CONNECTION_CTE_RECEIVE_PARAMETERS, |
| OpCodeIndex::LE_SET_CONNECTION_CTE_RECEIVE_PARAMETERS}, |
| {OpCode::LE_SET_CONNECTION_CTE_TRANSMIT_PARAMETERS, |
| OpCodeIndex::LE_SET_CONNECTION_CTE_TRANSMIT_PARAMETERS}, |
| {OpCode::LE_CONNECTION_CTE_REQUEST_ENABLE, |
| OpCodeIndex::LE_CONNECTION_CTE_REQUEST_ENABLE}, |
| {OpCode::LE_CONNECTION_CTE_RESPONSE_ENABLE, |
| OpCodeIndex::LE_CONNECTION_CTE_RESPONSE_ENABLE}, |
| {OpCode::LE_READ_ANTENNA_INFORMATION, |
| OpCodeIndex::LE_READ_ANTENNA_INFORMATION}, |
| {OpCode::LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE, |
| OpCodeIndex::LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE}, |
| {OpCode::LE_PERIODIC_ADVERTISING_SYNC_TRANSFER, |
| OpCodeIndex::LE_PERIODIC_ADVERTISING_SYNC_TRANSFER}, |
| {OpCode::LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER, |
| OpCodeIndex::LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER}, |
| {OpCode::LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS, |
| OpCodeIndex::LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS}, |
| {OpCode::LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS, |
| OpCodeIndex:: |
| LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS}, |
| {OpCode::LE_GENERATE_DHKEY_V2, OpCodeIndex::LE_GENERATE_DHKEY_V2}, |
| {OpCode::LE_MODIFY_SLEEP_CLOCK_ACCURACY, |
| OpCodeIndex::LE_MODIFY_SLEEP_CLOCK_ACCURACY}, |
| {OpCode::LE_READ_BUFFER_SIZE_V2, OpCodeIndex::LE_READ_BUFFER_SIZE_V2}, |
| {OpCode::LE_READ_ISO_TX_SYNC, OpCodeIndex::LE_READ_ISO_TX_SYNC}, |
| {OpCode::LE_SET_CIG_PARAMETERS, OpCodeIndex::LE_SET_CIG_PARAMETERS}, |
| {OpCode::LE_SET_CIG_PARAMETERS_TEST, |
| OpCodeIndex::LE_SET_CIG_PARAMETERS_TEST}, |
| {OpCode::LE_CREATE_CIS, OpCodeIndex::LE_CREATE_CIS}, |
| {OpCode::LE_REMOVE_CIG, OpCodeIndex::LE_REMOVE_CIG}, |
| {OpCode::LE_ACCEPT_CIS_REQUEST, OpCodeIndex::LE_ACCEPT_CIS_REQUEST}, |
| {OpCode::LE_REJECT_CIS_REQUEST, OpCodeIndex::LE_REJECT_CIS_REQUEST}, |
| {OpCode::LE_CREATE_BIG, OpCodeIndex::LE_CREATE_BIG}, |
| {OpCode::LE_CREATE_BIG_TEST, OpCodeIndex::LE_CREATE_BIG_TEST}, |
| {OpCode::LE_TERMINATE_BIG, OpCodeIndex::LE_TERMINATE_BIG}, |
| {OpCode::LE_BIG_CREATE_SYNC, OpCodeIndex::LE_BIG_CREATE_SYNC}, |
| {OpCode::LE_BIG_TERMINATE_SYNC, OpCodeIndex::LE_BIG_TERMINATE_SYNC}, |
| {OpCode::LE_REQUEST_PEER_SCA, OpCodeIndex::LE_REQUEST_PEER_SCA}, |
| {OpCode::LE_SETUP_ISO_DATA_PATH, OpCodeIndex::LE_SETUP_ISO_DATA_PATH}, |
| {OpCode::LE_REMOVE_ISO_DATA_PATH, OpCodeIndex::LE_REMOVE_ISO_DATA_PATH}, |
| {OpCode::LE_ISO_TRANSMIT_TEST, OpCodeIndex::LE_ISO_TRANSMIT_TEST}, |
| {OpCode::LE_ISO_RECEIVE_TEST, OpCodeIndex::LE_ISO_RECEIVE_TEST}, |
| {OpCode::LE_ISO_READ_TEST_COUNTERS, |
| OpCodeIndex::LE_ISO_READ_TEST_COUNTERS}, |
| {OpCode::LE_ISO_TEST_END, OpCodeIndex::LE_ISO_TEST_END}, |
| {OpCode::LE_SET_HOST_FEATURE, OpCodeIndex::LE_SET_HOST_FEATURE}, |
| {OpCode::LE_READ_ISO_LINK_QUALITY, |
| OpCodeIndex::LE_READ_ISO_LINK_QUALITY}, |
| {OpCode::LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL, |
| OpCodeIndex::LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL}, |
| {OpCode::LE_READ_REMOTE_TRANSMIT_POWER_LEVEL, |
| OpCodeIndex::LE_READ_REMOTE_TRANSMIT_POWER_LEVEL}, |
| {OpCode::LE_SET_PATH_LOSS_REPORTING_PARAMETERS, |
| OpCodeIndex::LE_SET_PATH_LOSS_REPORTING_PARAMETERS}, |
| {OpCode::LE_SET_PATH_LOSS_REPORTING_ENABLE, |
| OpCodeIndex::LE_SET_PATH_LOSS_REPORTING_ENABLE}, |
| {OpCode::LE_SET_TRANSMIT_POWER_REPORTING_ENABLE, |
| OpCodeIndex::LE_SET_TRANSMIT_POWER_REPORTING_ENABLE}, |
| {OpCode::LE_TRANSMITTER_TEST_V4, OpCodeIndex::LE_TRANSMITTER_TEST_V4}, |
| {OpCode::LE_SET_DATA_RELATED_ADDRESS_CHANGES, |
| OpCodeIndex::LE_SET_DATA_RELATED_ADDRESS_CHANGES}, |
| {OpCode::LE_SET_DEFAULT_SUBRATE, OpCodeIndex::LE_SET_DEFAULT_SUBRATE}, |
| {OpCode::LE_SUBRATE_REQUEST, OpCodeIndex::LE_SUBRATE_REQUEST}, |
| }; |
| |
| const std::unordered_map<OpCode, DualModeController::CommandHandler> |
| DualModeController::hci_command_handlers_{ |
| // LINK_CONTROL |
| {OpCode::INQUIRY, &DualModeController::Inquiry}, |
| {OpCode::INQUIRY_CANCEL, &DualModeController::InquiryCancel}, |
| //{OpCode::PERIODIC_INQUIRY_MODE, |
| //&DualModeController::PeriodicInquiryMode}, |
| //{OpCode::EXIT_PERIODIC_INQUIRY_MODE, |
| //&DualModeController::ExitPeriodicInquiryMode}, |
| {OpCode::CREATE_CONNECTION, &DualModeController::CreateConnection}, |
| {OpCode::DISCONNECT, &DualModeController::Disconnect}, |
| {OpCode::ADD_SCO_CONNECTION, &DualModeController::AddScoConnection}, |
| {OpCode::CREATE_CONNECTION_CANCEL, |
| &DualModeController::CreateConnectionCancel}, |
| {OpCode::ACCEPT_CONNECTION_REQUEST, |
| &DualModeController::AcceptConnectionRequest}, |
| {OpCode::REJECT_CONNECTION_REQUEST, |
| &DualModeController::RejectConnectionRequest}, |
| {OpCode::LINK_KEY_REQUEST_REPLY, &DualModeController::ForwardToLm}, |
| {OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, |
| &DualModeController::ForwardToLm}, |
| {OpCode::PIN_CODE_REQUEST_REPLY, &DualModeController::ForwardToLm}, |
| {OpCode::PIN_CODE_REQUEST_NEGATIVE_REPLY, |
| &DualModeController::ForwardToLm}, |
| {OpCode::CHANGE_CONNECTION_PACKET_TYPE, |
| &DualModeController::ChangeConnectionPacketType}, |
| {OpCode::AUTHENTICATION_REQUESTED, &DualModeController::ForwardToLm}, |
| {OpCode::SET_CONNECTION_ENCRYPTION, &DualModeController::ForwardToLm}, |
| {OpCode::CHANGE_CONNECTION_LINK_KEY, |
| &DualModeController::ChangeConnectionLinkKey}, |
| {OpCode::CENTRAL_LINK_KEY, &DualModeController::CentralLinkKey}, |
| {OpCode::REMOTE_NAME_REQUEST, &DualModeController::RemoteNameRequest}, |
| //{OpCode::REMOTE_NAME_REQUEST_CANCEL, |
| //&DualModeController::RemoteNameRequestCancel}, |
| {OpCode::READ_REMOTE_SUPPORTED_FEATURES, |
| &DualModeController::ReadRemoteSupportedFeatures}, |
| {OpCode::READ_REMOTE_EXTENDED_FEATURES, |
| &DualModeController::ReadRemoteExtendedFeatures}, |
| {OpCode::READ_REMOTE_VERSION_INFORMATION, |
| &DualModeController::ReadRemoteVersionInformation}, |
| {OpCode::READ_CLOCK_OFFSET, &DualModeController::ReadClockOffset}, |
| //{OpCode::READ_LMP_HANDLE, &DualModeController::ReadLmpHandle}, |
| {OpCode::SETUP_SYNCHRONOUS_CONNECTION, |
| &DualModeController::SetupSynchronousConnection}, |
| {OpCode::ACCEPT_SYNCHRONOUS_CONNECTION, |
| &DualModeController::AcceptSynchronousConnection}, |
| {OpCode::REJECT_SYNCHRONOUS_CONNECTION, |
| &DualModeController::RejectSynchronousConnection}, |
| {OpCode::IO_CAPABILITY_REQUEST_REPLY, &DualModeController::ForwardToLm}, |
| {OpCode::USER_CONFIRMATION_REQUEST_REPLY, |
| &DualModeController::ForwardToLm}, |
| {OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, |
| &DualModeController::ForwardToLm}, |
| {OpCode::USER_PASSKEY_REQUEST_REPLY, &DualModeController::ForwardToLm}, |
| {OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY, |
| &DualModeController::ForwardToLm}, |
| {OpCode::REMOTE_OOB_DATA_REQUEST_REPLY, |
| &DualModeController::ForwardToLm}, |
| {OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, |
| &DualModeController::ForwardToLm}, |
| {OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, |
| &DualModeController::ForwardToLm}, |
| {OpCode::ENHANCED_SETUP_SYNCHRONOUS_CONNECTION, |
| &DualModeController::EnhancedSetupSynchronousConnection}, |
| {OpCode::ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION, |
| &DualModeController::EnhancedAcceptSynchronousConnection}, |
| //{OpCode::TRUNCATED_PAGE, &DualModeController::TruncatedPage}, |
| //{OpCode::TRUNCATED_PAGE_CANCEL, |
| //&DualModeController::TruncatedPageCancel}, |
| //{OpCode::SET_CONNECTIONLESS_PERIPHERAL_BROADCAST, |
| //&DualModeController::SetConnectionlessPeripheralBroadcast}, |
| //{OpCode::SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_RECEIVE, |
| //&DualModeController::SetConnectionlessPeripheralBroadcastReceive}, |
| //{OpCode::START_SYNCHRONIZATION_TRAIN, |
| //&DualModeController::StartSynchronizationTrain}, |
| //{OpCode::RECEIVE_SYNCHRONIZATION_TRAIN, |
| //&DualModeController::ReceiveSynchronizationTrain}, |
| {OpCode::REMOTE_OOB_EXTENDED_DATA_REQUEST_REPLY, |
| &DualModeController::ForwardToLm}, |
| |
| // LINK_POLICY |
| {OpCode::HOLD_MODE, &DualModeController::HoldMode}, |
| {OpCode::SNIFF_MODE, &DualModeController::SniffMode}, |
| {OpCode::EXIT_SNIFF_MODE, &DualModeController::ExitSniffMode}, |
| {OpCode::QOS_SETUP, &DualModeController::QosSetup}, |
| {OpCode::ROLE_DISCOVERY, &DualModeController::RoleDiscovery}, |
| {OpCode::SWITCH_ROLE, &DualModeController::SwitchRole}, |
| {OpCode::READ_LINK_POLICY_SETTINGS, |
| &DualModeController::ReadLinkPolicySettings}, |
| {OpCode::WRITE_LINK_POLICY_SETTINGS, |
| &DualModeController::WriteLinkPolicySettings}, |
| {OpCode::READ_DEFAULT_LINK_POLICY_SETTINGS, |
| &DualModeController::ReadDefaultLinkPolicySettings}, |
| {OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS, |
| &DualModeController::WriteDefaultLinkPolicySettings}, |
| {OpCode::FLOW_SPECIFICATION, &DualModeController::FlowSpecification}, |
| {OpCode::SNIFF_SUBRATING, &DualModeController::SniffSubrating}, |
| |
| // CONTROLLER_AND_BASEBAND |
| {OpCode::SET_EVENT_MASK, &DualModeController::SetEventMask}, |
| {OpCode::RESET, &DualModeController::Reset}, |
| {OpCode::SET_EVENT_FILTER, &DualModeController::SetEventFilter}, |
| //{OpCode::FLUSH, &DualModeController::Flush}, |
| //{OpCode::READ_PIN_TYPE, &DualModeController::ReadPinType}, |
| //{OpCode::WRITE_PIN_TYPE, &DualModeController::WritePinType}, |
| //{OpCode::READ_STORED_LINK_KEY, |
| //&DualModeController::ReadStoredLinkKey}, |
| //{OpCode::WRITE_STORED_LINK_KEY, |
| //&DualModeController::WriteStoredLinkKey}, |
| {OpCode::DELETE_STORED_LINK_KEY, |
| &DualModeController::DeleteStoredLinkKey}, |
| {OpCode::WRITE_LOCAL_NAME, &DualModeController::WriteLocalName}, |
| {OpCode::READ_LOCAL_NAME, &DualModeController::ReadLocalName}, |
| {OpCode::READ_CONNECTION_ACCEPT_TIMEOUT, |
| &DualModeController::ReadConnectionAcceptTimeout}, |
| {OpCode::WRITE_CONNECTION_ACCEPT_TIMEOUT, |
| &DualModeController::WriteConnectionAcceptTimeout}, |
| {OpCode::READ_PAGE_TIMEOUT, &DualModeController::ReadPageTimeout}, |
| {OpCode::WRITE_PAGE_TIMEOUT, &DualModeController::WritePageTimeout}, |
| {OpCode::READ_SCAN_ENABLE, &DualModeController::ReadScanEnable}, |
| {OpCode::WRITE_SCAN_ENABLE, &DualModeController::WriteScanEnable}, |
| {OpCode::READ_PAGE_SCAN_ACTIVITY, |
| &DualModeController::ReadPageScanActivity}, |
| {OpCode::WRITE_PAGE_SCAN_ACTIVITY, |
| &DualModeController::WritePageScanActivity}, |
| {OpCode::READ_INQUIRY_SCAN_ACTIVITY, |
| &DualModeController::ReadInquiryScanActivity}, |
| {OpCode::WRITE_INQUIRY_SCAN_ACTIVITY, |
| &DualModeController::WriteInquiryScanActivity}, |
| {OpCode::READ_AUTHENTICATION_ENABLE, |
| &DualModeController::ReadAuthenticationEnable}, |
| {OpCode::WRITE_AUTHENTICATION_ENABLE, |
| &DualModeController::WriteAuthenticationEnable}, |
| {OpCode::READ_CLASS_OF_DEVICE, &DualModeController::ReadClassOfDevice}, |
| {OpCode::WRITE_CLASS_OF_DEVICE, |
| &DualModeController::WriteClassOfDevice}, |
| {OpCode::READ_VOICE_SETTING, &DualModeController::ReadVoiceSetting}, |
| {OpCode::WRITE_VOICE_SETTING, &DualModeController::WriteVoiceSetting}, |
| //{OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT, |
| //&DualModeController::ReadAutomaticFlushTimeout}, |
| //{OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT, |
| //&DualModeController::WriteAutomaticFlushTimeout}, |
| //{OpCode::READ_NUM_BROADCAST_RETRANSMITS, |
| //&DualModeController::ReadNumBroadcastRetransmits}, |
| //{OpCode::WRITE_NUM_BROADCAST_RETRANSMITS, |
| //&DualModeController::WriteNumBroadcastRetransmits}, |
| //{OpCode::READ_HOLD_MODE_ACTIVITY, |
| //&DualModeController::ReadHoldModeActivity}, |
| //{OpCode::WRITE_HOLD_MODE_ACTIVITY, |
| //&DualModeController::WriteHoldModeActivity}, |
| //{OpCode::READ_TRANSMIT_POWER_LEVEL, |
| //&DualModeController::ReadTransmitPowerLevel}, |
| {OpCode::READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE, |
| &DualModeController::ReadSynchronousFlowControlEnable}, |
| {OpCode::WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE, |
| &DualModeController::WriteSynchronousFlowControlEnable}, |
| //{OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL, |
| //&DualModeController::SetControllerToHostFlowControl}, |
| {OpCode::HOST_BUFFER_SIZE, &DualModeController::HostBufferSize}, |
| //{OpCode::HOST_NUMBER_OF_COMPLETED_PACKETS, |
| //&DualModeController::HostNumberOfCompletedPackets}, |
| //{OpCode::READ_LINK_SUPERVISION_TIMEOUT, |
| //&DualModeController::ReadLinkSupervisionTimeout}, |
| {OpCode::WRITE_LINK_SUPERVISION_TIMEOUT, |
| &DualModeController::WriteLinkSupervisionTimeout}, |
| {OpCode::READ_NUMBER_OF_SUPPORTED_IAC, |
| &DualModeController::ReadNumberOfSupportedIac}, |
| {OpCode::READ_CURRENT_IAC_LAP, &DualModeController::ReadCurrentIacLap}, |
| {OpCode::WRITE_CURRENT_IAC_LAP, |
| &DualModeController::WriteCurrentIacLap}, |
| //{OpCode::SET_AFH_HOST_CHANNEL_CLASSIFICATION, |
| //&DualModeController::SetAfhHostChannelClassification}, |
| {OpCode::READ_INQUIRY_SCAN_TYPE, |
| &DualModeController::ReadInquiryScanType}, |
| {OpCode::WRITE_INQUIRY_SCAN_TYPE, |
| &DualModeController::WriteInquiryScanType}, |
| {OpCode::READ_INQUIRY_MODE, &DualModeController::ReadInquiryMode}, |
| {OpCode::WRITE_INQUIRY_MODE, &DualModeController::WriteInquiryMode}, |
| {OpCode::READ_PAGE_SCAN_TYPE, &DualModeController::ReadPageScanType}, |
| {OpCode::WRITE_PAGE_SCAN_TYPE, &DualModeController::WritePageScanType}, |
| //{OpCode::READ_AFH_CHANNEL_ASSESSMENT_MODE, |
| //&DualModeController::ReadAfhChannelAssessmentMode}, |
| //{OpCode::WRITE_AFH_CHANNEL_ASSESSMENT_MODE, |
| //&DualModeController::WriteAfhChannelAssessmentMode}, |
| //{OpCode::READ_EXTENDED_INQUIRY_RESPONSE, |
| //&DualModeController::ReadExtendedInquiryResponse}, |
| {OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE, |
| &DualModeController::WriteExtendedInquiryResponse}, |
| {OpCode::REFRESH_ENCRYPTION_KEY, |
| &DualModeController::RefreshEncryptionKey}, |
| //{OpCode::READ_SIMPLE_PAIRING_MODE, |
| //&DualModeController::ReadSimplePairingMode}, |
| {OpCode::WRITE_SIMPLE_PAIRING_MODE, |
| &DualModeController::WriteSimplePairingMode}, |
| {OpCode::READ_LOCAL_OOB_DATA, &DualModeController::ReadLocalOobData}, |
| {OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL, |
| &DualModeController::ReadInquiryResponseTransmitPowerLevel}, |
| //{OpCode::WRITE_INQUIRY_TRANSMIT_POWER_LEVEL, |
| //&DualModeController::WriteInquiryTransmitPowerLevel}, |
| //{OpCode::READ_DEFAULT_ERRONEOUS_DATA_REPORTING, |
| //&DualModeController::ReadDefaultErroneousDataReporting}, |
| //{OpCode::WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING, |
| //&DualModeController::WriteDefaultErroneousDataReporting}, |
| {OpCode::ENHANCED_FLUSH, &DualModeController::EnhancedFlush}, |
| {OpCode::SEND_KEYPRESS_NOTIFICATION, &DualModeController::ForwardToLm}, |
| {OpCode::SET_EVENT_MASK_PAGE_2, &DualModeController::SetEventMaskPage2}, |
| //{OpCode::READ_FLOW_CONTROL_MODE, |
| //&DualModeController::ReadFlowControlMode}, |
| //{OpCode::WRITE_FLOW_CONTROL_MODE, |
| //&DualModeController::WriteFlowControlMode}, |
| //{OpCode::READ_ENHANCED_TRANSMIT_POWER_LEVEL, |
| //&DualModeController::ReadEnhancedTransmitPowerLevel}, |
| //{OpCode::READ_LE_HOST_SUPPORT, |
| //&DualModeController::ReadLeHostSupport}, |
| {OpCode::WRITE_LE_HOST_SUPPORT, |
| &DualModeController::WriteLeHostSupport}, |
| //{OpCode::SET_MWS_CHANNEL_PARAMETERS, |
| //&DualModeController::SetMwsChannelParameters}, |
| //{OpCode::SET_EXTERNAL_FRAME_CONFIGURATION, |
| //&DualModeController::SetExternalFrameConfiguration}, |
| //{OpCode::SET_MWS_SIGNALING, &DualModeController::SetMwsSignaling}, |
| //{OpCode::SET_MWS_TRANSPORT_LAYER, |
| //&DualModeController::SetMwsTransportLayer}, |
| //{OpCode::SET_MWS_SCAN_FREQUENCY_TABLE, |
| //&DualModeController::SetMwsScanFrequencyTable}, |
| //{OpCode::SET_MWS_PATTERN_CONFIGURATION, |
| //&DualModeController::SetMwsPatternConfiguration}, |
| //{OpCode::SET_RESERVED_LT_ADDR, |
| //&DualModeController::SetReservedLtAddr}, |
| //{OpCode::DELETE_RESERVED_LT_ADDR, |
| //&DualModeController::DeleteReservedLtAddr}, |
| //{OpCode::SET_CONNECTIONLESS_PERIPHERAL_BROADCAST_DATA, |
| //&DualModeController::SetConnectionlessPeripheralBroadcastData}, |
| //{OpCode::READ_SYNCHRONIZATION_TRAIN_PARAMETERS, |
| //&DualModeController::ReadSynchronizationTrainParameters}, |
| //{OpCode::WRITE_SYNCHRONIZATION_TRAIN_PARAMETERS, |
| //&DualModeController::WriteSynchronizationTrainParameters}, |
| //{OpCode::READ_SECURE_CONNECTIONS_HOST_SUPPORT, |
| //&DualModeController::ReadSecureConnectionsHostSupport}, |
| {OpCode::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT, |
| &DualModeController::WriteSecureConnectionsHostSupport}, |
| //{OpCode::READ_AUTHENTICATED_PAYLOAD_TIMEOUT, |
| //&DualModeController::ReadAuthenticatedPayloadTimeout}, |
| //{OpCode::WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT, |
| //&DualModeController::WriteAuthenticatedPayloadTimeout}, |
| {OpCode::READ_LOCAL_OOB_EXTENDED_DATA, |
| &DualModeController::ReadLocalOobExtendedData}, |
| //{OpCode::READ_EXTENDED_PAGE_TIMEOUT, |
| //&DualModeController::ReadExtendedPageTimeout}, |
| //{OpCode::WRITE_EXTENDED_PAGE_TIMEOUT, |
| //&DualModeController::WriteExtendedPageTimeout}, |
| //{OpCode::READ_EXTENDED_INQUIRY_LENGTH, |
| //&DualModeController::ReadExtendedInquiryLength}, |
| //{OpCode::WRITE_EXTENDED_INQUIRY_LENGTH, |
| //&DualModeController::WriteExtendedInquiryLength}, |
| //{OpCode::SET_ECOSYSTEM_BASE_INTERVAL, |
| //&DualModeController::SetEcosystemBaseInterval}, |
| //{OpCode::CONFIGURE_DATA_PATH, &DualModeController::ConfigureDataPath}, |
| //{OpCode::SET_MIN_ENCRYPTION_KEY_SIZE, |
| //&DualModeController::SetMinEncryptionKeySize}, |
| |
| // INFORMATIONAL_PARAMETERS |
| {OpCode::READ_LOCAL_VERSION_INFORMATION, |
| &DualModeController::ReadLocalVersionInformation}, |
| {OpCode::READ_LOCAL_SUPPORTED_COMMANDS, |
| &DualModeController::ReadLocalSupportedCommands}, |
| {OpCode::READ_LOCAL_SUPPORTED_FEATURES, |
| &DualModeController::ReadLocalSupportedFeatures}, |
| {OpCode::READ_LOCAL_EXTENDED_FEATURES, |
| &DualModeController::ReadLocalExtendedFeatures}, |
| {OpCode::READ_BUFFER_SIZE, &DualModeController::ReadBufferSize}, |
| {OpCode::READ_BD_ADDR, &DualModeController::ReadBdAddr}, |
| //{OpCode::READ_DATA_BLOCK_SIZE, |
| //&DualModeController::ReadDataBlockSize}, |
| {OpCode::READ_LOCAL_SUPPORTED_CODECS_V1, |
| &DualModeController::ReadLocalSupportedCodecsV1}, |
| //{OpCode::READ_LOCAL_SIMPLE_PAIRING_OPTIONS, |
| //&DualModeController::ReadLocalSimplePairingOptions}, |
| //{OpCode::READ_LOCAL_SUPPORTED_CODECS_V2, |
| //&DualModeController::ReadLocalSupportedCodecsV2}, |
| //{OpCode::READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES, |
| //&DualModeController::ReadLocalSupportedCodecCapabilities}, |
| //{OpCode::READ_LOCAL_SUPPORTED_CONTROLLER_DELAY, |
| //&DualModeController::ReadLocalSupportedControllerDelay}, |
| |
| // STATUS_PARAMETERS |
| {OpCode::READ_FAILED_CONTACT_COUNTER, |
| &DualModeController::ReadFailedContactCounter}, |
| {OpCode::RESET_FAILED_CONTACT_COUNTER, |
| &DualModeController::ResetFailedContactCounter}, |
| //{OpCode::READ_LINK_QUALITY, &DualModeController::ReadLinkQuality}, |
| {OpCode::READ_RSSI, &DualModeController::ReadRssi}, |
| //{OpCode::READ_AFH_CHANNEL_MAP, |
| //&DualModeController::ReadAfhChannelMap}, |
| //{OpCode::READ_CLOCK, &DualModeController::ReadClock}, |
| {OpCode::READ_ENCRYPTION_KEY_SIZE, |
| &DualModeController::ReadEncryptionKeySize}, |
| //{OpCode::GET_MWS_TRANSPORT_LAYER_CONFIGURATION, |
| //&DualModeController::GetMwsTransportLayerConfiguration}, |
| //{OpCode::SET_TRIGGERED_CLOCK_CAPTURE, |
| //&DualModeController::SetTriggeredClockCapture}, |
| |
| // TESTING |
| {OpCode::READ_LOOPBACK_MODE, &DualModeController::ReadLoopbackMode}, |
| {OpCode::WRITE_LOOPBACK_MODE, &DualModeController::WriteLoopbackMode}, |
| //{OpCode::ENABLE_DEVICE_UNDER_TEST_MODE, |
| //&DualModeController::EnableDeviceUnderTestMode}, |
| //{OpCode::WRITE_SIMPLE_PAIRING_DEBUG_MODE, |
| //&DualModeController::WriteSimplePairingDebugMode}, |
| //{OpCode::WRITE_SECURE_CONNECTIONS_TEST_MODE, |
| //&DualModeController::WriteSecureConnectionsTestMode}, |
| |
| // LE_CONTROLLER |
| {OpCode::LE_SET_EVENT_MASK, &DualModeController::LeSetEventMask}, |
| {OpCode::LE_READ_BUFFER_SIZE_V1, |
| &DualModeController::LeReadBufferSizeV1}, |
| {OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES, |
| &DualModeController::LeReadLocalSupportedFeatures}, |
| {OpCode::LE_SET_RANDOM_ADDRESS, |
| &DualModeController::LeSetRandomAddress}, |
| {OpCode::LE_SET_ADVERTISING_PARAMETERS, |
| &DualModeController::LeSetAdvertisingParameters}, |
| {OpCode::LE_READ_ADVERTISING_PHYSICAL_CHANNEL_TX_POWER, |
| &DualModeController::LeReadAdvertisingPhysicalChannelTxPower}, |
| {OpCode::LE_SET_ADVERTISING_DATA, |
| &DualModeController::LeSetAdvertisingData}, |
| {OpCode::LE_SET_SCAN_RESPONSE_DATA, |
| &DualModeController::LeSetScanResponseData}, |
| {OpCode::LE_SET_ADVERTISING_ENABLE, |
| &DualModeController::LeSetAdvertisingEnable}, |
| {OpCode::LE_SET_SCAN_PARAMETERS, |
| &DualModeController::LeSetScanParameters}, |
| {OpCode::LE_SET_SCAN_ENABLE, &DualModeController::LeSetScanEnable}, |
| {OpCode::LE_CREATE_CONNECTION, &DualModeController::LeCreateConnection}, |
| {OpCode::LE_CREATE_CONNECTION_CANCEL, |
| &DualModeController::LeCreateConnectionCancel}, |
| {OpCode::LE_READ_FILTER_ACCEPT_LIST_SIZE, |
| &DualModeController::LeReadFilterAcceptListSize}, |
| {OpCode::LE_CLEAR_FILTER_ACCEPT_LIST, |
| &DualModeController::LeClearFilterAcceptList}, |
| {OpCode::LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST, |
| &DualModeController::LeAddDeviceToFilterAcceptList}, |
| {OpCode::LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST, |
| &DualModeController::LeRemoveDeviceFromFilterAcceptList}, |
| {OpCode::LE_CONNECTION_UPDATE, &DualModeController::LeConnectionUpdate}, |
| //{OpCode::LE_SET_HOST_CHANNEL_CLASSIFICATION, |
| //&DualModeController::LeSetHostChannelClassification}, |
| //{OpCode::LE_READ_CHANNEL_MAP, &DualModeController::LeReadChannelMap}, |
| {OpCode::LE_READ_REMOTE_FEATURES, |
| &DualModeController::LeReadRemoteFeatures}, |
| {OpCode::LE_ENCRYPT, &DualModeController::LeEncrypt}, |
| {OpCode::LE_RAND, &DualModeController::LeRand}, |
| {OpCode::LE_START_ENCRYPTION, &DualModeController::LeStartEncryption}, |
| {OpCode::LE_LONG_TERM_KEY_REQUEST_REPLY, |
| &DualModeController::LeLongTermKeyRequestReply}, |
| {OpCode::LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY, |
| &DualModeController::LeLongTermKeyRequestNegativeReply}, |
| {OpCode::LE_READ_SUPPORTED_STATES, |
| &DualModeController::LeReadSupportedStates}, |
| //{OpCode::LE_RECEIVER_TEST_V1, &DualModeController::LeReceiverTestV1}, |
| //{OpCode::LE_TRANSMITTER_TEST_V1, |
| //&DualModeController::LeTransmitterTestV1}, |
| //{OpCode::LE_TEST_END, &DualModeController::LeTestEnd}, |
| {OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY, |
| &DualModeController::LeRemoteConnectionParameterRequestReply}, |
| {OpCode::LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY, |
| &DualModeController::LeRemoteConnectionParameterRequestNegativeReply}, |
| //{OpCode::LE_SET_DATA_LENGTH, &DualModeController::LeSetDataLength}, |
| {OpCode::LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH, |
| &DualModeController::LeReadSuggestedDefaultDataLength}, |
| {OpCode::LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH, |
| &DualModeController::LeWriteSuggestedDefaultDataLength}, |
| //{OpCode::LE_READ_LOCAL_P_256_PUBLIC_KEY, |
| //&DualModeController::LeReadLocalP256PublicKey}, |
| //{OpCode::LE_GENERATE_DHKEY_V1, |
| //&DualModeController::LeGenerateDhkeyV1}, |
| {OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST, |
| &DualModeController::LeAddDeviceToResolvingList}, |
| {OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST, |
| &DualModeController::LeRemoveDeviceFromResolvingList}, |
| {OpCode::LE_CLEAR_RESOLVING_LIST, |
| &DualModeController::LeClearResolvingList}, |
| {OpCode::LE_READ_RESOLVING_LIST_SIZE, |
| &DualModeController::LeReadResolvingListSize}, |
| {OpCode::LE_READ_PEER_RESOLVABLE_ADDRESS, |
| &DualModeController::LeReadPeerResolvableAddress}, |
| {OpCode::LE_READ_LOCAL_RESOLVABLE_ADDRESS, |
| &DualModeController::LeReadLocalResolvableAddress}, |
| {OpCode::LE_SET_ADDRESS_RESOLUTION_ENABLE, |
| &DualModeController::LeSetAddressResolutionEnable}, |
| {OpCode::LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT, |
| &DualModeController::LeSetResolvablePrivateAddressTimeout}, |
| {OpCode::LE_READ_MAXIMUM_DATA_LENGTH, |
| &DualModeController::LeReadMaximumDataLength}, |
| {OpCode::LE_READ_PHY, &DualModeController::LeReadPhy}, |
| {OpCode::LE_SET_DEFAULT_PHY, &DualModeController::LeSetDefaultPhy}, |
| {OpCode::LE_SET_PHY, &DualModeController::LeSetPhy}, |
| //{OpCode::LE_RECEIVER_TEST_V2, &DualModeController::LeReceiverTestV2}, |
| //{OpCode::LE_TRANSMITTER_TEST_V2, |
| //&DualModeController::LeTransmitterTestV2}, |
| {OpCode::LE_SET_ADVERTISING_SET_RANDOM_ADDRESS, |
| &DualModeController::LeSetAdvertisingSetRandomAddress}, |
| {OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS, |
| &DualModeController::LeSetExtendedAdvertisingParameters}, |
| {OpCode::LE_SET_EXTENDED_ADVERTISING_DATA, |
| &DualModeController::LeSetExtendedAdvertisingData}, |
| {OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA, |
| &DualModeController::LeSetExtendedScanResponseData}, |
| {OpCode::LE_SET_EXTENDED_ADVERTISING_ENABLE, |
| &DualModeController::LeSetExtendedAdvertisingEnable}, |
| {OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH, |
| &DualModeController::LeReadMaximumAdvertisingDataLength}, |
| {OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS, |
| &DualModeController::LeReadNumberOfSupportedAdvertisingSets}, |
| {OpCode::LE_REMOVE_ADVERTISING_SET, |
| &DualModeController::LeRemoveAdvertisingSet}, |
| {OpCode::LE_CLEAR_ADVERTISING_SETS, |
| &DualModeController::LeClearAdvertisingSets}, |
| {OpCode::LE_SET_PERIODIC_ADVERTISING_PARAMETERS, |
| &DualModeController::LeSetPeriodicAdvertisingParameters}, |
| {OpCode::LE_SET_PERIODIC_ADVERTISING_DATA, |
| &DualModeController::LeSetPeriodicAdvertisingData}, |
| {OpCode::LE_SET_PERIODIC_ADVERTISING_ENABLE, |
| &DualModeController::LeSetPeriodicAdvertisingEnable}, |
| {OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS, |
| &DualModeController::LeSetExtendedScanParameters}, |
| {OpCode::LE_SET_EXTENDED_SCAN_ENABLE, |
| &DualModeController::LeSetExtendedScanEnable}, |
| {OpCode::LE_EXTENDED_CREATE_CONNECTION, |
| &DualModeController::LeExtendedCreateConnection}, |
| {OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC, |
| &DualModeController::LePeriodicAdvertisingCreateSync}, |
| {OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL, |
| &DualModeController::LePeriodicAdvertisingCreateSyncCancel}, |
| {OpCode::LE_PERIODIC_ADVERTISING_TERMINATE_SYNC, |
| &DualModeController::LePeriodicAdvertisingTerminateSync}, |
| {OpCode::LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST, |
| &DualModeController::LeAddDeviceToPeriodicAdvertiserList}, |
| {OpCode::LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST, |
| &DualModeController::LeRemoveDeviceFromPeriodicAdvertiserList}, |
| {OpCode::LE_CLEAR_PERIODIC_ADVERTISER_LIST, |
| &DualModeController::LeClearPeriodicAdvertiserList}, |
| {OpCode::LE_READ_PERIODIC_ADVERTISER_LIST_SIZE, |
| &DualModeController::LeReadPeriodicAdvertiserListSize}, |
| //{OpCode::LE_READ_TRANSMIT_POWER, |
| //&DualModeController::LeReadTransmitPower}, |
| //{OpCode::LE_READ_RF_PATH_COMPENSATION_POWER, |
| //&DualModeController::LeReadRfPathCompensationPower}, |
| //{OpCode::LE_WRITE_RF_PATH_COMPENSATION_POWER, |
| //&DualModeController::LeWriteRfPathCompensationPower}, |
| {OpCode::LE_SET_PRIVACY_MODE, &DualModeController::LeSetPrivacyMode}, |
| //{OpCode::LE_RECEIVER_TEST_V3, &DualModeController::LeReceiverTestV3}, |
| //{OpCode::LE_TRANSMITTER_TEST_V3, |
| //&DualModeController::LeTransmitterTestV3}, |
| //{OpCode::LE_SET_CONNECTIONLESS_CTE_TRANSMIT_PARAMETERS, |
| //&DualModeController::LeSetConnectionlessCteTransmitParameters}, |
| //{OpCode::LE_SET_CONNECTIONLESS_CTE_TRANSMIT_ENABLE, |
| //&DualModeController::LeSetConnectionlessCteTransmitEnable}, |
| //{OpCode::LE_SET_CONNECTIONLESS_IQ_SAMPLING_ENABLE, |
| //&DualModeController::LeSetConnectionlessIqSamplingEnable}, |
| //{OpCode::LE_SET_CONNECTION_CTE_RECEIVE_PARAMETERS, |
| //&DualModeController::LeSetConnectionCteReceiveParameters}, |
| //{OpCode::LE_SET_CONNECTION_CTE_TRANSMIT_PARAMETERS, |
| //&DualModeController::LeSetConnectionCteTransmitParameters}, |
| //{OpCode::LE_CONNECTION_CTE_REQUEST_ENABLE, |
| //&DualModeController::LeConnectionCteRequestEnable}, |
| //{OpCode::LE_CONNECTION_CTE_RESPONSE_ENABLE, |
| //&DualModeController::LeConnectionCteResponseEnable}, |
| //{OpCode::LE_READ_ANTENNA_INFORMATION, |
| //&DualModeController::LeReadAntennaInformation}, |
| //{OpCode::LE_SET_PERIODIC_ADVERTISING_RECEIVE_ENABLE, |
| //&DualModeController::LeSetPeriodicAdvertisingReceiveEnable}, |
| //{OpCode::LE_PERIODIC_ADVERTISING_SYNC_TRANSFER, |
| //&DualModeController::LePeriodicAdvertisingSyncTransfer}, |
| //{OpCode::LE_PERIODIC_ADVERTISING_SET_INFO_TRANSFER, |
| //&DualModeController::LePeriodicAdvertisingSetInfoTransfer}, |
| //{OpCode::LE_SET_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS, |
| //&DualModeController::LeSetPeriodicAdvertisingSyncTransferParameters}, |
| //{OpCode::LE_SET_DEFAULT_PERIODIC_ADVERTISING_SYNC_TRANSFER_PARAMETERS, |
| //&DualModeController::LeSetDefaultPeriodicAdvertisingSyncTransferParameters}, |
| //{OpCode::LE_GENERATE_DHKEY_V2, |
| //&DualModeController::LeGenerateDhkeyV2}, |
| //{OpCode::LE_MODIFY_SLEEP_CLOCK_ACCURACY, |
| //&DualModeController::LeModifySleepClockAccuracy}, |
| {OpCode::LE_READ_BUFFER_SIZE_V2, |
| &DualModeController::LeReadBufferSizeV2}, |
| {OpCode::LE_READ_ISO_TX_SYNC, &DualModeController::LeReadIsoTxSync}, |
| {OpCode::LE_SET_CIG_PARAMETERS, |
| &DualModeController::LeSetCigParameters}, |
| //{OpCode::LE_SET_CIG_PARAMETERS_TEST, |
| //&DualModeController::LeSetCigParametersTest}, |
| {OpCode::LE_CREATE_CIS, &DualModeController::LeCreateCis}, |
| {OpCode::LE_REMOVE_CIG, &DualModeController::LeRemoveCig}, |
| {OpCode::LE_ACCEPT_CIS_REQUEST, |
| &DualModeController::LeAcceptCisRequest}, |
| {OpCode::LE_REJECT_CIS_REQUEST, |
| &DualModeController::LeRejectCisRequest}, |
| {OpCode::LE_CREATE_BIG, &DualModeController::LeCreateBig}, |
| //{OpCode::LE_CREATE_BIG_TEST, &DualModeController::LeCreateBigTest}, |
| {OpCode::LE_TERMINATE_BIG, &DualModeController::LeTerminateBig}, |
| {OpCode::LE_BIG_CREATE_SYNC, &DualModeController::LeBigCreateSync}, |
| {OpCode::LE_BIG_TERMINATE_SYNC, |
| &DualModeController::LeBigTerminateSync}, |
| {OpCode::LE_REQUEST_PEER_SCA, &DualModeController::LeRequestPeerSca}, |
| {OpCode::LE_SETUP_ISO_DATA_PATH, |
| &DualModeController::LeSetupIsoDataPath}, |
| {OpCode::LE_REMOVE_ISO_DATA_PATH, |
| &DualModeController::LeRemoveIsoDataPath}, |
| //{OpCode::LE_ISO_TRANSMIT_TEST, |
| //&DualModeController::LeIsoTransmitTest}, |
| //{OpCode::LE_ISO_RECEIVE_TEST, &DualModeController::LeIsoReceiveTest}, |
| //{OpCode::LE_ISO_READ_TEST_COUNTERS, |
| //&DualModeController::LeIsoReadTestCounters}, |
| //{OpCode::LE_ISO_TEST_END, &DualModeController::LeIsoTestEnd}, |
| {OpCode::LE_SET_HOST_FEATURE, &DualModeController::LeSetHostFeature}, |
| //{OpCode::LE_READ_ISO_LINK_QUALITY, |
| //&DualModeController::LeReadIsoLinkQuality}, |
| //{OpCode::LE_ENHANCED_READ_TRANSMIT_POWER_LEVEL, |
| //&DualModeController::LeEnhancedReadTransmitPowerLevel}, |
| //{OpCode::LE_READ_REMOTE_TRANSMIT_POWER_LEVEL, |
| //&DualModeController::LeReadRemoteTransmitPowerLevel}, |
| //{OpCode::LE_SET_PATH_LOSS_REPORTING_PARAMETERS, |
| //&DualModeController::LeSetPathLossReportingParameters}, |
| //{OpCode::LE_SET_PATH_LOSS_REPORTING_ENABLE, |
| //&DualModeController::LeSetPathLossReportingEnable}, |
| //{OpCode::LE_SET_TRANSMIT_POWER_REPORTING_ENABLE, |
| //&DualModeController::LeSetTransmitPowerReportingEnable}, |
| //{OpCode::LE_TRANSMITTER_TEST_V4, |
| //&DualModeController::LeTransmitterTestV4}, |
| //{OpCode::LE_SET_DATA_RELATED_ADDRESS_CHANGES, |
| //&DualModeController::LeSetDataRelatedAddressChanges}, |
| //{OpCode::LE_SET_DEFAULT_SUBRATE, |
| //&DualModeController::LeSetDefaultSubrate}, |
| //{OpCode::LE_SUBRATE_REQUEST, &DualModeController::LeSubrateRequest}, |
| |
| // VENDOR |
| {OpCode(CSR_VENDOR), &DualModeController::CsrVendorCommand}, |
| {OpCode::LE_MULTI_ADVT, &DualModeController::LeMultiAdv}, |
| {OpCode::LE_ADV_FILTER, &DualModeController::LeAdvertisingFilter}, |
| {OpCode::LE_EXTENDED_SCAN_PARAMS, |
| &DualModeController::LeExtendedScanParams}, |
| {OpCode::LE_ENERGY_INFO, &DualModeController::LeEnergyInfo}, |
| {OpCode::LE_GET_VENDOR_CAPABILITIES, |
| &DualModeController::LeGetVendorCapabilities}}; |
| |
| } // namespace rootcanal |