// Copyright 2017 Paul Nettle. // // This file is part of Gobbledegook. // // Gobbledegook is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Gobbledegook is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Gobbledegook. If not, see . // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // >> // >>> INSIDE THIS FILE // >> // // Protocol-level code for the Bluetooth Management API, which is used to configure the Bluetooth adapter // // >> // >>> DISCUSSION // >> // // This class is intended for use by `Mgmt` (see Mgmt.cpp). // // See the discussion at the top of HciAdapter.cpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #pragma once #include #include #include "HciSocket.h" #include "Utils.h" namespace ggk { class HciAdapter { public: struct Header { uint16_t code; uint16_t controllerId; uint16_t dataSize; void toNetwork() { code = Utils::endianToHci(code); controllerId = Utils::endianToHci(controllerId); dataSize = Utils::endianToHci(dataSize); } void toHost() { code = Utils::endianToHost(code); controllerId = Utils::endianToHost(controllerId); dataSize = Utils::endianToHost(dataSize); } } __attribute__((packed)); struct ResponseEvent { Header header; uint16_t commandCode; uint8_t status; void toNetwork() { header.toNetwork(); commandCode = Utils::endianToHci(commandCode); } void toHost() { header.toHost(); commandCode = Utils::endianToHost(commandCode); } } __attribute__((packed)); // Connects the HCI socket if a connection does not already exist // // If a connection already exists, this method will do nothing and return true. // // Note that it shouldn't be necessary to connect manually; any action requiring a connection will automatically connect // // Returns true if the HCI socket is connected (either via a new connection or an existing one), otherwise false bool connect(); // Returns true if connected to the HCI socket, otherwise false // // Note that it shouldn't be necessary to connect manually; any action requiring a connection will automatically connect bool isConnected() const; // Disconnects from the HCI Socket // // If the connection is not connected, this method will do nothing. // // It isn't necessary to disconnect manually; the HCI socket will get disocnnected automatically upon destruction void disconnect(); // Sends a command over the HCI socket // // If the HCI socket is not connected, it will auto-connect prior to sending the command. In the case of a failed auto-connect, // a failure is returned. // // Returns true on success, otherwise false bool sendCommand(Header &request, ResponseEvent &response, int responseLen); private: // Reads a response from the HCI socket // // Responses are generally triggered by sending commands (see `sendCommand`) but not always. In HCI parlance, a response is // actually an event. Performing commands triggers events. There is not always a 1:1 ratio betwee command and event, and a // command may trigger different events based on the result of the command. // // Unlike the other methods in this class, this method does not auto-connect, as this method is private and can only be called // from methods that have alreay auto-connected. bool readResponse(uint16_t commandCode, ResponseEvent &response, size_t responseLen) const; // Filter out events that we aren't interested in // // NOTE: We're just dipping our toe into the HCI stuff here, so we only care about command complete and status events. This // isn't the most robust way to do things, but it is effective. bool filterAndValidateEvents(uint16_t commandCode, std::vector &buffer) const; // Our HCI Socket, which allows us to talk directly to the kernel HciSocket hciSocket; }; }; // namespace ggk