From 7d5944f37aebe743e58211be6e7cad13811fab08 Mon Sep 17 00:00:00 2001 From: lathoub <4082369+lathoub@users.noreply.github.com> Date: Sun, 13 Sep 2020 22:37:10 +0200 Subject: [PATCH] added initial support for nRF52, cleanup ESP32 --- examples/Basic_IO/Basic_IO.ino | 4 +- examples/MidiBle/MidiBle.ino | 31 +- library.properties | 2 +- src/BLE-MIDI.h | 31 +- src/hardware/{BLE-MIDI_ESP32.h => ESP32.h} | 483 +++++++++++---------- src/hardware/nRF52.h | 136 ++++++ 6 files changed, 416 insertions(+), 271 deletions(-) rename src/hardware/{BLE-MIDI_ESP32.h => ESP32.h} (80%) mode change 100755 => 100644 create mode 100644 src/hardware/nRF52.h diff --git a/examples/Basic_IO/Basic_IO.ino b/examples/Basic_IO/Basic_IO.ino index dd49631..0881b8e 100644 --- a/examples/Basic_IO/Basic_IO.ino +++ b/examples/Basic_IO/Basic_IO.ino @@ -1,11 +1,11 @@ #include -#include +#include // Simple tutorial on how to receive and send MIDI messages. // Here, when receiving any message on channel 4, the Arduino // will blink a led and play back a note for 1 second. -BLEMIDI_CREATE_DEFAULT_ESP32_INSTANCE() +BLEMIDI_CREATE_DEFAULT_INSTANCE() void setup() { diff --git a/examples/MidiBle/MidiBle.ino b/examples/MidiBle/MidiBle.ino index 50cd632..824ebb7 100644 --- a/examples/MidiBle/MidiBle.ino +++ b/examples/MidiBle/MidiBle.ino @@ -1,7 +1,8 @@ #include -#include +#include +//#include -BLEMIDI_CREATE_DEFAULT_ESP32_INSTANCE() +BLEMIDI_CREATE_DEFAULT_INSTANCE() unsigned long t0 = millis(); bool isConnected = false; @@ -15,13 +16,13 @@ void setup() while (!Serial); Serial.println("Booting"); - MIDI.begin(1); + MIDI.begin(); - BLEMIDI.onConnected(OnBleMidiConnected); - BLEMIDI.onDisconnected(OnBleMidiDisconnected); + BLEMIDI.setHandleConnected(OnConnected); + BLEMIDI.setHandleDisconnected(OnDisconnected); - MIDI.setHandleNoteOn(OnBleMidiNoteOn); - MIDI.setHandleNoteOff(OnBleMidiNoteOff); + MIDI.setHandleNoteOn(OnNoteOn); + MIDI.setHandleNoteOff(OnNoteOff); Serial.println(F("Ready")); } @@ -47,25 +48,25 @@ void loop() // ==================================================================================== // ----------------------------------------------------------------------------- -// rtpMIDI session. Device connected +// Device connected // ----------------------------------------------------------------------------- -void OnBleMidiConnected() { +void OnConnected() { Serial.println(F("Connected")); isConnected = true; } // ----------------------------------------------------------------------------- -// rtpMIDI session. Device disconnected +// Device disconnected // ----------------------------------------------------------------------------- -void OnBleMidiDisconnected() { +void OnDisconnected() { Serial.println(F("Disconnected")); 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(channel); 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(channel); Serial.print(F(" note:")); diff --git a/library.properties b/library.properties index e1c3263..f07e99e 100644 --- a/library.properties +++ b/library.properties @@ -7,4 +7,4 @@ paragraph=MIDI over Bluetooth Low Energy category=Communication url=https://github.com/lathoub/Arduino-BLE-MIDI architectures=* -includes=BLEMIDI.h +includes=BLE-MIDI.h diff --git a/src/BLE-MIDI.h b/src/BLE-MIDI.h index 2afe691..d14d46a 100755 --- a/src/BLE-MIDI.h +++ b/src/BLE-MIDI.h @@ -48,7 +48,7 @@ public: // To communicate between the 2 cores. // 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) @@ -86,7 +86,7 @@ public: unsigned available() { 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; mRxBuffer[mRxIndex++] = byte; @@ -95,7 +95,7 @@ public: } public: - QueueHandle_t mRxQueue; +// QueueHandle_t mRxQueue; protected: /* @@ -161,11 +161,11 @@ public: void(*_disconnectedCallback)() = nullptr; public: - void onConnected(void(*fptr)()) { + void setHandleConnected(void(*fptr)()) { _connectedCallback = fptr; } - void onDisconnected(void(*fptr)()) { + void setHandleDisconnected(void(*fptr)()) { _disconnectedCallback = fptr; } @@ -173,23 +173,8 @@ public: END_BLEMIDI_NAMESPACE - struct MySettings : public MIDI_NAMESPACE::DefaultSettings - { +struct MySettings : public MIDI_NAMESPACE::DefaultSettings +{ static const bool Use1ByteParsing = false; - }; +}; -/*! \brief Create an instance of the library - */ -#define BLEMIDI_CREATE_INSTANCE(Type, DeviceName, Name) \ -BLEMIDI_NAMESPACE::BLEMIDITransport BLE##Name(DeviceName); \ -MIDI_NAMESPACE::MidiInterface, MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDITransport &)BLE##Name); - - /*! \brief Create an instance for ESP32 named - */ -#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") diff --git a/src/hardware/BLE-MIDI_ESP32.h b/src/hardware/ESP32.h old mode 100755 new mode 100644 similarity index 80% rename from src/hardware/BLE-MIDI_ESP32.h rename to src/hardware/ESP32.h index 98ed95b..0895194 --- a/src/hardware/BLE-MIDI_ESP32.h +++ b/src/hardware/ESP32.h @@ -1,230 +1,253 @@ -#pragma once - -// Headers for ESP32 BLE -#include -#include -#include -#include - -BEGIN_BLEMIDI_NAMESPACE - -class BLEMIDI_ESP32 -{ -private: - BLEServer* _server = nullptr; - BLEAdvertising* _advertising = nullptr; - BLECharacteristic* _characteristic = nullptr; - - BLEMIDITransport* _bleMidiTransport = nullptr; - -public: - BLEMIDI_ESP32() - { - } - - bool begin(const char*, BLEMIDITransport*); - - 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. - 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) - { - // Pointers used to search through payload. - uint8_t lPtr = 0; - uint8_t rPtr = 0; - // lastStatus used to capture runningStatus - uint8_t lastStatus; - // Decode first packet -- SHALL be "Full MIDI message" - lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status" - - //While statement contains incrementing pointers and breaks when buffer size exceeded. - while (true) - { - lastStatus = buffer[lPtr]; - - if( (buffer[lPtr] < 0x80)) - return; // Status message not present, bail - - // Point to next non-data byte - rPtr = lPtr; - while( (buffer[rPtr + 1] < 0x80) && (rPtr < (length - 1)) ) - rPtr++; - if (buffer[rPtr + 1] == 0xF7) rPtr++; - - // look at l and r pointers and decode by size. - if( rPtr - lPtr < 1 ) { - // Time code or system - xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY); - } else if( rPtr - lPtr < 2 ) { - xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY); - xQueueSend(_bleMidiTransport->mRxQueue, &buffer[lPtr + 1], portMAX_DELAY); - } else if( rPtr - lPtr < 3 ) { - xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY); - xQueueSend(_bleMidiTransport->mRxQueue, &buffer[lPtr + 1], portMAX_DELAY); - xQueueSend(_bleMidiTransport->mRxQueue, &buffer[lPtr + 2], portMAX_DELAY); - } else { - // Too much data - // If not System Common or System Real-Time, send it as running status - switch(buffer[lPtr] & 0xF0) - { - case 0x80: - case 0x90: - case 0xA0: - case 0xB0: - case 0xE0: - for (auto i = lPtr; i < rPtr; i = i + 2) - { - xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY); - xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 1], portMAX_DELAY); - xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 2], portMAX_DELAY); - } - break; - case 0xC0: - case 0xD0: - for (auto i = lPtr; i < rPtr; i = i + 1) - { - xQueueSend(_bleMidiTransport->mRxQueue, &lastStatus, portMAX_DELAY); - xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 1], portMAX_DELAY); - } - break; - case 0xF0: - xQueueSend(_bleMidiTransport->mRxQueue, &buffer[lPtr], portMAX_DELAY); - for (auto i = lPtr; i < rPtr; i++) - xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i + 1], portMAX_DELAY); - break; - default: - break; - } - } - - // Point to next status - lPtr = rPtr + 2; - if(lPtr >= length) - return; //end of packet - } - } - - void connected() - { - if (_bleMidiTransport->_connectedCallback) - _bleMidiTransport->_connectedCallback(); - } - - void disconnected() - { - if (_bleMidiTransport->_disconnectedCallback) - _bleMidiTransport->_disconnectedCallback(); - } -}; - -class MyServerCallbacks: public BLEServerCallbacks { -public: - MyServerCallbacks(BLEMIDI_ESP32* bluetoothEsp32) - : _bluetoothEsp32(bluetoothEsp32) { - } - -protected: - BLEMIDI_ESP32* _bluetoothEsp32 = nullptr; - - void onConnect(BLEServer*) { - if (_bluetoothEsp32) - _bluetoothEsp32->connected(); - }; - - void onDisconnect(BLEServer*) { - if (_bluetoothEsp32) - _bluetoothEsp32->disconnected(); - } -}; - -class MyCharacteristicCallbacks: public BLECharacteristicCallbacks { -public: - MyCharacteristicCallbacks(BLEMIDI_ESP32* bluetoothEsp32) - : _bluetoothEsp32(bluetoothEsp32 ) { - } - -protected: - BLEMIDI_ESP32* _bluetoothEsp32 = nullptr; - - void onWrite(BLECharacteristic * characteristic) { - std::string rxValue = characteristic->getValue(); - if (rxValue.length() > 0) { - _bluetoothEsp32->receive((uint8_t *)(rxValue.c_str()), rxValue.length()); - } - } -}; - -bool BLEMIDI_ESP32::begin(const char* deviceName, BLEMIDITransport* bleMidiTransport) -{ - _bleMidiTransport = bleMidiTransport; - - BLEDevice::init(deviceName); - - _server = BLEDevice::createServer(); - _server->setCallbacks(new MyServerCallbacks(this)); - - // Create the BLE Service - auto service = _server->createService(BLEUUID(SERVICE_UUID)); - - // Create a BLE Characteristic - _characteristic = service->createCharacteristic( - BLEUUID(CHARACTERISTIC_UUID), - BLECharacteristic::PROPERTY_READ | - BLECharacteristic::PROPERTY_WRITE | - BLECharacteristic::PROPERTY_NOTIFY | - BLECharacteristic::PROPERTY_WRITE_NR - ); - // Add CCCD 0x2902 to allow notify - _characteristic->addDescriptor(new BLE2902()); - - _characteristic->setCallbacks(new MyCharacteristicCallbacks(this)); - // Start the service - service->start(); - - auto advertisementData = BLEAdvertisementData(); - advertisementData.setFlags(0x04); - advertisementData.setCompleteServices(BLEUUID(SERVICE_UUID)); - advertisementData.setName(deviceName); - - // Start advertising - _advertising = _server->getAdvertising(); - _advertising->setAdvertisementData(advertisementData); - _advertising->start(); - - return true; -} - -END_BLEMIDI_NAMESPACE +#pragma once + +// Headers for ESP32 BLE +#include +#include +#include +#include + +BEGIN_BLEMIDI_NAMESPACE + +class BLEMIDI_ESP32 +{ +private: + BLEServer* _server = nullptr; + BLEAdvertising* _advertising = nullptr; + BLECharacteristic* _characteristic = nullptr; + + BLEMIDITransport* _bleMidiTransport = nullptr; + +protected: + QueueHandle_t mRxQueue; + +public: + BLEMIDI_ESP32() + { + } + + bool begin(const char*, BLEMIDITransport*); + + void write(uint8_t* buffer, size_t length) + { + _characteristic->setValue(buffer, length); + _characteristic->notify(); + } + + bool available(void *pvBuffer) + { + return xQueueReceive(mRxQueue, pvBuffer, 0); // return immediately when the queue is empty + } + + /* + 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) + { + // Pointers used to search through payload. + uint8_t lPtr = 0; + uint8_t rPtr = 0; + // lastStatus used to capture runningStatus + uint8_t lastStatus; + // Decode first packet -- SHALL be "Full MIDI message" + lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status" + + //While statement contains incrementing pointers and breaks when buffer size exceeded. + while (true) + { + lastStatus = buffer[lPtr]; + + if( (buffer[lPtr] < 0x80)) + return; // Status message not present, bail + + // Point to next non-data byte + rPtr = lPtr; + while( (buffer[rPtr + 1] < 0x80) && (rPtr < (length - 1)) ) + rPtr++; + if (buffer[rPtr + 1] == 0xF7) rPtr++; + + // look at l and r pointers and decode by size. + if( rPtr - lPtr < 1 ) { + // Time code or system + xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY); + } else if( rPtr - lPtr < 2 ) { + xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY); + xQueueSend(mRxQueue, &buffer[lPtr + 1], portMAX_DELAY); + } else if( rPtr - lPtr < 3 ) { + xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY); + xQueueSend(mRxQueue, &buffer[lPtr + 1], portMAX_DELAY); + xQueueSend(mRxQueue, &buffer[lPtr + 2], portMAX_DELAY); + } else { + // Too much data + // If not System Common or System Real-Time, send it as running status + switch(buffer[lPtr] & 0xF0) + { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xE0: + for (auto i = lPtr; i < rPtr; i = i + 2) + { + xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY); + xQueueSend(mRxQueue, &buffer[i + 1], portMAX_DELAY); + xQueueSend(mRxQueue, &buffer[i + 2], portMAX_DELAY); + } + break; + case 0xC0: + case 0xD0: + for (auto i = lPtr; i < rPtr; i = i + 1) + { + xQueueSend(mRxQueue, &lastStatus, portMAX_DELAY); + xQueueSend(mRxQueue, &buffer[i + 1], portMAX_DELAY); + } + break; + case 0xF0: + xQueueSend(mRxQueue, &buffer[lPtr], portMAX_DELAY); + for (auto i = lPtr; i < rPtr; i++) + xQueueSend(mRxQueue, &buffer[i + 1], portMAX_DELAY); + break; + default: + break; + } + } + + // Point to next status + lPtr = rPtr + 2; + if(lPtr >= length) + return; //end of packet + } + } + + void connected() + { + if (_bleMidiTransport->_connectedCallback) + _bleMidiTransport->_connectedCallback(); + } + + void disconnected() + { + if (_bleMidiTransport->_disconnectedCallback) + _bleMidiTransport->_disconnectedCallback(); + } +}; + +class MyServerCallbacks: public BLEServerCallbacks { +public: + MyServerCallbacks(BLEMIDI_ESP32* bluetoothEsp32) + : _bluetoothEsp32(bluetoothEsp32) { + } + +protected: + BLEMIDI_ESP32* _bluetoothEsp32 = nullptr; + + void onConnect(BLEServer*) { + if (_bluetoothEsp32) + _bluetoothEsp32->connected(); + }; + + void onDisconnect(BLEServer*) { + if (_bluetoothEsp32) + _bluetoothEsp32->disconnected(); + } +}; + +class MyCharacteristicCallbacks: public BLECharacteristicCallbacks { +public: + MyCharacteristicCallbacks(BLEMIDI_ESP32* bluetoothEsp32) + : _bluetoothEsp32(bluetoothEsp32 ) { + } + +protected: + BLEMIDI_ESP32* _bluetoothEsp32 = nullptr; + + void onWrite(BLECharacteristic * characteristic) { + std::string rxValue = characteristic->getValue(); + if (rxValue.length() > 0) { + _bluetoothEsp32->receive((uint8_t *)(rxValue.c_str()), rxValue.length()); + } + } +}; + +bool BLEMIDI_ESP32::begin(const char* deviceName, BLEMIDITransport* bleMidiTransport) +{ + _bleMidiTransport = bleMidiTransport; + + BLEDevice::init(deviceName); + + // To communicate between the 2 cores. + // Core_0 runs here, core_1 runs the BLE stack + mRxQueue = xQueueCreate(64, sizeof(uint8_t)); // TODO Settings::MaxBufferSize + + _server = BLEDevice::createServer(); + _server->setCallbacks(new MyServerCallbacks(this)); + + // Create the BLE Service + auto service = _server->createService(BLEUUID(SERVICE_UUID)); + + // Create a BLE Characteristic + _characteristic = service->createCharacteristic( + BLEUUID(CHARACTERISTIC_UUID), + BLECharacteristic::PROPERTY_READ | + BLECharacteristic::PROPERTY_WRITE | + BLECharacteristic::PROPERTY_NOTIFY | + BLECharacteristic::PROPERTY_WRITE_NR + ); + // Add CCCD 0x2902 to allow notify + _characteristic->addDescriptor(new BLE2902()); + + _characteristic->setCallbacks(new MyCharacteristicCallbacks(this)); + // Start the service + service->start(); + + auto advertisementData = BLEAdvertisementData(); + 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 + */ +#define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \ +BLEMIDI_NAMESPACE::BLEMIDITransport BLE##Name(DeviceName); \ +MIDI_NAMESPACE::MidiInterface, MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDITransport &)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 diff --git a/src/hardware/nRF52.h b/src/hardware/nRF52.h new file mode 100644 index 0000000..68116f3 --- /dev/null +++ b/src/hardware/nRF52.h @@ -0,0 +1,136 @@ +#pragma once + +// Headers for nRF52 BLE +//#include "BLECharacteristic.h" +//#include "BLEService.h" + +BEGIN_BLEMIDI_NAMESPACE + +class BLEMIDI_nRF52 +{ +private: + + BLEMIDITransport* _bleMidiTransport = nullptr; + +public: + BLEMIDI_nRF52() + { + } + + bool begin(const char*, BLEMIDITransport*); + + 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* 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 + */ +#define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \ +BLEMIDI_NAMESPACE::BLEMIDITransport BLE##Name(DeviceName); \ +MIDI_NAMESPACE::MidiInterface, MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDITransport &)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