group("vendor-libs") {
deps = [
- "linux:bt-vendor-linux"
+ "linux:bt-vendor-linux",
+ "test_vendor_lib:test_vendor_lib",
]
}
--- /dev/null
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+BT_DIR := $(TOP_DIR)system/bt
+
+LOCAL_SRC_FILES := \
+ src/bredr_controller.cc \
+ src/bt_vendor.cc \
+ src/command_packet.cc \
+ src/event_packet.cc \
+ src/hci_handler.cc \
+ src/hci_transport.cc \
+ src/packet.cc \
+ src/packet_stream.cc \
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+ $(BT_DIR) \
+ $(BT_DIR)/hci/include \
+ $(BT_DIR)/osi/include \
+ $(BT_DIR)/stack/include \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libchrome
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_MODULE := test-vendor
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+include $(BUILD_SHARED_LIBRARY)
--- /dev/null
+shared_library("test_vendor_lib") {
+ sources = [
+ "src/bredr_controller.cc",
+ "src/bt_vendor.cc",
+ "src/command_packet.cc",
+ "src/event_packet.cc",
+ "src/hci_handler.cc",
+ "src/hci_transport.cc",
+ "src/packet.cc",
+ "src/packet_stream.cc",
+ ]
+
+ include_dirs = [
+ "include",
+ "//",
+ # TODO(dennischeng): Ideally we should need to have the lines below for
+ # indirect includes.
+ "//osi/include",
+ "//stack/include",
+ ]
+
+ # TODO(dennischeng): Add libchrome as a dependency.
+}
+
+# TODO(dennischeng): Add a unit test target.
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+#include <unordered_map>
+
+#include <base/macros.h>
+
+namespace test_vendor_lib {
+
+// Emulates a BR/EDR controller by maintaining the link layer state machine
+// detailed in the Bluetooth Core Specification Version 4.2, Volume 2, Part B,
+// Section 8 (page 159). Provides actions corresponding to commands sent by the
+// HCI. These actions will be registered from a single global controller
+// instance as callbacks and called from the HciHandler.
+// TODO(dennischeng): Should the controller implement an interface provided by
+// the HciHandler and be used as a delegate (i.e. the HciHandler would hold a
+// controller object) instead of registering its methods as callbacks?
+class BREDRController {
+ public:
+ // Functions that operate on the global controller instance. Initialize()
+ // is called by the vendor library's Init() function to create the global
+ // controller and must be called before Get() and CleanUp().
+ // CleanUp() should be called when a call to TestVendorCleanUp() is made
+ // since the global controller should live throughout the entire time the test
+ // vendor library is in use.
+ static BREDRController* Get();
+
+ static void Initialize();
+
+ static void CleanUp();
+
+ // Controller commands. For error codes, see the Bluetooth Core Specification,
+ // Version 4.2, Volume 2, Part D (page 370).
+
+ // Resets the controller. For now, this just generates and sends a command
+ // complete event back to the HCI.
+ // Command parameters: none.
+ // Command response:
+ // Status (1 octet)
+ // 0x00: Success.
+ // 0x01-0xFF: Failed. Check error codes.
+ void HciReset(const std::vector<std::uint8_t>& args);
+
+ private:
+ // There will only be a single global instance of this class.
+ BREDRController();
+
+ // The destructor can only be indirectly accessed through the static
+ // CleanUp() method that destructs the global controller.
+ ~BREDRController() = default;
+
+ // Registers command callbacks with the HciHandler instance so that they are
+ // fired when the corresponding opcode is received from the HCI. For now, each
+ // command must be individually registered. This allows for some flexibility
+ // in which commands are made available by which controller.
+ void RegisterHandlerCallbacks();
+
+ // Maintains the commands to be registered and used in the HciHandler object.
+ // Keys are command opcodes and values are the callbacks to handle each
+ // command.
+ std::unordered_map<std::uint16_t,
+ std::function<void(const std::vector<std::uint8_t>&)>>
+ active_commands_;
+
+ // Disallow any copies of the singleton to be made.
+ DISALLOW_COPY_AND_ASSIGN(BREDRController);
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <cstdint>
+#include <vector>
+
+#include <base/macros.h>
+
+namespace test_vendor_lib {
+
+// The following is specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.1 (page 470). Command Packets begin with a 3
+// octet header formatted as follows:
+// - Opcode: 2 octets
+// - Opcode Group Field (OGF): Upper bits 10-15
+// - Opcode Command Field (OCF): Lower bits 0-9
+// - Payload size (in octets): 1 octet
+// The header is followed by the payload, which contains command specific
+// parameters and has a maximum size of 255 octets. Valid command opcodes are
+// defined in stack/include/hcidefs.h. The OGF ranges from 0x00 to 0x3F, with
+// 0x3F reserved for vendor-specific debug functions. The OCF ranges from
+// 0x0000 to 0x03FF. Note that the payload size is the size in octets of the
+// command parameters and not the number of parameters. Finally, although the
+// parameters contained in the payload are command specific (including the size
+// and number of parameters), each parameter will be an integer number of octets
+// in size.
+class CommandPacket : public Packet {
+ public:
+ CommandPacket();
+
+ ~CommandPacket() override = default;
+
+ // Returns the command opcode as defined in stack/include/hcidefs.h.
+ // See the Bluetooth Core Specification Version 4.2, Volume 2, Part E,
+ // Section 7 for more information about each HCI commands and for a listing
+ // of their specific opcodes/OGF and OCF values.
+ std::uint16_t GetOpcode() const;
+
+ // Returns the 6 bit opcode group field that specifies the general category of
+ // the command. The OGF can be one of seven values:
+ // - 0x01: Link control commands
+ // - 0x02: Link policy commands
+ // - 0x03: Controller and baseband commands
+ // - 0x04: Informational parameters commands
+ // - 0x05: Status parameters commands
+ // - 0x06: Testing commands
+ // - 0x08: Low energy controller commands
+ // The upper 2 bits will be zero filled.
+ std::uint8_t GetOGF() const;
+
+ // Returns the 10 bit opcode command field that specifies an exact command
+ // within an opcode group field. The upper 6 bits will be zero filled.
+ std::uint16_t GetOCF() const;
+
+ // Size in octets of a command packet header, which consists of a 2 octet
+ // opcode and a 1 octet payload size.
+ static const size_t kCommandHeaderSize = 3;
+
+ private:
+ // Disallow any copies of the singleton to be made.
+ DISALLOW_COPY_AND_ASSIGN(CommandPacket);
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+namespace test_vendor_lib {
+
+// The following is specified in the Bluetooth Core Specification Version 4.2,
+// Volume 2, Part E, Section 5.4.4 (page 477). Event Packets begin with a 2
+// octet header formatted as follows:
+// - Event code: 1 octet
+// - Payload size (in octets): 1 octet
+// The header is followed by the payload, which contains event specific
+// parameters and has a maximum size of 255 octets. Valid event codes are
+// listed in stack/include/hcidefs.h. They can range from 0x00 to 0xFF, with
+// 0xFF reserved for vendor specific debug events. Note the payload size
+// describes the total size of the event parameters and not the number of
+// parameters. The event parameters contained in the payload will be an integer
+// number of octets in size. Each flavor of event packet is created via a static
+// factory function that takes the event type-specific parameters and returns an
+// initialized event packet from that data.
+class EventPacket : public Packet {
+ public:
+ virtual ~EventPacket() override = default;
+
+ std::uint8_t GetEventCode() const;
+
+ // Static functions for creating event packets:
+
+ // Creates and returns a command complete event packet. See the Bluetooth
+ // Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14 (page 861)
+ // for more information about the command complete event.
+ // |num_hci_command_packets| indicates the number of HCI command packets the
+ // host can send to the controller. If |num_hci_command_packets| is 0, the
+ // controller would like to stop receiving commands from the host (to indicate
+ // readiness again, the controller sends a command complete event with
+ // |command_opcode| to 0x0000 (no op) and |num_hci_command_packets| > 1).
+ // |command_opcode| is the opcode of the command that caused this event.
+ // |return_parameters| will contain any event specific parameters that should
+ // be sent to the host.
+ static std::unique_ptr<EventPacket> CreateCommandCompleteEvent(
+ std::uint8_t num_hci_command_packets, std::uint16_t command_opcode,
+ const std::vector<std::uint8_t>& event_return_parameters);
+
+ // Size in octets of a data packet header, which consists of a 1 octet
+ // event code and a 1 octet payload size.
+ static const size_t kEventHeaderSize = 2;
+
+ private:
+ // Takes in the event parameters in |payload|. These parameters vary by event
+ // and are detailed in the Bluetooth Core Specification.
+ EventPacket(std::uint8_t event_code,
+ const std::vector<std::uint8_t>& payload);
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <cstdint>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include <base/macros.h>
+
+namespace test_vendor_lib {
+
+// Dispatches packets to the appropriate controller handler. These handlers
+// must be registered by controller objects in order for commands to be
+// processed. Unregistered commands will perform no operations. Exposes two
+// callbacks, HandleCommand() and HandleData(), to be registered with a listener
+// object and called when commands and data are sent by the host.
+class HciHandler {
+ public:
+ // Functions that operate on the global handler instance. Initialize()
+ // is called by the vendor library's Init() function to create the global
+ // handler and must be called before Get() and CleanUp().
+ // CleanUp() should be called when a call to TestVendorCleanUp() is made
+ // since the global handler should live throughout the entire time the test
+ // vendor library is in use.
+ static HciHandler* Get();
+
+ static void Initialize();
+
+ static void CleanUp();
+
+ // Callback to be fired when a command packet is received from the HCI. Takes
+ // ownership of the packet and dispatches work to the controller through the
+ // callback registered with the command's opcode. After the controller
+ // finishes processing the command and the callback returns, the command
+ // packet is destroyed.
+ void HandleCommand(std::unique_ptr<CommandPacket> command);
+
+ // Creates the mapping from the opcode to the method |callback|.
+ // |callback|, which is provided by the controller, will be fired when its
+ // command opcode is received from the HCI.
+ void RegisterControllerCallback(
+ std::uint16_t opcode,
+ std::function<void(const std::vector<std::uint8_t> args)> callback);
+
+ private:
+ // There will only be a single global instance of this class.
+ HciHandler() = default;
+
+ // The destructor can only be indirectly accessed through the static
+ // CleanUp() method that destructs the global handler.
+ ~HciHandler() = default;
+
+ // Sets the command and data callbacks for when packets are received from the
+ // HCI.
+ void RegisterTransportCallbacks();
+
+ // Disallow any copies of the singleton to be made.
+ DISALLOW_COPY_AND_ASSIGN(HciHandler);
+
+ // Controller callbacks to be executed in handlers and registered in
+ // RegisterControllerCallback().
+ std::unordered_map<std::uint16_t,
+ std::function<void(const std::vector<std::uint8_t> args)> >
+ callbacks_;
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet_stream.h"
+
+#include <functional>
+#include <memory>
+
+#include <base/macros.h>
+
+extern "C" {
+#include <sys/epoll.h>
+} // extern "C"
+
+namespace test_vendor_lib {
+
+// Manages communication channel between HCI and the controller. Listens for
+// available events from the host and receives packeted data when it is ready.
+// Also exposes a single send method for the controller to pass events back to
+// the HCI.
+// TODO(dennischeng): Create a nested delegate interface and have the HciHandler
+// subclass that interface instead of using callbacks.
+class HciTransport {
+ public:
+ // Returns the HCI's file descriptor for sending commands and data to the
+ // controller and for receiving events back.
+ int GetHciFd() const;
+
+ // Functions that operate on the global transport instance. Initialize()
+ // is called by the vendor library's Init() function to create the global
+ // transport and must be called before Get() and CleanUp().
+ // CleanUp() should be called when a call to TestVendorCleanUp() is made
+ // since the global transport should live throughout the entire time the test
+ // vendor library is in use.
+ static HciTransport* Get();
+
+ static void Initialize();
+
+ static void CleanUp();
+
+ // Creates the underlying socketpair and packet stream object. Returns true if
+ // the connection was successfully made.
+ bool Connect();
+
+ // Waits for events on the listener end of the socketpair. Fires the
+ // associated callback for each type of packet when data is received via
+ // |packet_stream_|. Returns false if an error occurs.
+ bool Listen();
+
+ // Sets the callback that is run when command packets are sent by the HCI.
+ void RegisterCommandCallback(
+ std::function<void(std::unique_ptr<CommandPacket>)> callback);
+
+ // TODO(dennischeng): Determine correct management of event object, what if
+ // write doesn't finish before destruction?
+ void SendEvent(const EventPacket& event);
+
+ private:
+ // Loops through the epoll event buffer and receives packets if they are
+ // ready. Fires the corresponding handler callback for each received packet.
+ bool ReceiveReadyPackets(const epoll_event& event_buffer,
+ int num_ready);
+
+ // Reads in a command packet and calls the handler's command ready callback,
+ // passing owernship of the command packet to the handler.
+ void ReceiveReadyCommand();
+
+ // There will only be one global instance of the HCI transport used by
+ // bt_vendor.cc and accessed via the static GetInstance() function.
+ HciTransport();
+
+ // The destructor can only be indirectly accessed through the static
+ // CleanUp() method that destructs the global transport.
+ ~HciTransport();
+
+ // Sets up the epoll instance and registers the listener fd. Returns true on
+ // success.
+ // TODO(dennischeng): import base/ and use a MessageLoopForIO for event loop.
+ bool ConfigEpoll();
+
+ // Disallow any copies of the singleton to be made.
+ DISALLOW_COPY_AND_ASSIGN(HciTransport);
+
+ // Callback executed in Listen() for command packets.
+ std::function<void(std::unique_ptr<CommandPacket>)> command_callback_;
+
+ // File descriptor for epoll instance. Closed in the HciTransport destructor.
+ int epoll_fd_;
+
+ // Used to guard against multiple calls to Connect().
+ bool connected_;
+
+ // For performing packet IO.
+ PacketStream packet_stream_;
+
+ // The two ends of the socket pair used to communicate with the HCI.
+ // |socketpair_fds_[0]| is the listener end and is closed in the PacketStream
+ // object. |socketpair_fds_[1]| is the HCI end and is closed in bt_vendor.cc.
+ int socketpair_fds_[2];
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+extern "C" {
+#include "hci/include/hci_hal.h"
+} // extern "C"
+
+namespace test_vendor_lib {
+
+// Abstract base class that manages a contiguous block of data and is
+// subclassed to provide type-specifc accessors on said data. Manages the data's
+// memory and guarantees the data's persistence for IO operations.
+class Packet {
+ public:
+ virtual ~Packet() = default;
+
+ // Returns the size in octets of the entire packet, which consists of the type
+ // octet, the header, and the payload.
+ size_t GetPacketSize() const;
+
+ const std::vector<std::uint8_t>& GetPayload() const;
+
+ std::uint8_t GetPayloadSize() const;
+
+ const std::vector<std::uint8_t>& GetHeader() const;
+
+ std::uint8_t GetHeaderSize() const;
+
+ serial_data_type_t GetType() const;
+
+ // Validates the packet by checking that the payload size in the header is
+ // accurate. If the size is not valid, returns false. Otherwise, the data in
+ // |header| and |payload| is copied into |header_| and |payload_|
+ // respectively. If an error occurs while the data is being copied, the
+ // contents of |header| and |payload| are guaranteed to be preserved. The
+ // packet object will assume ownership of the copied data for its entire
+ // lifetime.
+ bool Encode(const std::vector<std::uint8_t>& header,
+ const std::vector<std::uint8_t>& payload);
+
+ protected:
+ // Constructs an empty packet of type |type|. A call to Encode() shall be made
+ // to check and fill in the packet's data.
+ Packet(serial_data_type_t type);
+
+ private:
+ // Underlying containers for storing the actual packet, broken down into the
+ // packet header and the packet payload. Data is copied into the vectors
+ // during the constructor and becomes accessible (read only) to children
+ // through GetHeader() and GetPayload().
+ std::vector<std::uint8_t> header_;
+
+ std::vector<std::uint8_t> payload_;
+
+ // The packet type is one of DATA_TYPE_ACL, DATA_TYPE_COMMAND,
+ // DATA_TYPE_EVENT, or DATA_TYPE_SCO.
+ serial_data_type_t type_;
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#pragma once
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <cstdint>
+#include <vector>
+#include <memory>
+
+namespace test_vendor_lib {
+
+// Provides abstractions for IO with Packet objects. Used to receive commands
+// and data from the HCI and to send controller events back to the host.
+class PacketStream {
+ public:
+ // Constructs an invalid PacketStream object whose file descriptor must be set
+ // before use.
+ PacketStream();
+
+ // Closes |fd_|. Careful attention must be paid to when PacketStream objects
+ // are destructed because other objects may rely on the PacketStream's
+ // file descriptor.
+ virtual ~PacketStream();
+
+ // Reads a command packet and returns the packet back to the caller, along
+ // with the responsibility of managing the packet's memory.
+ std::unique_ptr<CommandPacket> ReceiveCommand();
+
+ // Reads and interprets a single octet as a packet type octet. Validates the
+ // type octet for correctness.
+ serial_data_type_t ReceivePacketType();
+
+ // Sends an event to the HCI. The memory management and ownership of the event
+ // is left with the caller.
+ void SendEvent(const EventPacket& event);
+
+ // Sets the file descriptor used in reading and writing. The PacketStream
+ // takes ownership of the descriptor at |fd| and closes it during destruction.
+ // This (as opposed to initializing fd_ in a constructor) helps prevent
+ // premature closing of the descriptor.
+ void SetFd(int fd);
+
+ private:
+ // Checks if |type| is in the valid range from DATA_TYPE_COMMAND to
+ // DATA_TYPE_SCO.
+ bool ValidateTypeOctet(serial_data_type_t type) const;
+
+ // Attempts to receive |num_octets_to_receive| into |buffer|, returning
+ // false if an error occurs.
+ bool ReceiveData(std::vector<std::uint8_t>& buffer,
+ size_t num_octets_to_receive);
+
+ // Attempts to send |num_octets_to_send| from |source|, returning false if an
+ // error occurs.
+ bool SendData(const std::vector<std::uint8_t>& source,
+ size_t num_octets_to_send);
+
+ // File descriptor to read from and write to. This is the descriptor given to
+ // the HCI from the HciTransport.
+ int fd_;
+};
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#define LOG_TAG "bredr_controller"
+
+#include "vendor_libs/test_vendor_lib/include/bredr_controller.h"
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+#include "vendor_libs/test_vendor_lib/include/hci_handler.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+extern "C" {
+#include "stack/include/hcidefs.h"
+#include "osi/include/log.h"
+
+#include <assert.h>
+} // extern "C"
+
+namespace {
+
+// Controller constants and packaged command return parameters.
+// All page numbers refer to the Bluetooth Core Specification, Version 4.2,
+// Volume 2, Part E, Secion 7.1.
+// TODO(dennischeng): Move this into member variables so the controller is
+// configurable.
+
+// Included in certain events to indicate the successful completion of the
+// associated command.
+const uint8_t kReturnStatusSuccess = 0;
+
+// The default number encoded in event packets to indicate to the HCI how many
+// command packets it can send to the controller.
+const uint8_t kNumHciCommandPackets = 1;
+
+// Creates a command complete event and sends it back to the HCI.
+void SendCommandComplete(uint16_t command_opcode,
+ const std::vector<uint8_t>& return_parameters) {
+ std::unique_ptr<test_vendor_lib::EventPacket> command_complete =
+ test_vendor_lib::EventPacket::CreateCommandCompleteEvent(
+ kNumHciCommandPackets, command_opcode, return_parameters);
+ // TODO(dennischeng): Should this dependency on HciTransport be removed?
+ test_vendor_lib::HciTransport::Get()->SendEvent(*command_complete);
+}
+
+// Sends a command complete event with no return parameters. This event is
+// typically sent for commands that can be completed immediately.
+void SendCommandCompleteSuccess(uint16_t command_opcode) {
+ SendCommandComplete(command_opcode, {kReturnStatusSuccess});
+}
+
+} // namespace
+
+namespace test_vendor_lib {
+
+// Global controller instance used in the vendor library.
+// TODO(dennischeng): Should this be moved to an unnamed namespace?
+BREDRController* g_controller = nullptr;
+
+// static
+BREDRController* BREDRController::Get() {
+ // Initialize should have been called already.
+ // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+ assert(g_controller);
+ return g_controller;
+}
+
+// static
+void BREDRController::Initialize() {
+ // Multiple calls to Initialize() should not be made and the HciHandler should
+ // already be initialized.
+ // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+ assert(!g_controller);
+ assert(HciHandler::Get());
+ g_controller = new BREDRController();
+ g_controller->RegisterHandlerCallbacks();
+}
+
+// static
+void BREDRController::CleanUp() {
+ delete g_controller;
+ g_controller = nullptr;
+}
+
+BREDRController::BREDRController() {
+#define SET_HANDLER(opcode, command) \
+ active_commands_[opcode] = \
+ std::bind(&BREDRController::command, this, std::placeholders::_1);
+ SET_HANDLER(HCI_RESET, HciReset);
+#undef SET_HANDLER
+}
+
+void BREDRController::RegisterHandlerCallbacks() {
+ HciHandler* handler = HciHandler::Get();
+ for (auto it = active_commands_.begin(); it != active_commands_.end(); ++it) {
+ handler->RegisterControllerCallback(it->first, it->second);
+ }
+}
+
+void BREDRController::HciReset(const std::vector<uint8_t>& /* args */) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+ SendCommandCompleteSuccess(HCI_RESET);
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#define LOG_TAG "bt_vendor"
+
+#include "hci/include/bt_vendor_lib.h"
+#include "vendor_libs/test_vendor_lib/include/bredr_controller.h"
+#include "vendor_libs/test_vendor_lib/include/hci_handler.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+#include <pthread.h>
+
+extern "C" {
+#include "osi/include/log.h"
+
+#include <assert.h>
+#include <unistd.h>
+} // extern "C"
+
+namespace {
+bt_vendor_callbacks_t* vendor_callbacks;
+
+// Wrapper for kicking off HciTransport listening on its own thread.
+void* ListenEntryPoint(void* context) {
+ while ((static_cast<test_vendor_lib::HciTransport*>(context))->Listen());
+ LOG_INFO(LOG_TAG, "HciTransport stopped listening.");
+ return NULL;
+}
+} // namespace
+
+namespace test_vendor_lib {
+
+// Initializes event handler for test device. |p_cb| are the callbacks to be
+// used by event handler. |local_bdaddr| points to the address of the Bluetooth
+// device. Returns 0 on success, -1 on error.
+static int TestVendorInitialize(const bt_vendor_callbacks_t* p_cb,
+ unsigned char* /* local_bdaddr */) {
+ LOG_INFO(LOG_TAG, "Initializing test controller.");
+
+ // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+ assert(p_cb);
+ vendor_callbacks = const_cast<bt_vendor_callbacks_t*>(p_cb);
+
+ // Initialize global objects. The order of initialization does not matter,
+ // however all global objects should be initialized before any other work is
+ // done by the vendor library.
+ test_vendor_lib::HciTransport::Initialize();
+ test_vendor_lib::HciHandler::Initialize();
+ test_vendor_lib::BREDRController::Initialize();
+
+ // Create the connection to be used for communication between the HCI and
+ // the HciTransport object.
+ HciTransport* transporter = HciTransport::Get();
+ if (!transporter->Connect()) {
+ LOG_ERROR(LOG_TAG, "Error connecting HciTransport object to HCI.");
+ return -1;
+ }
+
+ // Start HciTransport listening on its own thread.
+ pthread_t transporter_thread;
+ pthread_create(&transporter_thread, NULL, &ListenEntryPoint, transporter);
+ return 0;
+}
+
+// Vendor specific operations. |opcode| is the opcode for Bluedroid's vendor op
+// definitions. |param| points to operation specific arguments. Return value is
+// dependent on the operation invoked, or -1 on error.
+static int TestVendorOp(bt_vendor_opcode_t opcode, void* param) {
+ LOG_INFO(LOG_TAG, "Opcode received in vendor library: %d", opcode);
+
+ HciTransport* transporter = HciTransport::Get();
+ if (!transporter) {
+ LOG_ERROR(LOG_TAG, "HciTransport was not initialized");
+ return -1;
+ }
+
+ switch (opcode) {
+ case BT_VND_OP_POWER_CTRL: {
+ LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_POWER_CTRL");
+ int* state = static_cast<int*>(param);
+ if (*state == BT_VND_PWR_OFF) {
+ LOG_INFO(LOG_TAG, "Turning Bluetooth off.");
+ } else if (*state == BT_VND_PWR_ON) {
+ LOG_INFO(LOG_TAG, "Turning Bluetooth on.");
+ }
+ return 0;
+ }
+
+ // Give the HCI its fd to communicate with the HciTransport.
+ case BT_VND_OP_USERIAL_OPEN: {
+ LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_USERIAL_OPEN");
+ int* transporter_fd = static_cast<int*>(param);
+ transporter_fd[0] = transporter->GetHciFd();
+ LOG_INFO(LOG_TAG, "Setting HCI's fd to: %d", transporter_fd[0]);
+ return 1;
+ }
+
+ // Close the HCI's file descriptor.
+ case BT_VND_OP_USERIAL_CLOSE:
+ LOG_INFO(LOG_TAG, "Doing op: BT_VND_OP_USERIAL_CLOSE");
+ LOG_INFO(LOG_TAG, "Closing HCI's fd (fd: %d)", transporter->GetHciFd());
+ close(transporter->GetHciFd());
+ return 1;
+
+ case BT_VND_OP_FW_CFG:
+ LOG_INFO(LOG_TAG, "Unsupported op: BT_VND_OP_FW_CFG");
+ vendor_callbacks->fwcfg_cb(BT_VND_OP_RESULT_FAIL);
+ return -1;
+
+ default:
+ LOG_INFO(LOG_TAG, "Op not recognized.");
+ return -1;
+ }
+ return 0;
+}
+
+// Closes the vendor interface and destroys global objects.
+static void TestVendorCleanUp(void) {
+ LOG_INFO(LOG_TAG, "Cleaning up vendor library.");
+ test_vendor_lib::BREDRController::CleanUp();
+ test_vendor_lib::HciHandler::CleanUp();
+ test_vendor_lib::HciTransport::CleanUp();
+}
+
+} // namespace test_vendor_lib
+
+// Entry point of DLib.
+const bt_vendor_interface_t BLUETOOTH_VENDOR_LIB_INTERFACE = {
+ sizeof(bt_vendor_interface_t),
+ test_vendor_lib::TestVendorInitialize,
+ test_vendor_lib::TestVendorOp,
+ test_vendor_lib::TestVendorCleanUp
+};
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#define LOG_TAG "command_packet"
+
+#include "vendor_libs/test_vendor_lib/include/command_packet.h"
+
+extern "C" {
+#include "hci/include/hci_hal.h"
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+#include <assert.h>
+} // extern "C"
+
+namespace test_vendor_lib {
+
+CommandPacket::CommandPacket() : Packet(DATA_TYPE_COMMAND) {}
+
+uint16_t CommandPacket::GetOpcode() const {
+ return 0 | (GetHeader()[0] | (GetHeader()[1] << 8));
+}
+
+uint8_t CommandPacket::GetOGF() const {
+ return HCI_OGF(GetOpcode());
+}
+
+uint16_t CommandPacket::GetOCF() const {
+ return HCI_OCF(GetOpcode());
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#define LOG_TAG "event_packet"
+
+#include "vendor_libs/test_vendor_lib/include/event_packet.h"
+
+extern "C" {
+#include "osi/include/log.h"
+#include "stack/include/hcidefs.h"
+
+#include <assert.h>
+} // extern "C"
+
+namespace test_vendor_lib {
+
+EventPacket::EventPacket(uint8_t event_code,
+ const std::vector<uint8_t>& payload)
+ : Packet(DATA_TYPE_EVENT) {
+ Encode({event_code, static_cast<uint8_t>(payload.size())}, payload);
+}
+
+uint8_t EventPacket::GetEventCode() const {
+ return GetHeader()[0];
+}
+
+// static
+std::unique_ptr<EventPacket> EventPacket::CreateCommandCompleteEvent(
+ uint8_t num_hci_command_packets, uint16_t command_opcode,
+ const std::vector<uint8_t>& event_return_parameters) {
+ size_t payload_size = sizeof(num_hci_command_packets) +
+ sizeof(command_opcode) + event_return_parameters.size();
+
+ std::vector<uint8_t> payload;
+ payload.reserve(payload_size);
+ payload.push_back(num_hci_command_packets);
+ payload.push_back(command_opcode);
+ payload.push_back(command_opcode >> 8);
+ std::copy(event_return_parameters.begin(), event_return_parameters.end(),
+ std::back_inserter(payload));
+
+ return std::unique_ptr<EventPacket>(
+ new EventPacket(HCI_COMMAND_COMPLETE_EVT, payload));
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#define LOG_TAG "hci_handler"
+
+#include "vendor_libs/test_vendor_lib/include/hci_handler.h"
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+extern "C" {
+#include "osi/include/log.h"
+
+#include <assert.h>
+} // extern "C"
+
+namespace test_vendor_lib {
+
+// Global HciHandler instance used in the vendor library.
+// TODO(dennischeng): Should this be moved to an unnamed namespace?
+HciHandler* g_handler = nullptr;
+
+void HciHandler::RegisterTransportCallbacks() {
+ HciTransport* transporter = HciTransport::Get();
+ // Register the command packet callback with the HciTransport.
+ transporter->RegisterCommandCallback(
+ std::bind(&HciHandler::HandleCommand, this, std::placeholders::_1));
+}
+
+// static
+HciHandler* HciHandler::Get() {
+ // Initialize should have been called already.
+ // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+ assert(g_handler);
+ return g_handler;
+}
+
+// static
+void HciHandler::Initialize() {
+ // Multiple calls to Initialize() should not be made and the HciTransport
+ // should already be initialized.
+ // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+ assert(!g_handler);
+ assert(HciTransport::Get());
+ g_handler = new HciHandler();
+ g_handler->RegisterTransportCallbacks();
+}
+
+// static
+void HciHandler::CleanUp() {
+ delete g_handler;
+ g_handler = nullptr;
+}
+
+void HciHandler::HandleCommand(std::unique_ptr<CommandPacket> command) {
+ uint16_t opcode = command->GetOpcode();
+ LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode,
+ command->GetOGF(), command->GetOCF());
+
+ // The command hasn't been registered with the handler yet. There is nothing
+ // to do.
+ if (callbacks_.count(opcode) == 0) {
+ return;
+ }
+ std::function<void(const std::vector<uint8_t> args)> callback =
+ callbacks_[opcode];
+ callback(command->GetPayload());
+}
+
+void HciHandler::RegisterControllerCallback(
+ uint16_t opcode,
+ std::function<void(const std::vector<uint8_t> args)> callback) {
+ callbacks_[opcode] = callback;
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#define LOG_TAG "hci_transport"
+
+#include "vendor_libs/test_vendor_lib/include/hci_transport.h"
+
+extern "C" {
+#include "stack/include/hcidefs.h"
+#include "osi/include/log.h"
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+} // extern "C"
+
+namespace {
+// The maximum number of events in the epoll event buffer.
+const int kMaxEpollEvents = 10;
+} // namespace
+
+namespace test_vendor_lib {
+
+// Global HciTransport instance used in the vendor library.
+// TODO(dennischeng): Should this be moved to an unnamed namespace?
+HciTransport* g_transporter = nullptr;
+
+HciTransport::HciTransport() : epoll_fd_(-1), connected_(false) {}
+
+HciTransport::~HciTransport() {
+ close(epoll_fd_);
+}
+
+bool HciTransport::ConfigEpoll() {
+ epoll_fd_ = epoll_create1(EPOLL_CLOEXEC);
+ epoll_event event;
+ event.events = EPOLLIN;
+ event.data.fd = socketpair_fds_[0];
+ return epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, socketpair_fds_[0], &event) >= 0;
+}
+
+int HciTransport::GetHciFd() const {
+ return socketpair_fds_[1];
+}
+
+// static
+HciTransport* HciTransport::Get() {
+ // Initialize should have been called already.
+ // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+ assert(g_transporter);
+ return g_transporter;
+}
+
+// static
+void HciTransport::Initialize() {
+ // Multiple calls to Initialize should not be made.
+ // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+ assert(!g_transporter);
+ g_transporter = new HciTransport();
+}
+
+// static
+void HciTransport::CleanUp() {
+ delete g_transporter;
+ g_transporter = nullptr;
+}
+
+bool HciTransport::Connect() {
+ if (connected_) {
+ LOG_ERROR(LOG_TAG, "Error: transporter is already connected.");
+ return false;
+ }
+
+ // TODO(dennischeng): Use SOCK_SEQPACKET here.
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, socketpair_fds_) < 0) {
+ LOG_ERROR(LOG_TAG, "Error: creating socketpair in HciTransport.");
+ return false;
+ }
+
+ // Set the descriptor for the packet stream object. |packet_stream_| will take
+ // ownership of the descriptor.
+ packet_stream_.SetFd(socketpair_fds_[0]);
+
+ // Initialize epoll instance and set the file descriptor to listen on.
+ if (ConfigEpoll() < 0) {
+ LOG_ERROR(LOG_TAG, "Error: registering hci listener with epoll instance.");
+ return false;
+ }
+
+ connected_ = true;
+ return true;
+}
+
+bool HciTransport::Listen() {
+ epoll_event event_buffer[kMaxEpollEvents];
+ int num_ready;
+
+ // Check for ready events.
+ if ((num_ready = epoll_wait(epoll_fd_, event_buffer, kMaxEpollEvents, -1)) <
+ 0) {
+ LOG_ERROR(LOG_TAG, "Error: epoll wait.");
+ return false;
+ }
+
+ return ReceiveReadyPackets(*event_buffer, num_ready);
+}
+
+bool HciTransport::ReceiveReadyPackets(const epoll_event& event_buffer,
+ int num_ready) {
+ for (int i = 0; i < num_ready; ++i) {
+ // Event has data ready to be read.
+ if ((&event_buffer)[i].events & EPOLLIN) {
+ LOG_INFO(LOG_TAG, "Event ready in HciTransport.");
+ serial_data_type_t packet_type = packet_stream_.ReceivePacketType();
+
+ switch (packet_type) {
+ case (DATA_TYPE_COMMAND): {
+ ReceiveReadyCommand();
+ return true;
+ }
+
+ case (DATA_TYPE_ACL): {
+ LOG_INFO(LOG_TAG, "ACL data packets not currently supported.");
+ return true;
+ }
+
+ case (DATA_TYPE_SCO): {
+ LOG_INFO(LOG_TAG, "SCO data packets not currently supported.");
+ return true;
+ }
+
+ // TODO(dennischeng): Add debug level assert here.
+ default: {
+ LOG_INFO(LOG_TAG,
+ "Error received an invalid packet type from the HCI.");
+ return false;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void HciTransport::ReceiveReadyCommand() {
+ std::unique_ptr<CommandPacket> command =
+ packet_stream_.ReceiveCommand();
+ command_callback_(std::move(command));
+}
+
+void HciTransport::RegisterCommandCallback(
+ std::function<void(std::unique_ptr<CommandPacket>)> callback) {
+ command_callback_ = callback;
+}
+
+void HciTransport::SendEvent(const EventPacket& event) {
+ packet_stream_.SendEvent(event);
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#define LOG_TAG "packet"
+
+#include "vendor_libs/test_vendor_lib/include/packet.h"
+
+#include <algorithm>
+
+extern "C" {
+#include "osi/include/log.h"
+} // extern "C"
+
+namespace test_vendor_lib {
+
+Packet::Packet(serial_data_type_t type) : type_(type) {}
+
+bool Packet::Encode(const std::vector<uint8_t>& header,
+ const std::vector<uint8_t>& payload) {
+ if (header.back() != payload.size()) {
+ return false;
+ }
+ header_ = header;
+ payload_ = payload;
+ return true;
+}
+
+const std::vector<uint8_t>& Packet::GetHeader() const {
+ // Every packet must have a header.
+ assert(GetHeaderSize() > 0);
+ return header_;
+}
+
+uint8_t Packet::GetHeaderSize() const {
+ return header_.size();
+}
+
+size_t Packet::GetPacketSize() const {
+ return header_.size() + payload_.size() + sizeof(type_);
+}
+
+const std::vector<uint8_t>& Packet::GetPayload() const {
+ return payload_;
+}
+
+uint8_t Packet::GetPayloadSize() const {
+ return payload_.size();
+}
+
+serial_data_type_t Packet::GetType() const {
+ return type_;
+}
+
+} // namespace test_vendor_lib
--- /dev/null
+//
+// Copyright 2015 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.
+//
+
+#define LOG_TAG "packet_stream"
+
+#include "vendor_libs/test_vendor_lib/include/packet_stream.h"
+
+extern "C" {
+#include "osi/include/log.h"
+
+#include <errno.h>
+#include <unistd.h>
+} // extern "C"
+
+namespace test_vendor_lib {
+
+PacketStream::PacketStream() : fd_(-1) {}
+
+PacketStream::~PacketStream() {
+ close(fd_);
+}
+
+std::unique_ptr<CommandPacket> PacketStream::ReceiveCommand() {
+ std::vector<uint8_t> header;
+ if (!ReceiveData(header, CommandPacket::kCommandHeaderSize)) {
+ LOG_ERROR(LOG_TAG, "Error: receiving command header.");
+ return std::unique_ptr<CommandPacket>(nullptr);
+ }
+ std::vector<uint8_t> payload;
+ if (!ReceiveData(payload, header.back())) {
+ LOG_ERROR(LOG_TAG, "Error: receiving command payload.");
+ return std::unique_ptr<CommandPacket>(nullptr);
+ }
+ std::unique_ptr<CommandPacket> command(new CommandPacket());
+ if (!command->Encode(header, payload)) {
+ LOG_ERROR(LOG_TAG, "Error: encoding command packet.");
+ return std::unique_ptr<CommandPacket>(nullptr);
+ }
+ return command;
+}
+
+serial_data_type_t PacketStream::ReceivePacketType() {
+ LOG_INFO(LOG_TAG, "Receiving packet type.");
+
+ std::vector<uint8_t> raw_type_octet;
+ if (!ReceiveData(raw_type_octet, 1)) {
+ // TODO(dennischeng): Proper error handling.
+ LOG_ERROR(LOG_TAG, "Error: Could not receive packet type.");
+ }
+
+ // Check that the type octet received is in the valid range, i.e. the packet
+ // must be a command or data.
+ serial_data_type_t type = static_cast<serial_data_type_t>(raw_type_octet[0]);
+ if (!ValidateTypeOctet(type)) {
+ // TODO(dennischeng): Proper error handling.
+ LOG_ERROR(LOG_TAG, "Error: Received invalid packet type.");
+ }
+
+ return type;
+}
+
+void PacketStream::SendEvent(const EventPacket& event) {
+ LOG_INFO(LOG_TAG, "Sending event with event code: 0x%04X",
+ event.GetEventCode());
+ LOG_INFO(LOG_TAG, "Sending event with size: %zu octets",
+ event.GetPacketSize());
+
+ // TODO(dennischeng): Decide if three separate writes is necessary here.
+ if (!SendData({event.GetType()}, 1)) {
+ // TODO(dennischeng): Proper error handling.
+ LOG_ERROR(LOG_TAG, "Error: Could not send event type.");
+ return;
+ }
+ if (!SendData(event.GetHeader(), event.GetHeaderSize())) {
+ // TODO(dennischeng): Proper error handling.
+ LOG_ERROR(LOG_TAG, "Error: Could not send event header.");
+ return;
+ }
+ if (!SendData(event.GetPayload(), event.GetPayloadSize())) {
+ // TODO(dennischeng): Proper error handling.
+ LOG_ERROR(LOG_TAG, "Error: Could not send event payload.");
+ return;
+ }
+ LOG_INFO(LOG_TAG, "Event sent.");
+}
+
+void PacketStream::SetFd(int fd) {
+ if (fd >= 0) {
+ fd_ = fd;
+ }
+}
+
+bool PacketStream::ValidateTypeOctet(serial_data_type_t type) const {
+ LOG_INFO(LOG_TAG, "Signal octet is 0x%02X.", type);
+ // The only types of packets that should be received from the HCI are command
+ // packets and data packets.
+ return (type >= DATA_TYPE_COMMAND) && (type <= DATA_TYPE_SCO);
+}
+
+bool PacketStream::ReceiveData(std::vector<uint8_t>& buffer,
+ size_t num_octets_to_receive) {
+ buffer.resize(num_octets_to_receive);
+ size_t octets_remaining = num_octets_to_receive;
+ do {
+ int num_octets_received = read(
+ fd_,
+ &buffer[num_octets_to_receive - octets_remaining],
+ octets_remaining);
+ if (num_octets_received < 0) {
+ return false;
+ }
+ octets_remaining -= num_octets_received;
+ } while (octets_remaining > 0);
+ return true;
+}
+
+bool PacketStream::SendData(const std::vector<uint8_t>& source,
+ size_t num_octets_to_send) {
+ // TODO(dennischeng): use CHECK and DCHECK when libbase is imported.
+ assert(source.size() >= num_octets_to_send);
+ size_t octets_remaining = num_octets_to_send;
+ do {
+ int num_octets_sent = write(
+ fd_, &source[num_octets_to_send - octets_remaining], octets_remaining);
+ if (num_octets_sent < 0) {
+ return false;
+ }
+ octets_remaining -= num_octets_sent;
+ } while (octets_remaining > 0);
+ return true;
+}
+
+} // namespace test_vendor_lib