1 // Copyright 2023 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #pragma once 16 #include <lib/fit/defer.h> 17 18 #include "pw_bluetooth_sapphire/internal/host/common/log.h" 19 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h" 20 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h" 21 #include "pw_bluetooth_sapphire/internal/host/transport/error.h" 22 23 namespace bt::hci { 24 25 // CommandHandler is a wrapper around CommandChannel that abstracts serializing 26 // & deserializing of command and event packets. Command and event types must 27 // implement methods and fields documented above each method. 28 // TODO(fxbug.dev/42135598): Types should match PDL generated packet 29 // definitions. 30 // 31 // This class does not track state regarding commands and events, so it may be 32 // used as either a temporary or saved object. 33 class CommandHandler { 34 public: CommandHandler(CommandChannel::WeakPtr channel)35 explicit CommandHandler(CommandChannel::WeakPtr channel) 36 : channel_(std::move(channel)) {} 37 38 // Wrapper around CommandChannel::SendCommand that sends a CommandT and 39 // completes on CommandT::EventT. 40 // 41 // If an event status field indicates an error, that error will be returned 42 // instead of the event. 43 // 44 // The status event of async commands will be ignored unless it is an error. 45 // 46 // CommandT must implement: 47 // std::unique_ptr<CommandPacket> Encode(); 48 // using EventT = ...; 49 // static OpCode opcode(); 50 // 51 // EventT must implement: 52 // static fit::result<bt::Error<>, EventT> Decode(const EventPacket& packet); 53 // static constexpr uint8_t kEventCode = ...; 54 template <typename CommandT> SendCommand(CommandT command,ResultCallback<typename CommandT::EventT> event_cb)55 CommandChannel::TransactionId SendCommand( 56 CommandT command, ResultCallback<typename CommandT::EventT> event_cb) { 57 // EventT should be the command complete event code. Use 58 // SendCommandFinishOnStatus to only handle the command status event. 59 static_assert(CommandT::EventT::kEventCode != 60 hci_spec::kCommandStatusEventCode); 61 BT_ASSERT(event_cb); 62 63 auto encoded = command.Encode(); 64 auto event_packet_cb = [event_cb = std::move(event_cb)]( 65 auto id, 66 const EventPacket& event_packet) mutable { 67 BT_ASSERT_MSG(event_cb, 68 "SendCommand event callback already called (opcode: %#.4x)", 69 CommandT::opcode()); 70 71 auto status = event_packet.ToResult(); 72 if (status.is_error()) { 73 event_cb(status.take_error()); 74 return; 75 } 76 77 // Ignore success status event if it is not the expected completion event. 78 if (event_packet.event_code() == hci_spec::kCommandStatusEventCode && 79 CommandT::EventT::kEventCode != hci_spec::kCommandStatusEventCode) { 80 bt_log(TRACE, 81 "hci", 82 "received success command status event (opcode: %#.4x)", 83 CommandT::opcode()); 84 return; 85 } 86 87 BT_ASSERT(event_packet.event_code() == CommandT::EventT::kEventCode); 88 89 auto event_result = CommandT::EventT::Decode(event_packet); 90 if (event_result.is_error()) { 91 bt_log(WARN, 92 "hci", 93 "Error decoding event packet (event: %#.2x, error: %s)", 94 event_packet.event_code(), 95 bt_str(event_result.error_value())); 96 event_cb(event_result.take_error()); 97 return; 98 } 99 event_cb(event_result.take_value()); 100 }; 101 return channel_->SendCommand(std::move(encoded), 102 std::move(event_packet_cb), 103 CommandT::EventT::kEventCode); 104 } 105 106 // Same as SendCommand, but completes on the command status event. 107 // The complete event WILL BE IGNORED if no event handler is registered. 108 // 109 // This is useful when the command complete event is already handled by an 110 // event handler, and you only need to handle command errors. 111 // 112 // Example: 113 // handler.AddEventHandler(fit::bind_member<&BrEdrConnectionManager::OnConnectionComplete>(this)); 114 // 115 // handler.SendCommandFinishOnStatus( 116 // CreateConnectionCommand{...}, 117 // [](auto result) { 118 // if (result.is_error()) { 119 // // Handle error 120 // return; 121 // } 122 // }); 123 template <typename CommandT> SendCommandFinishOnStatus(CommandT command,hci::ResultCallback<> status_cb)124 CommandChannel::TransactionId SendCommandFinishOnStatus( 125 CommandT command, hci::ResultCallback<> status_cb) { 126 BT_ASSERT(status_cb); 127 128 auto encoded = command.Encode(); 129 auto event_packet_cb = [status_cb = std::move(status_cb)]( 130 auto id, 131 const EventPacket& event_packet) mutable { 132 BT_ASSERT(event_packet.event_code() == hci_spec::kCommandStatusEventCode); 133 134 status_cb(event_packet.ToResult()); 135 }; 136 return channel_->SendCommand(std::move(encoded), 137 std::move(event_packet_cb), 138 hci_spec::kCommandStatusEventCode); 139 } 140 141 // Wrapper around CommandChannel::AddEventHandler that calls |handler| with an 142 // EventT. 143 // 144 // EventT must implement: 145 // static fit::result<bt::Error<>, EventT> Decode(const EventPacket& packet); 146 // static constexpr uint8_t kEventCode = ...; 147 template <typename EventT> AddEventHandler(fit::function<CommandChannel::EventCallbackResult (EventT)> handler)148 CommandChannel::EventHandlerId AddEventHandler( 149 fit::function<CommandChannel::EventCallbackResult(EventT)> handler) { 150 BT_ASSERT(handler); 151 152 auto event_packet_cb = 153 [handler = std::move(handler)](const EventPacket& event_packet) { 154 auto event_result = EventT::Decode(event_packet); 155 if (event_result.is_error()) { 156 bt_log(WARN, 157 "hci", 158 "Error decoding event packet (event: %#.2x, error: %s)", 159 event_packet.event_code(), 160 bt_str(event_result.error_value())); 161 return CommandChannel::EventCallbackResult::kContinue; 162 } 163 return handler(std::move(event_result).value()); 164 }; 165 return channel_->AddEventHandler(EventT::kEventCode, 166 std::move(event_packet_cb)); 167 } 168 169 private: 170 CommandChannel::WeakPtr channel_; 171 }; 172 173 } // namespace bt::hci 174