Line data Source code
1 : #pragma once 2 : 3 : /** 4 : * @file 5 : * Type definitions and callback interfaces for communication between the 6 : * low-level BLE stacks and higher-level MIDI BLE backends. 7 : */ 8 : 9 : #include <Settings/NamespaceSettings.hpp> 10 : 11 : #include "Util/compat.hpp" 12 : 13 : #include <cstddef> 14 : #include <cstdint> 15 : 16 : BEGIN_CS_NAMESPACE 17 : 18 : /// Represents a handle to the connection to another device. 19 : struct BLEConnectionHandle { 20 : uint16_t conn = 0xFFFF; 21 : explicit operator bool() const { return conn != 0xFFFF; } 22 : 23 : #if __cplusplus < 201402L 24 : BLEConnectionHandle() = default; 25 : BLEConnectionHandle(uint16_t conn) : conn {conn} {} 26 : #endif 27 : }; 28 : 29 : /// Represents a handle to a local GATT characteristic. 30 : struct BLECharacteristicHandle { 31 : uint16_t characteristic = 0xFFFF; 32 : explicit operator bool() const { return characteristic != 0xFFFF; } 33 : 34 : #if __cplusplus < 201402L 35 : BLECharacteristicHandle() = default; 36 : BLECharacteristicHandle(uint16_t characteristic) 37 : : characteristic {characteristic} {} 38 : #endif 39 : }; 40 : 41 : /// Non-owning, std::span-style read-only view of BLE data. 42 : struct BLEDataView { 43 : const uint8_t *data = nullptr; 44 : uint16_t length = 0; 45 30 : explicit operator bool() const { return length > 0; } 46 : 47 : #if __cplusplus < 201402L 48 : BLEDataView() = default; 49 : BLEDataView(const uint8_t *data, uint16_t length) 50 : : data {data}, length {length} {} 51 : #endif 52 : }; 53 : 54 : /// Describes a byte buffer containing (part of) a BLE packet. 55 : /// Packets can be stored across multiple buffers, in which case the first 56 : /// first buffer has type `Packet` and subsequent buffers of the same packet 57 : /// have the type `Continuation`. 58 : enum class BLEDataType : uint8_t { 59 : None = 0, ///< No buffers available. 60 : Packet, ///< Buffer contains the start of a BLE packet. 61 : Continuation, ///< Buffer contains a chunk of a BLE packet. 62 : }; 63 : 64 : /// Callable that returns the next chunk of data from a BLE packet when called. 65 : /// Uses type erasure with a static buffer (no dynamic memory allocations). 66 : class BLEDataGenerator { 67 : public: 68 : /// Get the next chunk of data from the BLE packet. 69 : /// Returns a chunk of size zero to indicate completion. 70 : /// @pre This wrapper is not empty. 71 : /// @pre There is still data available. Calling this function again after 72 : /// the previous call returned an empty chunk is not allowed. 73 : BLEDataView operator()(); 74 : /// Release the resources of the underlying data generator. 75 : void clear(); 76 : /// Check if this wrapper contains an underlying data generator. 77 : explicit operator bool() const { return instance; } 78 : 79 : /// Create an empty BLEDataGenerator. 80 : BLEDataGenerator() = default; 81 : /// Store a callable of type @p T and initialize it by @p args. 82 : template <class T, class... Args> 83 : BLEDataGenerator(compat::in_place_type_t<T>, Args &&...args); 84 : /// Store a callable of type @p T (with cv qualifiers and references 85 : /// removed) and initialize it by forwarding @p t. 86 : template <class T> 87 : BLEDataGenerator(compat::in_place_t, T &&t); 88 : BLEDataGenerator(const BLEDataGenerator &) = delete; 89 : BLEDataGenerator &operator=(const BLEDataGenerator &) = delete; 90 : BLEDataGenerator(BLEDataGenerator &&other) noexcept; 91 : BLEDataGenerator &operator=(BLEDataGenerator &&other) noexcept; 92 15 : ~BLEDataGenerator() { clear(); } 93 : 94 : private: 95 : /// Type-erased interface. 96 : struct Iface; 97 : /// Specific class that implements the type-erased interface, wrapping the 98 : /// type @p T. 99 : template <class T> 100 : struct Impl; 101 : /// Alignment of the buffer to allocate the underlying data generator. 102 : using buffer_align_t = max_align_t; 103 : /// Size of the buffer to allocate the underlying data generator. 104 : static constexpr size_t capacity = 4 * sizeof(void *) - sizeof(Iface *); 105 : /// Buffer used for allocation of the underlying data generator. 106 : alignas(buffer_align_t) compat::byte storage[capacity]; 107 : //// Type-erased pointer to the underlying data generator in @ref storage. 108 : Iface *instance = nullptr; 109 : }; 110 : 111 : /// Should a buffer of BLEData be consumed immediately inside of the callback, 112 : /// or can we hold on to it and process it later? 113 : enum class BLEDataLifetime { 114 : /// Buffer is valid only during the callback. Do not keep any pointers to it. 115 : ConsumeImmediately, 116 : /// Buffer is valid for as long as the owning @ref BLEDataGenerator is not 117 : /// resumed or destroyed. 118 : Managed, 119 : }; 120 : 121 : /// Defines the interface for callback functions registered by the low-level 122 : /// BLE code. 123 : /// @warning These functions may be called from different tasks/threads or 124 : /// low-priority interrupt handlers. You cannot take locks, and you 125 : /// need to synchronize appropriately (e.g. using `std::atomic` or 126 : /// by using critical sections). 127 : class MIDIBLEInstance { 128 : public: 129 29 : virtual ~MIDIBLEInstance() = default; 130 : /// Called by the BLE stack when a connection is established. 131 : virtual void handleConnect(BLEConnectionHandle conn_handle) = 0; 132 : /// Called by the BLE stack when a connection is terminated. 133 : virtual void handleDisconnect(BLEConnectionHandle conn_handle) = 0; 134 : /// Called by the BLE stack when the maximum transmission unit for the 135 : /// connection changes. 136 : virtual void handleMTU(BLEConnectionHandle conn_handle, uint16_t mtu) = 0; 137 : /// Called by the BLE stack when the central subscribes to receive 138 : /// notifications for the MIDI GATT characteristic. 139 : virtual void handleSubscribe(BLEConnectionHandle conn_handle, 140 : BLECharacteristicHandle char_handle, 141 : bool notify) = 0; 142 : /// Called by the BLE stack when the central writes data to the MIDI GATT 143 : /// characteristic. 144 : virtual void handleData(BLEConnectionHandle conn_handle, 145 : BLEDataGenerator &&data, 146 : BLEDataLifetime lifetime) = 0; 147 : }; 148 : 149 : /// Configuration options for the low-level BLE code. 150 : struct BLESettings { 151 : /// Device name (used for advertising) 152 : const char *device_name = "Control Surface MIDI"; 153 : /// Connection intervals as multiples of 1.25 milliseconds 154 : /// (e.g.0x000C = 15 ms). 155 : struct { 156 : uint16_t minimum = 0x000C; 157 : uint16_t maximum = 0x000C; 158 : } connection_interval {}; 159 : /// Set to true if you want the Arduino to always initiate the Bluetooth 160 : /// bonding or secure connection. As a result, it will show up as a "paired" 161 : /// device on your computer/phone/tablet. If set to false, security is still 162 : /// supported, but the central device should take the initiative. 163 : bool initiate_security = false; 164 : }; 165 : 166 : END_CS_NAMESPACE 167 : 168 : #include "BLEAPI.ipp"