| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_HCI_CONTROL_PACKETS_H_ |
| #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_HCI_CONTROL_PACKETS_H_ |
| |
| #include <endian.h> |
| #include <fbl/macros.h> |
| |
| #include <memory> |
| |
| #include "src/connectivity/bluetooth/core/bt-host/common/byte_buffer.h" |
| #include "src/connectivity/bluetooth/core/bt-host/hci/hci.h" |
| #include "src/connectivity/bluetooth/core/bt-host/hci/packet.h" |
| #include "src/connectivity/bluetooth/core/bt-host/hci/status.h" |
| |
| namespace bt { |
| namespace hci { |
| |
| using CommandPacket = Packet<CommandHeader>; |
| using EventPacket = Packet<EventHeader>; |
| |
| // Packet template specialization for HCI command packets. |
| template <> |
| class Packet<CommandHeader> : public PacketBase<CommandHeader, CommandPacket> { |
| public: |
| // Slab-allocates a new CommandPacket with the given payload size and |
| // initializes the packet's header field. |
| static std::unique_ptr<CommandPacket> New(OpCode opcode, |
| size_t payload_size = 0u); |
| |
| // Returns the HCI command opcode currently in this packet. |
| OpCode opcode() const { return le16toh(view().header().opcode); } |
| |
| protected: |
| Packet<CommandHeader>() = default; |
| |
| private: |
| // Writes the given header fields into the underlying buffer. |
| void WriteHeader(OpCode opcode); |
| }; |
| |
| // Packet template specialization for HCI event packets. |
| template <> |
| class Packet<EventHeader> : public PacketBase<EventHeader, EventPacket> { |
| public: |
| // Slab-allocates a new EventPacket with the given payload size without |
| // initializing its contents. |
| static std::unique_ptr<EventPacket> New(size_t payload_size); |
| |
| // Returns the HCI event code currently in this packet. |
| EventCode event_code() const { return view().header().event_code; } |
| |
| // If this is a CommandComplete event packet, this method returns a pointer to |
| // the beginning of the return parameter structure. If the given template type |
| // would exceed the bounds of the packet or if this packet does not represent |
| // a CommandComplete event, this method returns nullptr. |
| template <typename ReturnParams> |
| const ReturnParams* return_params() const { |
| if (event_code() != kCommandCompleteEventCode || |
| sizeof(ReturnParams) > |
| view().payload_size() - sizeof(CommandCompleteEventParams)) |
| return nullptr; |
| return reinterpret_cast<const ReturnParams*>( |
| view().payload<CommandCompleteEventParams>().return_parameters); |
| } |
| |
| // If this is a LE Meta Event packet, this method returns a pointer to the |
| // beginning of the subevent parameter structure. If the given template type |
| // would exceed the bounds of the packet or if this packet does not represent |
| // a LE Meta Event, this method returns nullptr. |
| template <typename SubeventParams> |
| const SubeventParams* le_event_params() const { |
| if (event_code() != kLEMetaEventCode || |
| sizeof(SubeventParams) > |
| view().payload_size() - sizeof(LEMetaEventParams)) |
| return nullptr; |
| return reinterpret_cast<const SubeventParams*>( |
| view().payload<LEMetaEventParams>().subevent_parameters); |
| } |
| |
| // If this is an event packet with a standard status (See Vol 2, Part D), this |
| // method returns true and populates |out_status| using the status from the |
| // event parameters. |
| // |
| // Not all events contain a status code and not all of those that do are |
| // supported by this method. Returns false for such events and |out_status| is |
| // left unmodified. |
| // |
| // NOTE: Using this method on an unsupported event packet will trigger an |
| // assertion in debug builds. If you intend to use this with a new event code, |
| // make sure to add an entry to the implementation in control_packets.cc. |
| // |
| // TODO(armansito): Add more event entries here as needed. |
| bool ToStatusCode(hci::StatusCode* out_code) const; |
| |
| // Returns a status if this event represents the result of an operation. See |
| // the documentation on ToStatusCode() as the same conditions apply to this |
| // method. Instead of a boolean, this returns a default status of type |
| // HostError::kMalformedPacket. |
| Status ToStatus() const; |
| |
| // Initializes the internal PacketView by reading the header portion of the |
| // underlying buffer. |
| void InitializeFromBuffer(); |
| |
| protected: |
| Packet<EventHeader>() = default; |
| }; |
| |
| } // namespace hci |
| } // namespace bt |
| |
| // Convenience macros to check and log any non-Success status of an event. |
| // Evaluate to true if the event status is not success. |
| #define hci_is_error(event, flag, tag, fmt...) \ |
| bt_is_error(event.ToStatus(), flag, tag, fmt) |
| |
| #endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_HCI_CONTROL_PACKETS_H_ |