From 06f646aec4dbce64d28bae1be6111bd833f8e79e Mon Sep 17 00:00:00 2001 From: Paul Nettle Date: Fri, 25 Aug 2017 09:30:39 -0500 Subject: Initial version 1.0 --- src/HciAdapter.h | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 src/HciAdapter.h (limited to 'src/HciAdapter.h') diff --git a/src/HciAdapter.h b/src/HciAdapter.h new file mode 100644 index 0000000..3f6c929 --- /dev/null +++ b/src/HciAdapter.h @@ -0,0 +1,138 @@ +// 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" + +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; +}; -- cgit v1.2.3