added working ArduinoBLE
This commit is contained in:
parent
9193101fab
commit
2efc6e5f0a
|
|
@ -1,3 +1,4 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
examples/.DS_Store
|
examples/.DS_Store
|
||||||
src/.DS_Store
|
src/.DS_Store
|
||||||
|
.vscode/settings.json
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@ public:
|
||||||
unsigned available()
|
unsigned available()
|
||||||
{
|
{
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
auto succes = mBleClass.available(&byte);
|
auto success = mBleClass.available(&byte);
|
||||||
if (!succes) return mRxIndex;
|
if (!success) return mRxIndex;
|
||||||
|
|
||||||
mRxBuffer[mRxIndex++] = byte;
|
mRxBuffer[mRxIndex++] = byte;
|
||||||
|
|
||||||
|
|
@ -192,13 +192,13 @@ public:
|
||||||
MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved
|
MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved
|
||||||
from other messages – except for System Exclusive messages.
|
from other messages – except for System Exclusive messages.
|
||||||
*/
|
*/
|
||||||
void receive(uint8_t* buffer, size_t length)
|
void receive(byte* buffer, size_t length)
|
||||||
{
|
{
|
||||||
// Pointers used to search through payload.
|
// Pointers used to search through payload.
|
||||||
uint8_t lPtr = 0;
|
byte lPtr = 0;
|
||||||
uint8_t rPtr = 0;
|
byte rPtr = 0;
|
||||||
// lastStatus used to capture runningStatus
|
// lastStatus used to capture runningStatus
|
||||||
uint8_t lastStatus;
|
byte lastStatus;
|
||||||
// Decode first packet -- SHALL be "Full MIDI message"
|
// Decode first packet -- SHALL be "Full MIDI message"
|
||||||
lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status"
|
lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status"
|
||||||
|
|
||||||
|
|
@ -219,14 +219,14 @@ public:
|
||||||
// look at l and r pointers and decode by size.
|
// look at l and r pointers and decode by size.
|
||||||
if( rPtr - lPtr < 1 ) {
|
if( rPtr - lPtr < 1 ) {
|
||||||
// Time code or system
|
// Time code or system
|
||||||
mBleClass.add(&lastStatus);
|
mBleClass.add(lastStatus);
|
||||||
} else if( rPtr - lPtr < 2 ) {
|
} else if( rPtr - lPtr < 2 ) {
|
||||||
mBleClass.add(&lastStatus);
|
mBleClass.add(lastStatus);
|
||||||
mBleClass.add(&buffer[lPtr + 1]);
|
mBleClass.add(buffer[lPtr + 1]);
|
||||||
} else if( rPtr - lPtr < 3 ) {
|
} else if( rPtr - lPtr < 3 ) {
|
||||||
mBleClass.add(&lastStatus);
|
mBleClass.add(lastStatus);
|
||||||
mBleClass.add(&buffer[lPtr + 1]);
|
mBleClass.add(buffer[lPtr + 1]);
|
||||||
mBleClass.add(&buffer[lPtr + 2]);
|
mBleClass.add(buffer[lPtr + 2]);
|
||||||
} else {
|
} else {
|
||||||
// Too much data
|
// Too much data
|
||||||
// If not System Common or System Real-Time, send it as running status
|
// If not System Common or System Real-Time, send it as running status
|
||||||
|
|
@ -239,23 +239,23 @@ public:
|
||||||
case 0xE0:
|
case 0xE0:
|
||||||
for (auto i = lPtr; i < rPtr; i = i + 2)
|
for (auto i = lPtr; i < rPtr; i = i + 2)
|
||||||
{
|
{
|
||||||
mBleClass.add(&lastStatus);
|
mBleClass.add(lastStatus);
|
||||||
mBleClass.add(&buffer[i + 1]);
|
mBleClass.add(buffer[i + 1]);
|
||||||
mBleClass.add(&buffer[i + 2]);
|
mBleClass.add(buffer[i + 2]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xC0:
|
case 0xC0:
|
||||||
case 0xD0:
|
case 0xD0:
|
||||||
for (auto i = lPtr; i < rPtr; i = i + 1)
|
for (auto i = lPtr; i < rPtr; i = i + 1)
|
||||||
{
|
{
|
||||||
mBleClass.add(&lastStatus);
|
mBleClass.add(lastStatus);
|
||||||
mBleClass.add(&buffer[i + 1]);
|
mBleClass.add(buffer[i + 1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xF0:
|
case 0xF0:
|
||||||
mBleClass.add(&buffer[lPtr]);
|
mBleClass.add(buffer[lPtr]);
|
||||||
for (auto i = lPtr; i < rPtr; i++)
|
for (auto i = lPtr; i < rPtr; i++)
|
||||||
mBleClass.add(&buffer[i + 1]);
|
mBleClass.add(buffer[i + 1]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
//#include <hardware/BLEMIDI_ESP32_NimBLE.h>
|
#include <hardware/BLEMIDI_ESP32_NimBLE.h>
|
||||||
#include <hardware/BLEMIDI_ESP32.h>
|
//#include <hardware/BLEMIDI_ESP32.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef AAA
|
#ifdef AAA
|
||||||
#include <hardware/BLEMIDI_nRF52.h>
|
#include <hardware/BLEMIDI_nRF52.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __AVR__
|
|
||||||
|
//#ifdef BBB
|
||||||
#include <hardware/BLEMIDI_ArduinoBLE.h>
|
#include <hardware/BLEMIDI_ArduinoBLE.h>
|
||||||
#endif
|
//#endif
|
||||||
|
|
|
||||||
|
|
@ -10,20 +10,70 @@ BLEStringCharacteristic midiChar(CHARACTERISTIC_UUID, // standard 16-bit charac
|
||||||
|
|
||||||
BEGIN_BLEMIDI_NAMESPACE
|
BEGIN_BLEMIDI_NAMESPACE
|
||||||
|
|
||||||
class BLEMIDI
|
template<typename T, int rawSize>
|
||||||
|
class Fifo {
|
||||||
|
public:
|
||||||
|
const size_t size; //speculative feature, in case it's needed
|
||||||
|
|
||||||
|
Fifo(): size(rawSize)
|
||||||
|
{
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
T dequeue()
|
||||||
|
{
|
||||||
|
numberOfElements--;
|
||||||
|
nextOut %= size;
|
||||||
|
return raw[ nextOut++];
|
||||||
|
};
|
||||||
|
|
||||||
|
bool enqueue( T element )
|
||||||
|
{
|
||||||
|
if ( count() >= rawSize )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
numberOfElements++;
|
||||||
|
nextIn %= size;
|
||||||
|
raw[nextIn] = element;
|
||||||
|
nextIn++; //advance to next index
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
T peek() const
|
||||||
|
{
|
||||||
|
return raw[ nextOut % size];
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush()
|
||||||
|
{
|
||||||
|
nextIn = nextOut = numberOfElements = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// how many elements are currently in the FIFO?
|
||||||
|
size_t count() { return numberOfElements; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t numberOfElements;
|
||||||
|
size_t nextIn;
|
||||||
|
size_t nextOut;
|
||||||
|
T raw[rawSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
class BLEMIDI_ArduinoBLE
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
static BLEMIDITransport<class BLEMIDI>* _bleMidiTransport;
|
static BLEMIDITransport<class BLEMIDI_ArduinoBLE>* _bleMidiTransport;
|
||||||
static BLEDevice* _central;
|
static BLEDevice* _central;
|
||||||
|
|
||||||
// byte mRxBuffer[Settings::MaxBufferSize];
|
Fifo<byte, 64> mRxBuffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BLEMIDI()
|
BLEMIDI_ArduinoBLE()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool begin(const char*, BLEMIDITransport<class BLEMIDI>*);
|
bool begin(const char*, BLEMIDITransport<class BLEMIDI_ArduinoBLE>*);
|
||||||
|
|
||||||
void write(uint8_t* buffer, size_t length)
|
void write(uint8_t* buffer, size_t length)
|
||||||
{
|
{
|
||||||
|
|
@ -31,9 +81,16 @@ public:
|
||||||
((BLECharacteristic)midiChar).writeValue(buffer, length);
|
((BLECharacteristic)midiChar).writeValue(buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t available(uint8_t* buffer, const size_t index, const size_t max)
|
bool available(byte* pvBuffer)
|
||||||
{
|
{
|
||||||
#ifdef BLE_POLLING
|
#ifdef BLE_POLLING
|
||||||
|
|
||||||
|
if (mRxBuffer.count() > 0) {
|
||||||
|
*pvBuffer = mRxBuffer.dequeue();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
poll();
|
poll();
|
||||||
|
|
||||||
if (midiChar.written()) {
|
if (midiChar.written()) {
|
||||||
|
|
@ -41,60 +98,30 @@ public:
|
||||||
auto length = midiChar.valueLength();
|
auto length = midiChar.valueLength();
|
||||||
|
|
||||||
if (length > 0) {
|
if (length > 0) {
|
||||||
// TODO: test length
|
auto buffer = midiChar.value().c_str();
|
||||||
memcpy(buffer + index, midiChar.value().c_str(), length);
|
_bleMidiTransport->receive((byte*)buffer, length);
|
||||||
return length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
#endif
|
#endif
|
||||||
#ifdef BLE_EVENTS
|
#ifdef BLE_EVENTS
|
||||||
/ BLE.poll();
|
/ BLE.poll();
|
||||||
return 0;
|
return ; // ??
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void read()
|
void add(byte value)
|
||||||
{
|
{
|
||||||
|
// called from BLE-MIDI, to add it to a buffer here
|
||||||
|
mRxBuffer.enqueue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
protected:
|
||||||
The general form of a MIDI message follows:
|
static void receive(const unsigned char* buffer, size_t length)
|
||||||
n-byte MIDI Message
|
|
||||||
Byte 0 MIDI message Status byte, Bit 7 is Set to 1.
|
|
||||||
Bytes 1 to n-1 MIDI message Data bytes, if n > 1. Bit 7 is Set to 0
|
|
||||||
There are two types of MIDI messages that can appear in a single packet: full MIDI messages and
|
|
||||||
Running Status MIDI messages. Each is encoded differently.
|
|
||||||
A full MIDI message is simply the MIDI message with the Status byte included.
|
|
||||||
A Running Status MIDI message is a MIDI message with the Status byte omitted. Running Status
|
|
||||||
MIDI messages may only be placed in the data stream if the following criteria are met:
|
|
||||||
1. The original MIDI message is 2 bytes or greater and is not a System Common or System
|
|
||||||
Real-Time message.
|
|
||||||
2. The omitted Status byte matches the most recently preceding full MIDI message’s Status
|
|
||||||
byte within the same BLE packet.
|
|
||||||
In addition, the following rules apply with respect to Running Status:
|
|
||||||
1. A Running Status MIDI message is allowed within the packet after at least one full MIDI
|
|
||||||
message.
|
|
||||||
2. Every MIDI Status byte must be preceded by a timestamp byte. Running Status MIDI
|
|
||||||
messages may be preceded by a timestamp byte. If a Running Status MIDI message is not
|
|
||||||
preceded by a timestamp byte, the timestamp byte of the most recently preceding message
|
|
||||||
in the same packet is used.
|
|
||||||
3. System Common and System Real-Time messages do not cancel Running Status if
|
|
||||||
interspersed between Running Status MIDI messages. However, a timestamp byte must
|
|
||||||
precede the Running Status MIDI message that follows.
|
|
||||||
4. The end of a BLE packet does cancel Running Status.
|
|
||||||
In the MIDI 1.0 protocol, System Real-Time messages can be sent at any time and may be
|
|
||||||
inserted anywhere in a MIDI data stream, including between Status and Data bytes of any other
|
|
||||||
MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved
|
|
||||||
from other messages – except for System Exclusive messages.
|
|
||||||
*/
|
|
||||||
static void receive(const uint8_t* buffer, size_t length)
|
|
||||||
{
|
{
|
||||||
Serial.print("receive: ");
|
// forward the buffer so it can be parsed
|
||||||
for (int i = 0; i < length; i++) {
|
_bleMidiTransport->receive((uint8_t*)buffer, length);
|
||||||
Serial.print(" 0x");
|
|
||||||
Serial.print(buffer[i], HEX);
|
|
||||||
}
|
|
||||||
Serial.println("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poll()
|
bool poll()
|
||||||
|
|
@ -102,7 +129,7 @@ public:
|
||||||
BLEDevice central = BLE.central();
|
BLEDevice central = BLE.central();
|
||||||
if (!central) {
|
if (!central) {
|
||||||
if (_central) {
|
if (_central) {
|
||||||
BLEMIDI::blePeripheralDisconnectHandler(*_central);
|
BLEMIDI_ArduinoBLE::blePeripheralDisconnectHandler(*_central);
|
||||||
_central = nullptr;
|
_central = nullptr;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -113,13 +140,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nullptr == _central) {
|
if (nullptr == _central) {
|
||||||
BLEMIDI::blePeripheralConnectHandler(central);
|
BLEMIDI_ArduinoBLE::blePeripheralConnectHandler(central);
|
||||||
_central = ¢ral;
|
_central = ¢ral;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (*_central != central) {
|
if (*_central != central) {
|
||||||
BLEMIDI::blePeripheralDisconnectHandler(*_central);
|
BLEMIDI_ArduinoBLE::blePeripheralDisconnectHandler(*_central);
|
||||||
BLEMIDI::blePeripheralConnectHandler(central);
|
BLEMIDI_ArduinoBLE::blePeripheralConnectHandler(central);
|
||||||
_central = ¢ral;
|
_central = ¢ral;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -150,10 +177,10 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BLEMIDITransport<class BLEMIDI>* BLEMIDI::_bleMidiTransport = nullptr;
|
BLEMIDITransport<class BLEMIDI_ArduinoBLE>* BLEMIDI_ArduinoBLE::_bleMidiTransport = nullptr;
|
||||||
BLEDevice* BLEMIDI::_central = nullptr;
|
BLEDevice* BLEMIDI_ArduinoBLE::_central = nullptr;
|
||||||
|
|
||||||
bool BLEMIDI::begin(const char* deviceName, BLEMIDITransport<class BLEMIDI>* bleMidiTransport)
|
bool BLEMIDI_ArduinoBLE::begin(const char* deviceName, BLEMIDITransport<class BLEMIDI_ArduinoBLE>* bleMidiTransport)
|
||||||
{
|
{
|
||||||
_bleMidiTransport = bleMidiTransport;
|
_bleMidiTransport = bleMidiTransport;
|
||||||
|
|
||||||
|
|
@ -168,8 +195,8 @@ bool BLEMIDI::begin(const char* deviceName, BLEMIDITransport<class BLEMIDI>* ble
|
||||||
|
|
||||||
#ifdef BLE_EVENTS
|
#ifdef BLE_EVENTS
|
||||||
// assign event handlers for connected, disconnected to peripheral
|
// assign event handlers for connected, disconnected to peripheral
|
||||||
BLE.setEventHandler(BLEConnected, BLEMIDI::blePeripheralConnectHandler);
|
BLE.setEventHandler(BLEConnected, BLEMIDI_ArduinoBLE::blePeripheralConnectHandler);
|
||||||
BLE.setEventHandler(BLEDisconnected, BLEMIDI::blePeripheralDisconnectHandler);
|
BLE.setEventHandler(BLEDisconnected, BLEMIDI_ArduinoBLE::blePeripheralDisconnectHandler);
|
||||||
|
|
||||||
midiChar.setEventHandler(BLEWritten, characteristicWritten);
|
midiChar.setEventHandler(BLEWritten, characteristicWritten);
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -187,8 +214,8 @@ bool BLEMIDI::begin(const char* deviceName, BLEMIDITransport<class BLEMIDI>* ble
|
||||||
/*! \brief Create an instance for nRF52 named <DeviceName>
|
/*! \brief Create an instance for nRF52 named <DeviceName>
|
||||||
*/
|
*/
|
||||||
#define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \
|
#define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \
|
||||||
BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI> BLE##Name(DeviceName); \
|
BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_ArduinoBLE> BLE##Name(DeviceName); \
|
||||||
MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI>, MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI> &)BLE##Name);
|
MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_ArduinoBLE>, MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_ArduinoBLE> &)BLE##Name);
|
||||||
|
|
||||||
/*! \brief Create a default instance for nRF52 named BLE-MIDI
|
/*! \brief Create a default instance for nRF52 named BLE-MIDI
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -36,15 +36,15 @@ public:
|
||||||
_characteristic->notify();
|
_characteristic->notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool available(void *pvBuffer)
|
bool available(byte* pvBuffer)
|
||||||
{
|
{
|
||||||
return xQueueReceive(mRxQueue, pvBuffer, 0); // return immediately when the queue is empty
|
return xQueueReceive(mRxQueue, pvBuffer, 0); // return immediately when the queue is empty
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(const void* value)
|
void add(byte value)
|
||||||
{
|
{
|
||||||
// called from BLE-MIDI, to add it to a buffer here
|
// called from BLE-MIDI, to add it to a buffer here
|
||||||
xQueueSend(mRxQueue, value, portMAX_DELAY);
|
xQueueSend(mRxQueue, &value, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
||||||
|
|
@ -33,21 +33,22 @@ public:
|
||||||
_characteristic->notify();
|
_characteristic->notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t available(void *pvBuffer)
|
bool available(byte* pvBuffer)
|
||||||
{
|
{
|
||||||
return xQueueReceive(mRxQueue, pvBuffer, 0); // return immediately when the queue is empty
|
// return 1 byte from the Queue
|
||||||
|
return xQueueReceive(mRxQueue, (void*)pvBuffer, 0); // return immediately when the queue is empty
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(const void* value)
|
void add(byte value)
|
||||||
{
|
{
|
||||||
// called from BLE-MIDI, to add it to a buffer here
|
// called from BLE-MIDI, to add it to a buffer here
|
||||||
xQueueSend(mRxQueue, value, portMAX_DELAY);
|
xQueueSend(mRxQueue, &value, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void receive(uint8_t* buffer, size_t length)
|
void receive(uint8_t* buffer, size_t length)
|
||||||
{
|
{
|
||||||
// parse the incoming buffer
|
// forward the buffer so it can be parsed
|
||||||
_bleMidiTransport->receive(buffer, length);
|
_bleMidiTransport->receive(buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue