Control Surface  1.2.0
MIDI Control Surface library for Arduino
BluetoothMIDI_Interface.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "BLEMIDI.hpp"
5 
6 #include <AH/Error/Error.hpp>
7 
9 
16  public BLEServerCallbacks,
17  public BLECharacteristicCallbacks {
18 
19  // BLE Callbacks
20 
21  void onConnect(BLEServer *pServer) override {
22  (void)pServer;
23  DEBUGFN("Connected");
24  connected++;
25  };
26  void onDisconnect(BLEServer *pServer) override {
27  (void)pServer;
28  DEBUGFN("Disonnected");
29  if (!connected) {
30  ERROR(F("Error: disconnect event, but was not connected"), 0x7788);
31  return;
32  }
33  connected--;
34  }
35 
36  void onRead(BLECharacteristic *pCharacteristic) override {
37  DEBUGFN("Read");
38  pCharacteristic->setValue(nullptr, 0);
39  }
40  void onWrite(BLECharacteristic *pCharacteristic) override {
41  DEBUGFN("Write: ");
42  std::string value = pCharacteristic->getValue();
43  const uint8_t *const data =
44  reinterpret_cast<const uint8_t *>(value.data());
45  size_t len = value.size();
46  parse(data, len);
47  }
48 
49  constexpr static unsigned long MAX_MESSAGE_TIME = 10000; // microseconds
50 
51  unsigned long startTime = 0;
52 
53  constexpr static size_t BUFFER_LENGTH = 1024;
54 
55  uint8_t buffer[BUFFER_LENGTH] = {};
56  size_t index = 0;
57 
59 
61 
62  uint8_t connected = 0;
63 
64  bool hasSpaceFor(size_t bytes) { return bytes <= BUFFER_LENGTH - index; }
65 
66  public:
68 
69  void begin() override { bleMidi.begin(this, this); }
70 
71  void publish() {
72  if (index == 0)
73  return;
74  if (!connected) {
75  DEBUGFN("No connected BLE clients");
76  return;
77  }
79  index = 0;
80  }
81 
82  MIDIReadEvent read() override {
83  update(); // TODO
84  return MIDIReadEvent::NO_MESSAGE; // TODO
85  }
86 
87  template <size_t N>
88  void addToBuffer(const uint8_t (&data)[N]) {
89  addToBuffer(&data[0], N);
90  }
91 
92  void addToBuffer(const uint8_t *data, size_t len) {
93  bool first = index == 0;
94  if (!hasSpaceFor(len + 1 + first)) { // TODO
95  DEBUGFN("Buffer full");
96  publish();
97  if (!hasSpaceFor(len + 1 + first)) { // TODO
98  DEBUGFN("Message is larger than buffer");
99  return;
100  }
101  }
102 
103  if (first)
104  startTime = micros();
105 
106  if (first)
107  buffer[index++] = 0x80; // header / timestamp msb
108  buffer[index++] = 0x80; // timestamp lsb
109  memcpy(&buffer[index], data, len);
110  index += len;
111 
112  update();
113  }
114 
115  void update() override {
116  if (micros() - startTime >= MAX_MESSAGE_TIME)
117  publish();
118  }
119 
120  void sendImpl(uint8_t header, uint8_t d1, uint8_t d2, uint8_t cn) override {
121  (void)cn;
122  uint8_t msg[3] = {header, d1, d2};
123  addToBuffer(msg);
124  }
125  void sendImpl(uint8_t header, uint8_t d1, uint8_t cn) override {
126  (void)cn;
127  uint8_t msg[2] = {header, d1};
128  addToBuffer(msg);
129  }
130 
131  void sendImpl(const uint8_t *data, size_t length, uint8_t cn) override {
132  (void)data;
133  (void)length;
134  (void)cn; // TODO
135  }
136 
137  void sendImpl(uint8_t rt, uint8_t cn) override {
138  (void)rt;
139  (void)cn; // TODO
140  }
141 
142  void parse(const uint8_t *const data, const size_t len) {
143  // TODO: documentation and link to BLE MIDI spec
144  if (len <= 1)
145  return;
146  if (MIDI_Parser::isData(data[0]))
147  return;
148  if (MIDI_Parser::isData(data[1]))
149  parse(data[1]);
150  bool prevWasTimestamp = true;
151  for (const uint8_t *d = data + 2; d < data + len; d++) {
152  if (MIDI_Parser::isData(*d)) {
153  parse(*d);
154  prevWasTimestamp = false;
155  } else {
156  if (prevWasTimestamp)
157  parse(*d);
158  prevWasTimestamp = !prevWasTimestamp;
159  }
160  }
161  }
162 
163  void parse(uint8_t data) {
164  event = parser.parse(data);
165  // Best we can do is just retry until the pipe is no longer in exclusive
166  // mode.
167  // Keep in mind that this is executed in the callback of the BLE stack,
168  // I don't know what happens to the Bluetooth connection if we let it
169  // wait for longer than the communication interval.
170  //
171  // TODO: If this causes problems, we could buffer the data until the
172  // pipe is available for writing again.
173  while (!dispatchMIDIEvent(event))
174 #ifdef ARDUINO
175  delay(1);
176 #else
177  usleep(1e3);
178 #endif
179  }
180 
181  BLEMIDI &getBLEMIDI() { return bleMidi; }
182 };
183 
BLEMIDI::begin
void begin(BLEServerCallbacks *serverCallbacks, BLECharacteristicCallbacks *midiCallbacks)
Definition: BLEMIDI.hpp:52
BluetoothMIDI_Interface::sendImpl
void sendImpl(uint8_t rt, uint8_t cn) override
Low-level function for sending a single-byte MIDI message.
Definition: BluetoothMIDI_Interface.hpp:137
BluetoothMIDI_Interface
Bluetooth Low Energy MIDI Interface for the ESP32.
Definition: BluetoothMIDI_Interface.hpp:17
BluetoothMIDI_Interface::BluetoothMIDI_Interface
BluetoothMIDI_Interface()
Definition: BluetoothMIDI_Interface.hpp:67
BluetoothMIDI_Interface::sendImpl
void sendImpl(uint8_t header, uint8_t d1, uint8_t cn) override
Low-level function for sending a 2-byte MIDI message.
Definition: BluetoothMIDI_Interface.hpp:125
BluetoothMIDI_Interface::parse
void parse(uint8_t data)
Definition: BluetoothMIDI_Interface.hpp:163
MIDI_Parser::isData
static bool isData(uint8_t data)
Check if the given byte is a MIDI data byte.
Definition: MIDI_Parser.hpp:47
BluetoothMIDI_Interface::sendImpl
void sendImpl(uint8_t header, uint8_t d1, uint8_t d2, uint8_t cn) override
Low-level function for sending a 3-byte MIDI message.
Definition: BluetoothMIDI_Interface.hpp:120
Error.hpp
Parsing_MIDI_Interface
An abstract class for MIDI interfaces.
Definition: MIDI_Interface.hpp:232
BluetoothMIDI_Interface::onDisconnect
void onDisconnect(BLEServer *pServer) override
Definition: BluetoothMIDI_Interface.hpp:26
SerialMIDI_Interface.hpp
BluetoothMIDI_Interface::publish
void publish()
Definition: BluetoothMIDI_Interface.hpp:71
BluetoothMIDI_Interface::onConnect
void onConnect(BLEServer *pServer) override
Definition: BluetoothMIDI_Interface.hpp:21
BluetoothMIDI_Interface::addToBuffer
void addToBuffer(const uint8_t *data, size_t len)
Definition: BluetoothMIDI_Interface.hpp:92
BluetoothMIDI_Interface::MAX_MESSAGE_TIME
constexpr static unsigned long MAX_MESSAGE_TIME
Definition: BluetoothMIDI_Interface.hpp:49
BEGIN_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
Definition: Settings/NamespaceSettings.hpp:9
BluetoothMIDI_Interface::onWrite
void onWrite(BLECharacteristic *pCharacteristic) override
Definition: BluetoothMIDI_Interface.hpp:40
BluetoothMIDI_Interface::onRead
void onRead(BLECharacteristic *pCharacteristic) override
Definition: BluetoothMIDI_Interface.hpp:36
BluetoothMIDI_Interface::getBLEMIDI
BLEMIDI & getBLEMIDI()
Definition: BluetoothMIDI_Interface.hpp:181
BluetoothMIDI_Interface::sendImpl
void sendImpl(const uint8_t *data, size_t length, uint8_t cn) override
Low-level function for sending a system exclusive MIDI message.
Definition: BluetoothMIDI_Interface.hpp:131
BluetoothMIDI_Interface::update
void update() override
Read the MIDI interface and call the callback if a message is received.
Definition: BluetoothMIDI_Interface.hpp:115
END_CS_NAMESPACE
#define END_CS_NAMESPACE
Definition: Settings/NamespaceSettings.hpp:10
BluetoothMIDI_Interface::addToBuffer
void addToBuffer(const uint8_t(&data)[N])
Definition: BluetoothMIDI_Interface.hpp:88
BluetoothMIDI_Interface::index
size_t index
Definition: BluetoothMIDI_Interface.hpp:56
ERROR
#define ERROR(msg, errc)
Print the error message and error code, and stop the execution if FATAL_ERRORS are enabled.
Definition: Error.hpp:42
Parsing_MIDI_Interface::event
MIDIReadEvent event
Definition: MIDI_Interface.hpp:288
BLEMIDI::notifyValue
void notifyValue(uint8_t *data, size_t len)
Definition: BLEMIDI.hpp:92
BluetoothMIDI_Interface::parser
SerialMIDI_Parser parser
Definition: BluetoothMIDI_Interface.hpp:58
SerialMIDI_Parser
Definition: SerialMIDI_Parser.hpp:8
BLEMIDI.hpp
BluetoothMIDI_Interface::begin
void begin() override
Initialize this updatable.
Definition: BluetoothMIDI_Interface.hpp:69
Parsing_MIDI_Interface::dispatchMIDIEvent
bool dispatchMIDIEvent(MIDIReadEvent event)
Definition: MIDI_Interface.cpp:47
BluetoothMIDI_Interface::parse
void parse(const uint8_t *const data, const size_t len)
Definition: BluetoothMIDI_Interface.hpp:142
BLEMIDI
Definition: BLEMIDI.hpp:24
BluetoothMIDI_Interface::BUFFER_LENGTH
constexpr static size_t BUFFER_LENGTH
Definition: BluetoothMIDI_Interface.hpp:53
MIDI_Notes::F
constexpr int8_t F
Definition: Notes.hpp:23
BluetoothMIDI_Interface::connected
uint8_t connected
Definition: BluetoothMIDI_Interface.hpp:62
DEBUGFN
#define DEBUGFN(x)
Print an expression and its function (function name and line number) to the debug output if debugging...
Definition: Debug.hpp:93
SerialMIDI_Parser::parse
MIDIReadEvent parse(uint8_t midibyte)
Definition: SerialMIDI_Parser.cpp:5
MIDIReadEvent
MIDIReadEvent
Result of the MIDI interface read methods.
Definition: MIDI_Parser.hpp:15
BluetoothMIDI_Interface::startTime
unsigned long startTime
Definition: BluetoothMIDI_Interface.hpp:51
BluetoothMIDI_Interface::read
MIDIReadEvent read() override
Try reading and parsing a single incoming MIDI message.
Definition: BluetoothMIDI_Interface.hpp:82
BluetoothMIDI_Interface::bleMidi
BLEMIDI bleMidi
Definition: BluetoothMIDI_Interface.hpp:60
BluetoothMIDI_Interface::hasSpaceFor
bool hasSpaceFor(size_t bytes)
Definition: BluetoothMIDI_Interface.hpp:64
BluetoothMIDI_Interface::buffer
uint8_t buffer[BUFFER_LENGTH]
Definition: BluetoothMIDI_Interface.hpp:55