| // 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_sapphire/internal/connection.h" |
| |
| namespace pw::bluetooth_sapphire::internal { |
| |
| namespace { |
| // This lock has to be global rather than a member variable so that dispatcher |
| // tasks can lock the mutex before dereferencing their weak pointers. |
| pw::sync::Mutex g_connection_lock; |
| } // namespace |
| |
| pw::sync::Mutex& Connection::lock() { return g_connection_lock; } |
| |
| Connection::Connection( |
| bt::PeerId peer_id, |
| std::unique_ptr<bt::gap::LowEnergyConnectionHandle> handle, |
| pw::async::Dispatcher& dispatcher) |
| : peer_id_(peer_id), dispatcher_(dispatcher), handle_(std::move(handle)) { |
| // This is safe because the constructor is only called on the Bluetooth |
| // thread. |
| handle_->set_closed_callback([self = self_]() PW_NO_LOCK_SAFETY_ANALYSIS { |
| std::lock_guard guard(g_connection_lock); |
| if (!self.is_alive()) { |
| return; |
| } |
| // TODO: https://pwbug.dev/396449684 - Update set_closed_callback with |
| // disconnect reason. |
| self->disconnect_reason_ = DisconnectReason::kFailure; |
| std::move(self->waker_).Wake(); |
| }); |
| } |
| |
| Connection::~Connection() { |
| std::lock_guard guard(lock()); |
| // This will destroy handle_ on the Bluetooth thread. |
| Status post_status = |
| dispatcher_.Post([handle = std::move(handle_)](auto, auto) {}); |
| PW_CHECK_OK(post_status); |
| |
| weak_factory_.InvalidatePtrs(); |
| } |
| |
| async2::Poll<pw::bluetooth::low_energy::Connection2::DisconnectReason> |
| Connection::PendDisconnect(async2::Context& cx) { |
| std::lock_guard guard(lock()); |
| if (disconnect_reason_) { |
| return async2::Ready(*disconnect_reason_); |
| } |
| PW_ASYNC_STORE_WAKER(cx, waker_, "bt-disconnect"); |
| return async2::Pending(); |
| } |
| |
| pw::bluetooth::gatt::Client2* Connection::GattClient() { |
| // TODO: https://pwbug.dev/396449684 - Return Client2 |
| return nullptr; |
| } |
| |
| uint16_t Connection::AttMtu() { |
| // TODO: https://pwbug.dev/396449684 - Return actual MTU |
| return 0u; |
| } |
| |
| async2::Poll<uint16_t> Connection::PendAttMtuChange(async2::Context&) { |
| // TODO: https://pwbug.dev/396449684 - Wire up MTU change logic. |
| return async2::Pending(); |
| } |
| |
| pw::bluetooth::low_energy::Connection2::ConnectionParameters |
| Connection::Parameters() { |
| // TODO: https://pwbug.dev/396449684 - Get the actual connection parameters. |
| return pw::bluetooth::low_energy::Connection2::ConnectionParameters(); |
| } |
| |
| async2::OnceReceiver<pw::expected< |
| void, |
| pw::bluetooth::low_energy::Connection2::ConnectionParameterUpdateError>> |
| Connection::RequestParameterUpdate(RequestedConnectionParameters) { |
| // TODO: https://pwbug.dev/396449684 - Update the parameters. |
| return async2::OnceReceiver< |
| pw::expected<void, |
| pw::bluetooth::low_energy::Connection2:: |
| ConnectionParameterUpdateError>>(); |
| } |
| |
| async2::OnceReceiver<pw::Result<pw::bluetooth::low_energy::Channel::Ptr>> |
| Connection::ConnectL2cap(ConnectL2capParameters) { |
| // TODO: https://pwbug.dev/396449684 - Open an L2CAP channel. |
| return async2::OnceReceiver< |
| pw::Result<pw::bluetooth::low_energy::Channel::Ptr>>( |
| pw::Status::Unimplemented()); |
| } |
| |
| } // namespace pw::bluetooth_sapphire::internal |