| /* |
| * Copyright (C) 2017 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 <cstring> |
| |
| #include <base/logging.h> |
| |
| #include "bdaddr.h" |
| #include "mca_api.h" |
| #include "mca_defs.h" |
| #include "mcap_test_mcl.h" |
| |
| namespace SYSTEM_BT_TOOLS_MCAP_TOOL { |
| |
| McapMcl::McapMcl(btmcap_test_interface_t* mcap_test_interface, |
| tMCA_HANDLE mcap_handle, const RawAddress& peer_bd_addr) |
| : _mdl_list() { |
| _mcap_handle = mcap_handle; |
| _mcap_test_interface = mcap_test_interface; |
| memcpy(_peer_bd_addr.address, peer_bd_addr.address, |
| sizeof(_peer_bd_addr.address)); |
| } |
| |
| bool McapMcl::Connect(uint16_t ctrl_psm, uint16_t sec_mask) { |
| tMCA_RESULT ret = _mcap_test_interface->connect_mcl( |
| _mcap_handle, _peer_bd_addr, ctrl_psm, sec_mask); |
| LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret; |
| return ret == MCA_SUCCESS; |
| } |
| |
| bool McapMcl::Disconnect() { |
| if (!IsConnected()) { |
| LOG(ERROR) << "MCL is not connected"; |
| return false; |
| } |
| tMCA_RESULT ret = _mcap_test_interface->disconnect_mcl(_mcl_handle); |
| LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret; |
| return ret == MCA_SUCCESS; |
| } |
| |
| McapMdl* McapMcl::AllocateMdl(tMCA_DEP mdep_handle, uint16_t mdl_id, |
| uint8_t dep_id, uint8_t cfg) { |
| if (!IsConnected()) { |
| LOG(ERROR) << "MCL is not connected"; |
| return nullptr; |
| } |
| if (FindMdlById(mdl_id) != nullptr) { |
| LOG(ERROR) << "mdl_id=" << mdl_id << "already exists"; |
| return nullptr; |
| } |
| if (!HasAvailableMdl()) { |
| LOG(ERROR) << "No more avaible MDL, currently " << _mdl_list.size(); |
| return nullptr; |
| } |
| _mdl_list.push_back(McapMdl(_mcap_test_interface, _mcl_handle, mdep_handle, |
| mdl_id, dep_id, cfg)); |
| return &_mdl_list[_mdl_list.size() - 1]; |
| } |
| |
| bool McapMcl::CreateMdl(tMCA_DEP mdep_handle, uint16_t data_psm, |
| uint16_t mdl_id, uint8_t peer_dep_id, uint8_t cfg, |
| bool should_connect) { |
| if (!IsConnected()) { |
| LOG(ERROR) << "MCL is not connected"; |
| return false; |
| } |
| McapMdl* mcap_mdl = FindMdlById(mdl_id); |
| if (!mcap_mdl) { |
| LOG(INFO) << "mdl_id=" << mdl_id << "does not exists, creating new one"; |
| mcap_mdl = AllocateMdl(mdep_handle, mdl_id, peer_dep_id, cfg); |
| if (!mcap_mdl) { |
| return false; |
| } |
| } |
| if (mcap_mdl->IsConnected()) { |
| LOG(ERROR) << "mdl_id=" << mdl_id << "is already connected with handle " |
| << (int)mcap_mdl->GetHandle(); |
| return false; |
| } |
| return mcap_mdl->Create(data_psm, should_connect); |
| } |
| |
| bool McapMcl::DataChannelConfig() { |
| tMCA_RESULT ret = _mcap_test_interface->data_channel_config( |
| _mcl_handle, get_test_channel_config()); |
| LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret; |
| return ret == MCA_SUCCESS; |
| } |
| |
| bool McapMcl::CreateMdlResponse(tMCA_DEP mdep_handle, uint16_t mdl_id, |
| uint8_t my_dep_id, uint8_t cfg) { |
| if (!IsConnected()) { |
| LOG(ERROR) << "MCL is not connected"; |
| return false; |
| } |
| McapMdl* mcap_mdl = FindMdlById(mdl_id); |
| if (!mcap_mdl) { |
| LOG(INFO) << "mdl_id=" << mdl_id << " does not exists, creating new one"; |
| mcap_mdl = AllocateMdl(mdep_handle, mdl_id, my_dep_id, cfg); |
| if (!mcap_mdl) { |
| LOG(ERROR) << "MDL cannot be created"; |
| return false; |
| } |
| } |
| if (mcap_mdl->IsConnected()) { |
| LOG(INFO) << "mdl_id=" << mdl_id << " is already connected with handle " |
| << (int)mcap_mdl->GetHandle() << ", updating context"; |
| mcap_mdl->UpdateContext(mdep_handle, my_dep_id, cfg); |
| } |
| return mcap_mdl->CreateResponse(); |
| } |
| |
| bool McapMcl::AbortMdl() { |
| tMCA_RESULT ret = _mcap_test_interface->abort_mdl(_mcl_handle); |
| LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret; |
| return ret == MCA_SUCCESS; |
| } |
| |
| bool McapMcl::DeleteMdl(uint16_t mdl_id) { |
| tMCA_RESULT ret = _mcap_test_interface->delete_mdl(_mcl_handle, mdl_id); |
| LOG_IF(INFO, ret != MCA_SUCCESS) << "ret=" << (int)ret; |
| return ret == MCA_SUCCESS; |
| } |
| |
| RawAddress& McapMcl::GetPeerAddress() { return _peer_bd_addr; } |
| |
| void McapMcl::SetHandle(tMCA_CL handle) { _mcl_handle = handle; } |
| |
| tMCA_CL McapMcl::GetHandle() const { return _mcl_handle; } |
| |
| void McapMcl::SetMtu(uint16_t mtu) { _control_mtu = mtu; } |
| |
| uint16_t McapMcl::GetMtu() { return _control_mtu; } |
| |
| McapMdl* McapMcl::FindMdlById(uint16_t mdl_id) { |
| for (McapMdl& mdl : _mdl_list) { |
| if (mdl.GetId() == mdl_id) { |
| return &mdl; |
| } |
| } |
| return nullptr; |
| } |
| |
| McapMdl* McapMcl::FindMdlByHandle(tMCA_DL mdl_handle) { |
| for (McapMdl& mdl : _mdl_list) { |
| if (mdl.GetHandle() == mdl_handle) { |
| return &mdl; |
| } |
| } |
| return nullptr; |
| } |
| |
| void McapMcl::RemoveAllMdl() { _mdl_list.clear(); } |
| |
| void McapMcl::RemoveMdl(uint16_t mdl_id) { |
| LOG(INFO) << "Removing MDL id " << (int)mdl_id; |
| for (std::vector<McapMdl>::iterator it = _mdl_list.begin(); |
| it != _mdl_list.end(); ++it) { |
| if (it->GetId() == mdl_id) { |
| _mdl_list.erase(it); |
| LOG(INFO) << "Removed MDL id " << (int)mdl_id; |
| return; |
| } |
| } |
| } |
| |
| void McapMcl::ResetAllMdl() { |
| for (McapMdl& mcap_mdl : _mdl_list) { |
| mcap_mdl.SetHandle(0); |
| mcap_mdl.SetMtu(0); |
| mcap_mdl.SetResponseCode(-1); |
| } |
| } |
| |
| void McapMcl::ResetMdl(uint16_t mdl_id) { |
| LOG(INFO) << "Closing MDL id " << (int)mdl_id; |
| McapMdl* mcap_mdl = FindMdlById(mdl_id); |
| if (!mcap_mdl) { |
| LOG(ERROR) << "Cannot find MDL for id " << (int)mdl_id; |
| return; |
| } |
| if (mcap_mdl->IsConnected()) { |
| LOG(ERROR) << "MDL " << (int)mdl_id << " is still connected"; |
| return; |
| } |
| mcap_mdl->SetHandle(0); |
| mcap_mdl->SetMtu(0); |
| mcap_mdl->SetResponseCode(-1); |
| } |
| |
| bool McapMcl::IsConnected() { return _mcl_handle > 0; } |
| |
| int McapMcl::ConnectedMdlCount() { |
| int count = 0; |
| for (McapMdl& mcap_mdl : _mdl_list) { |
| if (mcap_mdl.IsConnected()) { |
| count++; |
| } |
| } |
| return count; |
| } |
| |
| bool McapMcl::HasAvailableMdl() { return ConnectedMdlCount() < MCA_NUM_MDLS; } |
| |
| } // namespace SYSTEM_BT_TOOLS_MCAP_TOOL |