#ifndef BLUETOOTH_H #define BLUETOOTH_H #include #include #include #include #include "ByteBuffer.h" namespace trygvis { namespace bluetooth { using namespace std; struct SpecUuid { public: SpecUuid(uint16_t value) : value(value) { } uint16_t value; }; namespace uuids { const SpecUuid PRIMARY_SERVICE = SpecUuid(0x2800); const SpecUuid SECONDARY_SERVICE = SpecUuid(0x2801); const SpecUuid CHARACTERISTIC = SpecUuid(0x2803); } class BluetoothAdapter; class BluetoothDevice; class BluetoothGattService; class BluetoothGattCharacteristic; class BluetoothException : public runtime_error { public: BluetoothException(const BluetoothAdapter *adapter, string const &what) : runtime_error(what), adapter(adapter), device(nullptr) { } BluetoothException(const BluetoothDevice *device, string const &what) : runtime_error(what), adapter(nullptr), device(device) { } BluetoothException(string const &what) : runtime_error(what), adapter(nullptr), device(nullptr) { } const BluetoothAdapter *adapter; const BluetoothDevice *device; }; class Mac { public: Mac(uint8_t _0, uint8_t _1, uint8_t _2, uint8_t _3, uint8_t _4, uint8_t _5) { bytes[0] = _0; bytes[1] = _1; bytes[2] = _2; bytes[3] = _3; bytes[4] = _4; bytes[5] = _5; }; string str() const; bool operator==(Mac &other) const; bool operator!=(Mac &other) const; void copy(uint8_t &_0, uint8_t &_1, uint8_t &_2, uint8_t &_3, uint8_t &_4, uint8_t &_5) const; static Mac parseMac(string s); friend bool operator<(const Mac &a, const Mac &b); private: uint8_t bytes[6]; }; class BluetoothGattCharacteristic { public: virtual ~BluetoothGattCharacteristic() { }; virtual BluetoothGattService &getService() const = 0; virtual uint16_t getHandle() const = 0; virtual const boost::uuids::uuid getUuid() const = 0; virtual uint8_t getProperties() const = 0; virtual uint16_t getValueHandle() const = 0; }; class BluetoothGattService { public: virtual ~BluetoothGattService() { }; virtual BluetoothDevice &getDevice() const = 0; virtual boost::uuids::uuid getUuid() const = 0; virtual uint16_t getHandle() const = 0; virtual uint16_t getEndGroupHandle() const = 0; virtual const vector getCharacteristics() const = 0; virtual void addCharacteristic(BluetoothGattCharacteristic *characteristic) = 0; virtual const boost::optional findCharacteristic(boost::uuids::uuid uuid) const = 0; }; class BluetoothGatt { public: BluetoothGatt(); virtual ~BluetoothGatt(); virtual BluetoothDevice &getDevice() const = 0; virtual bool isConnected() const = 0; virtual void writeValue(const BluetoothGattCharacteristic &c, const ByteBuffer &bytes) = 0; virtual ByteBuffer readValue(const BluetoothGattCharacteristic &c) = 0; virtual void discoverServices() = 0; virtual const vector getServices() const = 0; virtual const boost::optional findService(boost::uuids::uuid uuid) const = 0; }; class BluetoothDevice { public: BluetoothDevice(); virtual ~BluetoothDevice(); virtual Mac const &getMac() = 0; virtual BluetoothAdapter &getAdapter() = 0; virtual shared_ptr connectGatt() = 0; }; class BluetoothAdapter { public: virtual void startScan() = 0; virtual void stopScan() = 0; virtual void runScan(void (callback)(BluetoothDevice &device)) = 0; virtual BluetoothDevice &getDevice(Mac &mac) = 0; protected: BluetoothAdapter(); virtual ~BluetoothAdapter(); }; /** * Right this is only RAII support to properly call shutdown(). * * TODO: move getAdapter() here. Make this control all shutdowns. */ class BluetoothSystem { public: BluetoothSystem(); ~BluetoothSystem(); }; enum AttPduType { ERROR = 0x00, INVALID_HANDLE = 0x01, READ_BY_TYPE_REQ = 0x08, READ_BY_TYPE_RES = 0x09, READ_REQ = 0x0a, READ_RES = 0x0b, READ_BY_GROUP_TYPE_REQ = 0x10, READ_BY_GROUP_TYPE_RES = 0x11, WRITE_REQ = 0x12, WRITE_RES = 0x13, }; class AttributeData; class AttPdu { public: AttPdu(ByteBuffer &bytes); AttPdu(ByteBuffer &bytes, AttPduType type); AttPduType getType(); static vector parseReadByGroupType(ByteBuffer &bytes); static vector parseReadByType(ByteBuffer &bytes); static void parseRead(ByteBuffer &bytes); static void parseWrite(ByteBuffer &bytes); static void makeReadByGroupType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, SpecUuid uuid); static void makeReadByType(ByteBuffer &bytes, uint16_t startHandle, uint16_t endHandle, SpecUuid uuid); static void makeRead(ByteBuffer &bytes, uint16_t handle); static void makeWrite(ByteBuffer &req, uint16_t handle, const ByteBuffer &bytes); private: static void checkType(ByteBuffer &bytes, AttPduType type); static vector parse(ByteBuffer &bytes, AttPduType type); ByteBuffer &bytes; }; class AttributeData { public: ~AttributeData(); static AttributeData fromByteBuffer(ByteBuffer &value); const uint16_t handle; ByteBuffer value; private: AttributeData(uint16_t handle, ByteBuffer value); }; BluetoothAdapter &getAdapter(int hciDevice); void shutdown(); boost::uuids::uuid makeUuid(const boost::uuids::uuid base, uint8_t a, uint8_t b); } } #endif