added initial support for nRF52, cleanup ESP32
This commit is contained in:
parent
ce874ad382
commit
7d5944f37a
|
|
@ -1,11 +1,11 @@
|
||||||
#include <BLE-MIDI.h>
|
#include <BLE-MIDI.h>
|
||||||
#include <hardware/BLE-MIDI_ESP32.h>
|
#include <hardware/ESP32.h>
|
||||||
|
|
||||||
// Simple tutorial on how to receive and send MIDI messages.
|
// Simple tutorial on how to receive and send MIDI messages.
|
||||||
// Here, when receiving any message on channel 4, the Arduino
|
// Here, when receiving any message on channel 4, the Arduino
|
||||||
// will blink a led and play back a note for 1 second.
|
// will blink a led and play back a note for 1 second.
|
||||||
|
|
||||||
BLEMIDI_CREATE_DEFAULT_ESP32_INSTANCE()
|
BLEMIDI_CREATE_DEFAULT_INSTANCE()
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
#include <BLE-MIDI.h>
|
#include <BLE-MIDI.h>
|
||||||
#include <hardware/BLE-MIDI_ESP32.h>
|
#include <hardware/ESP32.h>
|
||||||
|
//#include <hardware/nRF52.h>
|
||||||
|
|
||||||
BLEMIDI_CREATE_DEFAULT_ESP32_INSTANCE()
|
BLEMIDI_CREATE_DEFAULT_INSTANCE()
|
||||||
|
|
||||||
unsigned long t0 = millis();
|
unsigned long t0 = millis();
|
||||||
bool isConnected = false;
|
bool isConnected = false;
|
||||||
|
|
@ -15,13 +16,13 @@ void setup()
|
||||||
while (!Serial);
|
while (!Serial);
|
||||||
Serial.println("Booting");
|
Serial.println("Booting");
|
||||||
|
|
||||||
MIDI.begin(1);
|
MIDI.begin();
|
||||||
|
|
||||||
BLEMIDI.onConnected(OnBleMidiConnected);
|
BLEMIDI.setHandleConnected(OnConnected);
|
||||||
BLEMIDI.onDisconnected(OnBleMidiDisconnected);
|
BLEMIDI.setHandleDisconnected(OnDisconnected);
|
||||||
|
|
||||||
MIDI.setHandleNoteOn(OnBleMidiNoteOn);
|
MIDI.setHandleNoteOn(OnNoteOn);
|
||||||
MIDI.setHandleNoteOff(OnBleMidiNoteOff);
|
MIDI.setHandleNoteOff(OnNoteOff);
|
||||||
|
|
||||||
Serial.println(F("Ready"));
|
Serial.println(F("Ready"));
|
||||||
}
|
}
|
||||||
|
|
@ -47,25 +48,25 @@ void loop()
|
||||||
// ====================================================================================
|
// ====================================================================================
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// rtpMIDI session. Device connected
|
// Device connected
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
void OnBleMidiConnected() {
|
void OnConnected() {
|
||||||
Serial.println(F("Connected"));
|
Serial.println(F("Connected"));
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// rtpMIDI session. Device disconnected
|
// Device disconnected
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
void OnBleMidiDisconnected() {
|
void OnDisconnected() {
|
||||||
Serial.println(F("Disconnected"));
|
Serial.println(F("Disconnected"));
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// received note on
|
// Received note on
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
void OnBleMidiNoteOn(byte channel, byte note, byte velocity) {
|
void OnNoteOn(byte channel, byte note, byte velocity) {
|
||||||
Serial.print(F("Incoming NoteOn from channel:"));
|
Serial.print(F("Incoming NoteOn from channel:"));
|
||||||
Serial.print(channel);
|
Serial.print(channel);
|
||||||
Serial.print(F(" note:"));
|
Serial.print(F(" note:"));
|
||||||
|
|
@ -76,9 +77,9 @@ void OnBleMidiNoteOn(byte channel, byte note, byte velocity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// received note off
|
// Received note off
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
void OnBleMidiNoteOff(byte channel, byte note, byte velocity) {
|
void OnNoteOff(byte channel, byte note, byte velocity) {
|
||||||
Serial.print(F("Incoming NoteOff from channel:"));
|
Serial.print(F("Incoming NoteOff from channel:"));
|
||||||
Serial.print(channel);
|
Serial.print(channel);
|
||||||
Serial.print(F(" note:"));
|
Serial.print(F(" note:"));
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@ paragraph=MIDI over Bluetooth Low Energy
|
||||||
category=Communication
|
category=Communication
|
||||||
url=https://github.com/lathoub/Arduino-BLE-MIDI
|
url=https://github.com/lathoub/Arduino-BLE-MIDI
|
||||||
architectures=*
|
architectures=*
|
||||||
includes=BLEMIDI.h
|
includes=BLE-MIDI.h
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ public:
|
||||||
|
|
||||||
// To communicate between the 2 cores.
|
// To communicate between the 2 cores.
|
||||||
// Core_0 runs here, core_1 runs the BLE stack
|
// Core_0 runs here, core_1 runs the BLE stack
|
||||||
mRxQueue = xQueueCreate(Settings::MaxBufferSize, sizeof(uint8_t));
|
// mRxQueue = xQueueCreate(Settings::MaxBufferSize, sizeof(uint8_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool beginTransmission(MidiType)
|
bool beginTransmission(MidiType)
|
||||||
|
|
@ -86,7 +86,7 @@ public:
|
||||||
unsigned available()
|
unsigned available()
|
||||||
{
|
{
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
auto succes = xQueueReceive(mRxQueue, &byte, 0); // return immediately when the queue is empty
|
auto succes = mBleClass.available(&byte); // xQueueReceive(mRxQueue, &byte, 0); // return immediately when the queue is empty
|
||||||
if (!succes) return mRxIndex;
|
if (!succes) return mRxIndex;
|
||||||
|
|
||||||
mRxBuffer[mRxIndex++] = byte;
|
mRxBuffer[mRxIndex++] = byte;
|
||||||
|
|
@ -95,7 +95,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QueueHandle_t mRxQueue;
|
// QueueHandle_t mRxQueue;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/*
|
/*
|
||||||
|
|
@ -161,11 +161,11 @@ public:
|
||||||
void(*_disconnectedCallback)() = nullptr;
|
void(*_disconnectedCallback)() = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void onConnected(void(*fptr)()) {
|
void setHandleConnected(void(*fptr)()) {
|
||||||
_connectedCallback = fptr;
|
_connectedCallback = fptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDisconnected(void(*fptr)()) {
|
void setHandleDisconnected(void(*fptr)()) {
|
||||||
_disconnectedCallback = fptr;
|
_disconnectedCallback = fptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,23 +173,8 @@ public:
|
||||||
|
|
||||||
END_BLEMIDI_NAMESPACE
|
END_BLEMIDI_NAMESPACE
|
||||||
|
|
||||||
struct MySettings : public MIDI_NAMESPACE::DefaultSettings
|
struct MySettings : public MIDI_NAMESPACE::DefaultSettings
|
||||||
{
|
{
|
||||||
static const bool Use1ByteParsing = false;
|
static const bool Use1ByteParsing = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief Create an instance of the library
|
|
||||||
*/
|
|
||||||
#define BLEMIDI_CREATE_INSTANCE(Type, DeviceName, Name) \
|
|
||||||
BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32> BLE##Name(DeviceName); \
|
|
||||||
MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32>, MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32> &)BLE##Name);
|
|
||||||
|
|
||||||
/*! \brief Create an instance for ESP32 named <DeviceName>
|
|
||||||
*/
|
|
||||||
#define BLEMIDI_CREATE_ESP32_INSTANCE(DeviceName) \
|
|
||||||
BLEMIDI_CREATE_INSTANCE(BLEMIDI_NAMESPACE::BLEMIDI_ESP32, DeviceName, MIDI);
|
|
||||||
|
|
||||||
/*! \brief Create a default instance for ESP32 named BLE-MIDI
|
|
||||||
*/
|
|
||||||
#define BLEMIDI_CREATE_DEFAULT_ESP32_INSTANCE() \
|
|
||||||
BLEMIDI_CREATE_ESP32_INSTANCE("BLE-MIDI")
|
|
||||||
|
|
|
||||||
|
|
@ -1,230 +1,253 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Headers for ESP32 BLE
|
// Headers for ESP32 BLE
|
||||||
#include <BLEDevice.h>
|
#include <BLEDevice.h>
|
||||||
#include <BLEUtils.h>
|
#include <BLEUtils.h>
|
||||||
#include <BLEServer.h>
|
#include <BLEServer.h>
|
||||||
#include <BLE2902.h>
|
#include <BLE2902.h>
|
||||||
|
|
||||||
BEGIN_BLEMIDI_NAMESPACE
|
BEGIN_BLEMIDI_NAMESPACE
|
||||||
|
|
||||||
class BLEMIDI_ESP32
|
class BLEMIDI_ESP32
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
BLEServer* _server = nullptr;
|
BLEServer* _server = nullptr;
|
||||||
BLEAdvertising* _advertising = nullptr;
|
BLEAdvertising* _advertising = nullptr;
|
||||||
BLECharacteristic* _characteristic = nullptr;
|
BLECharacteristic* _characteristic = nullptr;
|
||||||
|
|
||||||
BLEMIDITransport<class BLEMIDI_ESP32>* _bleMidiTransport = nullptr;
|
BLEMIDITransport<class BLEMIDI_ESP32>* _bleMidiTransport = nullptr;
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
BLEMIDI_ESP32()
|
QueueHandle_t mRxQueue;
|
||||||
{
|
|
||||||
}
|
public:
|
||||||
|
BLEMIDI_ESP32()
|
||||||
bool begin(const char*, BLEMIDITransport<class BLEMIDI_ESP32>*);
|
{
|
||||||
|
}
|
||||||
void write(uint8_t* buffer, size_t length)
|
|
||||||
{
|
bool begin(const char*, BLEMIDITransport<class BLEMIDI_ESP32>*);
|
||||||
_characteristic->setValue(buffer, length);
|
|
||||||
_characteristic->notify();
|
void write(uint8_t* buffer, size_t length)
|
||||||
}
|
{
|
||||||
|
_characteristic->setValue(buffer, length);
|
||||||
/*
|
_characteristic->notify();
|
||||||
The general form of a MIDI message follows:
|
}
|
||||||
n-byte MIDI Message
|
|
||||||
Byte 0 MIDI message Status byte, Bit 7 is Set to 1.
|
bool available(void *pvBuffer)
|
||||||
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
|
return xQueueReceive(mRxQueue, pvBuffer, 0); // return immediately when the queue is empty
|
||||||
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:
|
The general form of a MIDI message follows:
|
||||||
1. The original MIDI message is 2 bytes or greater and is not a System Common or System
|
n-byte MIDI Message
|
||||||
Real-Time message.
|
Byte 0 MIDI message Status byte, Bit 7 is Set to 1.
|
||||||
2. The omitted Status byte matches the most recently preceding full MIDI message’s Status
|
Bytes 1 to n-1 MIDI message Data bytes, if n > 1. Bit 7 is Set to 0
|
||||||
byte within the same BLE packet.
|
There are two types of MIDI messages that can appear in a single packet: full MIDI messages and
|
||||||
In addition, the following rules apply with respect to Running Status:
|
Running Status MIDI messages. Each is encoded differently.
|
||||||
1. A Running Status MIDI message is allowed within the packet after at least one full MIDI
|
A full MIDI message is simply the MIDI message with the Status byte included.
|
||||||
message.
|
A Running Status MIDI message is a MIDI message with the Status byte omitted. Running Status
|
||||||
2. Every MIDI Status byte must be preceded by a timestamp byte. Running Status MIDI
|
MIDI messages may only be placed in the data stream if the following criteria are met:
|
||||||
messages may be preceded by a timestamp byte. If a Running Status MIDI message is not
|
1. The original MIDI message is 2 bytes or greater and is not a System Common or System
|
||||||
preceded by a timestamp byte, the timestamp byte of the most recently preceding message
|
Real-Time message.
|
||||||
in the same packet is used.
|
2. The omitted Status byte matches the most recently preceding full MIDI message’s Status
|
||||||
3. System Common and System Real-Time messages do not cancel Running Status if
|
byte within the same BLE packet.
|
||||||
interspersed between Running Status MIDI messages. However, a timestamp byte must
|
In addition, the following rules apply with respect to Running Status:
|
||||||
precede the Running Status MIDI message that follows.
|
1. A Running Status MIDI message is allowed within the packet after at least one full MIDI
|
||||||
4. The end of a BLE packet does cancel Running Status.
|
message.
|
||||||
In the MIDI 1.0 protocol, System Real-Time messages can be sent at any time and may be
|
2. Every MIDI Status byte must be preceded by a timestamp byte. Running Status MIDI
|
||||||
inserted anywhere in a MIDI data stream, including between Status and Data bytes of any other
|
messages may be preceded by a timestamp byte. If a Running Status MIDI message is not
|
||||||
MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved
|
preceded by a timestamp byte, the timestamp byte of the most recently preceding message
|
||||||
from other messages – except for System Exclusive messages.
|
in the same packet is used.
|
||||||
*/
|
3. System Common and System Real-Time messages do not cancel Running Status if
|
||||||
void receive(uint8_t* buffer, size_t length)
|
interspersed between Running Status MIDI messages. However, a timestamp byte must
|
||||||
{
|
precede the Running Status MIDI message that follows.
|
||||||
// Pointers used to search through payload.
|
4. The end of a BLE packet does cancel Running Status.
|
||||||
uint8_t lPtr = 0;
|
In the MIDI 1.0 protocol, System Real-Time messages can be sent at any time and may be
|
||||||
uint8_t rPtr = 0;
|
inserted anywhere in a MIDI data stream, including between Status and Data bytes of any other
|
||||||
// lastStatus used to capture runningStatus
|
MIDI messages. In the MIDI BLE protocol, the System Real-Time messages must be deinterleaved
|
||||||
uint8_t lastStatus;
|
from other messages – except for System Exclusive messages.
|
||||||
// Decode first packet -- SHALL be "Full MIDI message"
|
*/
|
||||||
lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status"
|
void receive(uint8_t* buffer, size_t length)
|
||||||
|
{
|
||||||
//While statement contains incrementing pointers and breaks when buffer size exceeded.
|
// Pointers used to search through payload.
|
||||||
while (true)
|
uint8_t lPtr = 0;
|
||||||
{
|
uint8_t rPtr = 0;
|
||||||
lastStatus = buffer[lPtr];
|
// lastStatus used to capture runningStatus
|
||||||
|
uint8_t lastStatus;
|
||||||
if( (buffer[lPtr] < 0x80))
|
// Decode first packet -- SHALL be "Full MIDI message"
|
||||||
return; // Status message not present, bail
|
lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status"
|
||||||
|
|
||||||
// Point to next non-data byte
|
//While statement contains incrementing pointers and breaks when buffer size exceeded.
|
||||||
rPtr = lPtr;
|
while (true)
|
||||||
while( (buffer[rPtr + 1] < 0x80) && (rPtr < (length - 1)) )
|
{
|
||||||
rPtr++;
|
lastStatus = buffer[lPtr];
|
||||||
if (buffer[rPtr + 1] == 0xF7) rPtr++;
|
|
||||||
|
if( (buffer[lPtr] < 0x80))
|
||||||
// look at l and r pointers and decode by size.
|
return; // Status message not present, bail
|
||||||
if( rPtr - lPtr < 1 ) {
|
|
||||||
// Time code or system
|
// Point to next non-data byte
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY);
|
rPtr = lPtr;
|
||||||
} else if( rPtr - lPtr < 2 ) {
|
while( (buffer[rPtr + 1] < 0x80) && (rPtr < (length - 1)) )
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY);
|
rPtr++;
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &buffer[lPtr + 1], portMAX_DELAY);
|
if (buffer[rPtr + 1] == 0xF7) rPtr++;
|
||||||
} else if( rPtr - lPtr < 3 ) {
|
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY);
|
// look at l and r pointers and decode by size.
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &buffer[lPtr + 1], portMAX_DELAY);
|
if( rPtr - lPtr < 1 ) {
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &buffer[lPtr + 2], portMAX_DELAY);
|
// Time code or system
|
||||||
} else {
|
xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY);
|
||||||
// Too much data
|
} else if( rPtr - lPtr < 2 ) {
|
||||||
// If not System Common or System Real-Time, send it as running status
|
xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY);
|
||||||
switch(buffer[lPtr] & 0xF0)
|
xQueueSend(mRxQueue, &buffer[lPtr + 1], portMAX_DELAY);
|
||||||
{
|
} else if( rPtr - lPtr < 3 ) {
|
||||||
case 0x80:
|
xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY);
|
||||||
case 0x90:
|
xQueueSend(mRxQueue, &buffer[lPtr + 1], portMAX_DELAY);
|
||||||
case 0xA0:
|
xQueueSend(mRxQueue, &buffer[lPtr + 2], portMAX_DELAY);
|
||||||
case 0xB0:
|
} else {
|
||||||
case 0xE0:
|
// Too much data
|
||||||
for (auto i = lPtr; i < rPtr; i = i + 2)
|
// If not System Common or System Real-Time, send it as running status
|
||||||
{
|
switch(buffer[lPtr] & 0xF0)
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY);
|
{
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 1], portMAX_DELAY);
|
case 0x80:
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 2], portMAX_DELAY);
|
case 0x90:
|
||||||
}
|
case 0xA0:
|
||||||
break;
|
case 0xB0:
|
||||||
case 0xC0:
|
case 0xE0:
|
||||||
case 0xD0:
|
for (auto i = lPtr; i < rPtr; i = i + 2)
|
||||||
for (auto i = lPtr; i < rPtr; i = i + 1)
|
{
|
||||||
{
|
xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY);
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY);
|
xQueueSend(mRxQueue, &buffer[i + 1], portMAX_DELAY);
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 1], portMAX_DELAY);
|
xQueueSend(mRxQueue, &buffer[i + 2], portMAX_DELAY);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xF0:
|
case 0xC0:
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &buffer[lPtr], portMAX_DELAY);
|
case 0xD0:
|
||||||
for (auto i = lPtr; i < rPtr; i++)
|
for (auto i = lPtr; i < rPtr; i = i + 1)
|
||||||
xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 1], portMAX_DELAY);
|
{
|
||||||
break;
|
xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY);
|
||||||
default:
|
xQueueSend(mRxQueue, &buffer[i + 1], portMAX_DELAY);
|
||||||
break;
|
}
|
||||||
}
|
break;
|
||||||
}
|
case 0xF0:
|
||||||
|
xQueueSend(mRxQueue, &buffer[lPtr], portMAX_DELAY);
|
||||||
// Point to next status
|
for (auto i = lPtr; i < rPtr; i++)
|
||||||
lPtr = rPtr + 2;
|
xQueueSend(mRxQueue, &buffer[i + 1], portMAX_DELAY);
|
||||||
if(lPtr >= length)
|
break;
|
||||||
return; //end of packet
|
default:
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void connected()
|
|
||||||
{
|
// Point to next status
|
||||||
if (_bleMidiTransport->_connectedCallback)
|
lPtr = rPtr + 2;
|
||||||
_bleMidiTransport->_connectedCallback();
|
if(lPtr >= length)
|
||||||
}
|
return; //end of packet
|
||||||
|
}
|
||||||
void disconnected()
|
}
|
||||||
{
|
|
||||||
if (_bleMidiTransport->_disconnectedCallback)
|
void connected()
|
||||||
_bleMidiTransport->_disconnectedCallback();
|
{
|
||||||
}
|
if (_bleMidiTransport->_connectedCallback)
|
||||||
};
|
_bleMidiTransport->_connectedCallback();
|
||||||
|
}
|
||||||
class MyServerCallbacks: public BLEServerCallbacks {
|
|
||||||
public:
|
void disconnected()
|
||||||
MyServerCallbacks(BLEMIDI_ESP32* bluetoothEsp32)
|
{
|
||||||
: _bluetoothEsp32(bluetoothEsp32) {
|
if (_bleMidiTransport->_disconnectedCallback)
|
||||||
}
|
_bleMidiTransport->_disconnectedCallback();
|
||||||
|
}
|
||||||
protected:
|
};
|
||||||
BLEMIDI_ESP32* _bluetoothEsp32 = nullptr;
|
|
||||||
|
class MyServerCallbacks: public BLEServerCallbacks {
|
||||||
void onConnect(BLEServer*) {
|
public:
|
||||||
if (_bluetoothEsp32)
|
MyServerCallbacks(BLEMIDI_ESP32* bluetoothEsp32)
|
||||||
_bluetoothEsp32->connected();
|
: _bluetoothEsp32(bluetoothEsp32) {
|
||||||
};
|
}
|
||||||
|
|
||||||
void onDisconnect(BLEServer*) {
|
protected:
|
||||||
if (_bluetoothEsp32)
|
BLEMIDI_ESP32* _bluetoothEsp32 = nullptr;
|
||||||
_bluetoothEsp32->disconnected();
|
|
||||||
}
|
void onConnect(BLEServer*) {
|
||||||
};
|
if (_bluetoothEsp32)
|
||||||
|
_bluetoothEsp32->connected();
|
||||||
class MyCharacteristicCallbacks: public BLECharacteristicCallbacks {
|
};
|
||||||
public:
|
|
||||||
MyCharacteristicCallbacks(BLEMIDI_ESP32* bluetoothEsp32)
|
void onDisconnect(BLEServer*) {
|
||||||
: _bluetoothEsp32(bluetoothEsp32 ) {
|
if (_bluetoothEsp32)
|
||||||
}
|
_bluetoothEsp32->disconnected();
|
||||||
|
}
|
||||||
protected:
|
};
|
||||||
BLEMIDI_ESP32* _bluetoothEsp32 = nullptr;
|
|
||||||
|
class MyCharacteristicCallbacks: public BLECharacteristicCallbacks {
|
||||||
void onWrite(BLECharacteristic * characteristic) {
|
public:
|
||||||
std::string rxValue = characteristic->getValue();
|
MyCharacteristicCallbacks(BLEMIDI_ESP32* bluetoothEsp32)
|
||||||
if (rxValue.length() > 0) {
|
: _bluetoothEsp32(bluetoothEsp32 ) {
|
||||||
_bluetoothEsp32->receive((uint8_t *)(rxValue.c_str()), rxValue.length());
|
}
|
||||||
}
|
|
||||||
}
|
protected:
|
||||||
};
|
BLEMIDI_ESP32* _bluetoothEsp32 = nullptr;
|
||||||
|
|
||||||
bool BLEMIDI_ESP32::begin(const char* deviceName, BLEMIDITransport<class BLEMIDI_ESP32>* bleMidiTransport)
|
void onWrite(BLECharacteristic * characteristic) {
|
||||||
{
|
std::string rxValue = characteristic->getValue();
|
||||||
_bleMidiTransport = bleMidiTransport;
|
if (rxValue.length() > 0) {
|
||||||
|
_bluetoothEsp32->receive((uint8_t *)(rxValue.c_str()), rxValue.length());
|
||||||
BLEDevice::init(deviceName);
|
}
|
||||||
|
}
|
||||||
_server = BLEDevice::createServer();
|
};
|
||||||
_server->setCallbacks(new MyServerCallbacks(this));
|
|
||||||
|
bool BLEMIDI_ESP32::begin(const char* deviceName, BLEMIDITransport<class BLEMIDI_ESP32>* bleMidiTransport)
|
||||||
// Create the BLE Service
|
{
|
||||||
auto service = _server->createService(BLEUUID(SERVICE_UUID));
|
_bleMidiTransport = bleMidiTransport;
|
||||||
|
|
||||||
// Create a BLE Characteristic
|
BLEDevice::init(deviceName);
|
||||||
_characteristic = service->createCharacteristic(
|
|
||||||
BLEUUID(CHARACTERISTIC_UUID),
|
// To communicate between the 2 cores.
|
||||||
BLECharacteristic::PROPERTY_READ |
|
// Core_0 runs here, core_1 runs the BLE stack
|
||||||
BLECharacteristic::PROPERTY_WRITE |
|
mRxQueue = xQueueCreate(64, sizeof(uint8_t)); // TODO Settings::MaxBufferSize
|
||||||
BLECharacteristic::PROPERTY_NOTIFY |
|
|
||||||
BLECharacteristic::PROPERTY_WRITE_NR
|
_server = BLEDevice::createServer();
|
||||||
);
|
_server->setCallbacks(new MyServerCallbacks(this));
|
||||||
// Add CCCD 0x2902 to allow notify
|
|
||||||
_characteristic->addDescriptor(new BLE2902());
|
// Create the BLE Service
|
||||||
|
auto service = _server->createService(BLEUUID(SERVICE_UUID));
|
||||||
_characteristic->setCallbacks(new MyCharacteristicCallbacks(this));
|
|
||||||
// Start the service
|
// Create a BLE Characteristic
|
||||||
service->start();
|
_characteristic = service->createCharacteristic(
|
||||||
|
BLEUUID(CHARACTERISTIC_UUID),
|
||||||
auto advertisementData = BLEAdvertisementData();
|
BLECharacteristic::PROPERTY_READ |
|
||||||
advertisementData.setFlags(0x04);
|
BLECharacteristic::PROPERTY_WRITE |
|
||||||
advertisementData.setCompleteServices(BLEUUID(SERVICE_UUID));
|
BLECharacteristic::PROPERTY_NOTIFY |
|
||||||
advertisementData.setName(deviceName);
|
BLECharacteristic::PROPERTY_WRITE_NR
|
||||||
|
);
|
||||||
// Start advertising
|
// Add CCCD 0x2902 to allow notify
|
||||||
_advertising = _server->getAdvertising();
|
_characteristic->addDescriptor(new BLE2902());
|
||||||
_advertising->setAdvertisementData(advertisementData);
|
|
||||||
_advertising->start();
|
_characteristic->setCallbacks(new MyCharacteristicCallbacks(this));
|
||||||
|
// Start the service
|
||||||
return true;
|
service->start();
|
||||||
}
|
|
||||||
|
auto advertisementData = BLEAdvertisementData();
|
||||||
END_BLEMIDI_NAMESPACE
|
advertisementData.setFlags(0x04);
|
||||||
|
advertisementData.setCompleteServices(BLEUUID(SERVICE_UUID));
|
||||||
|
advertisementData.setName(deviceName);
|
||||||
|
|
||||||
|
// Start advertising
|
||||||
|
_advertising = _server->getAdvertising();
|
||||||
|
_advertising->setAdvertisementData(advertisementData);
|
||||||
|
_advertising->start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Create an instance for ESP32 named <DeviceName>
|
||||||
|
*/
|
||||||
|
#define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \
|
||||||
|
BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32> BLE##Name(DeviceName); \
|
||||||
|
MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32>, MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32> &)BLE##Name);
|
||||||
|
|
||||||
|
/*! \brief Create a default instance for ESP32 named BLE-MIDI
|
||||||
|
*/
|
||||||
|
#define BLEMIDI_CREATE_DEFAULT_INSTANCE() \
|
||||||
|
BLEMIDI_CREATE_INSTANCE("BLE-MIDI", MIDI)
|
||||||
|
|
||||||
|
END_BLEMIDI_NAMESPACE
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Headers for nRF52 BLE
|
||||||
|
//#include "BLECharacteristic.h"
|
||||||
|
//#include "BLEService.h"
|
||||||
|
|
||||||
|
BEGIN_BLEMIDI_NAMESPACE
|
||||||
|
|
||||||
|
class BLEMIDI_nRF52
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
BLEMIDITransport<class BLEMIDI_nRF52>* _bleMidiTransport = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BLEMIDI_nRF52()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool begin(const char*, BLEMIDITransport<class BLEMIDI_nRF52>*);
|
||||||
|
|
||||||
|
void write(uint8_t* buffer, size_t length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The general form of a MIDI message follows:
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
void receive(uint8_t* buffer, size_t length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void connected()
|
||||||
|
{
|
||||||
|
if (_bleMidiTransport->_connectedCallback)
|
||||||
|
_bleMidiTransport->_connectedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnected()
|
||||||
|
{
|
||||||
|
if (_bleMidiTransport->_disconnectedCallback)
|
||||||
|
_bleMidiTransport->_disconnectedCallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool BLEMIDI_nRF52::begin(const char* deviceName, BLEMIDITransport<class BLEMIDI_nRF52>* bleMidiTransport)
|
||||||
|
{
|
||||||
|
_bleMidiTransport = bleMidiTransport;
|
||||||
|
|
||||||
|
// Config the peripheral connection with maximum bandwidth
|
||||||
|
// more SRAM required by SoftDevice
|
||||||
|
// Note: All config***() function must be called before begin()
|
||||||
|
// Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
|
||||||
|
|
||||||
|
// Bluefruit.begin();
|
||||||
|
// Bluefruit.setName(deviceName);
|
||||||
|
// Bluefruit.setTxPower(4); // Check bluefruit.h for supported values
|
||||||
|
|
||||||
|
// Setup the on board blue LED to be enabled on CONNECT
|
||||||
|
// Bluefruit.autoConnLed(true);
|
||||||
|
|
||||||
|
// Configure and Start Device Information Service
|
||||||
|
// bledis.setManufacturer("Adafruit Industries");
|
||||||
|
// bledis.setModel("Bluefruit Feather52");
|
||||||
|
// bledis.begin();
|
||||||
|
|
||||||
|
// Start advertising
|
||||||
|
// Set General Discoverable Mode flag
|
||||||
|
// Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
|
||||||
|
|
||||||
|
// Advertise TX Power
|
||||||
|
// Bluefruit.Advertising.addTxPower();
|
||||||
|
|
||||||
|
// Advertise BLE MIDI Service
|
||||||
|
// Bluefruit.Advertising.addService(blemidi);
|
||||||
|
|
||||||
|
// Secondary Scan Response packet (optional)
|
||||||
|
// Since there is no room for 'Name' in Advertising packet
|
||||||
|
// Bluefruit.ScanResponse.addName();
|
||||||
|
|
||||||
|
/* Start Advertising
|
||||||
|
* - Enable auto advertising if disconnected
|
||||||
|
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
|
||||||
|
* - Timeout for fast mode is 30 seconds
|
||||||
|
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
|
||||||
|
*
|
||||||
|
* For recommended advertising interval
|
||||||
|
* https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||||
|
*/
|
||||||
|
// Bluefruit.Advertising.restartOnDisconnect(true);
|
||||||
|
// Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
||||||
|
// Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||||
|
// Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Create an instance for nRF52 named <DeviceName>
|
||||||
|
*/
|
||||||
|
#define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \
|
||||||
|
BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_nRF52> BLE##Name(DeviceName); \
|
||||||
|
MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_nRF52>, MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDITransport<BLEMIDI_NAMESPACE::BLEMIDI_nRF52> &)BLE##Name);
|
||||||
|
|
||||||
|
/*! \brief Create a default instance for nRF52 named BLE-MIDI
|
||||||
|
*/
|
||||||
|
#define BLEMIDI_CREATE_DEFAULT_INSTANCE() \
|
||||||
|
BLEMIDI_CREATE_INSTANCE("BLE-MIDI", MIDI)
|
||||||
|
|
||||||
|
END_BLEMIDI_NAMESPACE
|
||||||
Loading…
Reference in New Issue