blob: 88f4425aac512b830460cdf72420c40da048253f [file] [edit]
// Copyright 2025 The Pigweed Authors
//
// 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
//
// https://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 "pw_bluetooth_proxy/config.h"
#if PW_BLUETOOTH_PROXY_ASYNC == 0
#include <mutex>
#include "pw_assert/check.h"
#include "pw_bluetooth_proxy/internal/generic_l2cap_channel.h"
#include "pw_bluetooth_proxy/internal/l2cap_channel.h"
#include "pw_bluetooth_proxy/internal/l2cap_channel_manager.h"
#include "pw_bluetooth_proxy/internal/l2cap_channel_manager_sync.h"
namespace pw::bluetooth::proxy::internal {
GenericL2capChannelImpl::GenericL2capChannelImpl(L2capChannel& channel)
: channel_(&channel) {
std::lock_guard lock(L2capChannelImpl::mutex());
channel_->impl_.client_ = this;
}
GenericL2capChannelImpl& GenericL2capChannelImpl::operator=(
GenericL2capChannelImpl&& other) {
if (this == &other) {
return *this;
}
std::lock_guard lock(L2capChannelImpl::mutex());
if (channel_ != nullptr) {
channel_->impl_.client_ = nullptr;
}
channel_ = std::exchange(other.channel_, nullptr);
if (channel_ != nullptr) {
channel_->impl_.client_ = this;
}
return *this;
}
GenericL2capChannelImpl::~GenericL2capChannelImpl() {
std::lock_guard lock(L2capChannelImpl::mutex());
if (channel_ != nullptr) {
channel_->impl_.client_ = nullptr;
}
}
Status GenericL2capChannelImpl::Init() { return OkStatus(); }
void GenericL2capChannelImpl::Start() {
auto result = BorrowL2capChannel(L2capChannel::State::kNew);
if (result.ok()) {
BorrowedL2capChannel borrowed = std::move(*result);
borrowed->Start();
}
}
StatusWithMultiBuf GenericL2capChannelImpl::Write(
multibuf::MultiBuf&& payload) {
auto result = BorrowL2capChannel();
if (!result.ok()) {
return {result.status(), std::move(payload)};
}
BorrowedL2capChannel borrowed = std::move(*result);
return borrowed->Write(std::move(payload));
}
Status GenericL2capChannelImpl::IsWriteAvailable() {
PW_TRY_ASSIGN(BorrowedL2capChannel borrowed, BorrowL2capChannel());
return borrowed->impl().IsWriteAvailable();
}
Status GenericL2capChannelImpl::SendAdditionalRxCredits(
uint16_t additional_rx_credits) {
PW_TRY_ASSIGN(BorrowedL2capChannel borrowed, BorrowL2capChannel());
return borrowed->SendAdditionalRxCredits(additional_rx_credits);
}
void GenericL2capChannelImpl::Stop() {
auto result = BorrowL2capChannel();
if (result.ok()) {
BorrowedL2capChannel borrowed = std::move(*result);
borrowed->Stop();
}
}
void GenericL2capChannelImpl::Close() {
auto result = BorrowL2capChannel();
if (result.ok()) {
BorrowedL2capChannel borrowed = std::move(*result);
borrowed->Close();
}
}
L2capChannel* GenericL2capChannelImpl::InternalForTesting() const {
std::lock_guard lock(L2capChannelImpl::mutex());
return channel_;
}
Result<BorrowedL2capChannel> GenericL2capChannelImpl::BorrowL2capChannel(
L2capChannel::State expected) const {
std::lock_guard lock(L2capChannelImpl::mutex());
if (channel_ == nullptr || channel_->state() != expected) {
return Status::FailedPrecondition();
}
return BorrowedL2capChannel(channel_->impl_);
}
} // namespace pw::bluetooth::proxy::internal
#endif // PW_BLUETOOTH_PROXY_ASYNC