Compare commits

...

69 Commits

Author SHA1 Message Date
lathoub 929c2fc049
Merge pull request #65 from aselectroworks/ESP32-BLE_Client
fix panic'ed bug when call BLEMIDI_Client_ESP32::end() is called
2022-09-19 12:02:41 +02:00
Atsushi Sasaki 8e740fb499 fix panic'ed bug when call BLEMIDI_Client_ESP32::end() is called 2022-09-19 17:38:11 +09:00
lathoub 8dee1f7d25
Update build-arduino.sh 2022-01-20 07:35:28 +01:00
lathoub 498d192e97
Update build-arduino.sh 2022-01-20 07:32:53 +01:00
lathoub 8b7eb46277
Delete arduino-cli.yaml 2022-01-20 07:29:32 +01:00
lathoub ada4b3ce57
Update build-arduino.sh 2022-01-20 07:19:50 +01:00
lathoub 9f04bcfdd7
Update build-arduino.sh 2022-01-20 07:17:15 +01:00
lathoub 40fd2c241c
Update build-arduino.sh 2022-01-20 07:15:25 +01:00
lathoub 741e713ebf
Update build-arduino.sh 2022-01-20 06:57:11 +01:00
lathoub c2815355d7
Update arduino-cli.yaml 2022-01-20 05:56:59 +01:00
lathoub 564c5a9dde
Update build-arduino.sh 2022-01-20 05:55:26 +01:00
lathoub 4b455f695e
Update build-arduino.sh 2022-01-20 05:54:06 +01:00
lathoub a8cb8f3582
Update build-arduino.sh 2022-01-20 05:53:13 +01:00
lathoub 354c75ed60
Create arduino-cli.yaml 2022-01-20 05:52:49 +01:00
lathoub 39ce9ff6d6
Merge pull request #49 from lathoub/v2.2
new v2.2
2022-01-20 05:39:23 +01:00
lathoub 656d7376fe
Create build.yml 2022-01-20 05:37:44 +01:00
lathoub b1e968f492 new v2.2 2022-01-20 05:32:44 +01:00
lathoub def06b13ef
Merge pull request #48 from RobertoHE/master
Disable Soft-Reconnection, thank you @RobertoHE !
2022-01-19 14:17:41 +01:00
Roberto ebe18daaea Bug fixed of dad42b4dde (diff-bf9bc149421b933caf483239631a8722a328bfd41cd331fa986737433b42fcd7). 2022-01-18 16:51:55 +01:00
Roberto dad42b4dde Force New Connection
Add functionalities for https://github.com/lathoub/Arduino-BLE-MIDI/issues/40 issue.
2021-12-23 18:41:39 +01:00
lathoub 5c42e14704
Update library.properties 2021-12-09 09:51:42 +01:00
lathoub 36999ecf28
Merge pull request #39 from alf45tar/master
Moved SERVICE_UUID and CHARACTERISTIC_UUID inside namespace to avoid conflicts
Thank you @alf45tar
2021-12-09 09:50:55 +01:00
alf45tar 3f9b48cb1a
Moved SERVICE_UUID and CHARACTERISTIC_UUID inside namespace to avoid conflicts 2021-12-08 12:51:48 +01:00
alf45tar f8236efa5f
Moved SERVICE_UUID and CHARACTERISTIC_UUID inside namespace to avoid conflicts 2021-12-08 12:49:56 +01:00
lathoub 4724511fa8
Update README.md 2021-09-24 12:01:16 +02:00
lathoub c05b5301c5
Update README.md 2021-09-24 11:58:09 +02:00
lathoub 5698c0c4ae
added support for RP2040 2021-09-24 11:56:13 +02:00
lathoub dbeadf5a7f events return a pointer to this for easy event chaining 2021-09-23 22:25:31 +02:00
lathoub 950ff4e219 updated parser for MultiPart SysEx
Thanks to @RobertoHE
2021-09-23 17:44:40 +02:00
lathoub e0afefb9a2 re-advertise after disconnect (ESP32 & ESP32_NimBLE) 2021-09-22 22:42:12 +02:00
lathoub 927b3ac8be
Merge pull request #36 from RobertoHE/master
Improve transmissions in client mode (thank you @RobertoHE)
2021-09-21 22:06:03 +02:00
Roberto b3df11a0ea Update Communication Parameters 2021-09-21 18:22:25 +02:00
Roberto 6ea32b340f Transmision power 2021-09-21 18:16:13 +02:00
RobertoHE f9ad1e5b83
Transmition speed Improved WriteNoResponse
Now it sends data to server in Write Without Response mode. This increase the transmission speed and it get adapted to MIDI over BLE protocol.
Some devices needs a first message with confirmation for clean security flags. After a connection or after an error, the first message is sended like Write (with response).
2021-09-21 17:39:06 +02:00
lathoub 6045d2270c setName 2021-09-19 16:48:20 +02:00
lathoub 3b08fec7da
remove duplicate end()
thanks @alf45tar for spotting!
2021-08-10 17:02:41 +02:00
lathoub 697e0d40b0
Delete BLE-MIDI_Client_ESP32.h
see PR #30
2021-08-06 09:12:51 +02:00
lathoub f1e0982e6b
Merge pull request #30 from RobertoHE/master
Client for BLEMIDI
2021-08-06 09:11:31 +02:00
RobertoHE 3c8f54c459
Create BLE-MIDI_Client_ESP32.h
For pull request only
2021-08-06 08:29:48 +02:00
RobertoHE c87819b42e
Delete src/hardware/src directory 2021-08-06 08:27:37 +02:00
RobertoHE ab1dd1567f
Create BLE-MIDI_Client_ESP32.h 2021-08-06 08:23:03 +02:00
lathoub 841754ce96 Update .gitignore 2021-08-06 06:55:46 +02:00
RobertoHE ad26e7b4ed
Undo Changes for PullRequest
Conflict with other opened pull request
2021-08-06 00:00:04 +02:00
Roberto 31817fba8e Parser Upgraded 2021-08-05 21:31:42 +02:00
RobertoHE 6d00baaf53
Merge pull request #1 from RobertoHE/Client_Upgrade
Update and simplify connect()
2021-08-05 17:41:40 +02:00
Roberto 586207d747 Some little modification in Scan times.
Removed a printf in Connect()
Removed avaliableSpace
2021-08-05 17:39:33 +02:00
RobertoHE 895089174b
Update and simplify connect()
(UNTESTED)
Connect() method is simplified. Only one client connection by object is allowed now. If any connection step fails during connection setup, this client is deleted and reset. This deleted client doesn't ocupe for NIMBLE_MAX_CONNECTIONS count now.
Some Serial.print() traces was commented.
Now NotifyCB() doesn't check space available in rx buffer.
2021-08-05 10:58:02 +02:00
Roberto 4e52f70062 Modified received(). Running Status and divided SysEx are accepted 2021-08-04 17:39:48 +02:00
Roberto 5a0fd77bc6 added a newline at the end of file 2021-07-09 19:13:46 +02:00
Roberto 43d9cfbc35 README.md equal like master repo 2021-07-09 19:11:18 +02:00
Roberto 49f7ec93db Removed non-functional BLE-MIDI_Client_ESP32.h 2021-07-09 18:40:21 +02:00
Roberto 5f7d493acd Added characterisctic protecction in write(). Clean-up the code 2021-07-09 18:36:37 +02:00
Roberto 665f343d74 Example added 2021-07-09 18:33:25 +02:00
Roberto 60cfe28c45 Merge branch 'master' of https://github.com/RobertoHE/Arduino-BLE-MIDI 2021-07-03 11:08:41 +02:00
Roberto b830648af4 Limpieza y estructuracion del codigo. Se han añadido defines al inicio del fichero para que modificar las caracteristicas de seguridad, nombre y parámetros de comunicacion. TODO: No depender del método read(), que salten los callback de manera automática 2021-07-03 11:08:22 +02:00
RobertoHE 65d96380b8 test 2021-06-08 16:12:04 +02:00
Roberto b8831e4d3e Reconnect mechanism done in avaliable funcion. Avaliable is called in MIDI.read() in funtional code. FIXED: Write method now works. TODO: Clear debug comments and structure the code. Change scanDone and doConnect global variables inside AdviceCB class. BUG: If input buffer is completly full it is not possible send or recive anything 2021-06-05 14:19:52 +02:00
Roberto 75069b93ea First stable client connection. TODO: autoReconnect and ConnectTo 2021-05-31 18:46:43 +02:00
lathoub aa0f6bc44a added end() method, stop'ping BLE 2021-05-28 21:06:07 +02:00
lathoub e0fb12b9c0
Merge pull request #28 from per1234/mbed_nano
Add mbed_nano to list of compatible architectures
2021-05-06 09:01:21 +02:00
per1234 37ac074af7
Add mbed_nano to list of compatible architectures
In the 2.0.0 release of the Arduino Mbed OS Boards platform, the mbed architecture split into four architectures:
- mbed_edge: Arduino Edge Control
- mbed_nano: Nano 33 BLE and Nano RP2040 Connect
- mbed_rp2040: Raspberry Pi Pico
- mbed_portenta: Portenta H7

The mbed architecture should be retained for backwards support, but the new mbed_nano should also be added to avoid spurious incompatibility warnings and the library's examples being shown under the File > Examples > INCOMPATIBLE menu of the Arduino IDE when the Nano 33 BLE board is selected.
2021-05-04 02:01:20 -07:00
lathoub 0cc25e9ced
Update MidiBle.ino 2020-12-20 23:38:43 +01:00
lathoub 30d101bca6
Update MidiBle.ino 2020-12-20 23:37:03 +01:00
lathoub f4927cd4ea reworked basic demo
led comes on when connected, noteOn turns it off, NoteOff turn it back on
2020-12-20 23:10:35 +01:00
lathoub 4aee6708ca Windows connection to ESP32
Windows connection to ESP32, based on suggestion from @wakwak-koba (I get notes in the MIDIBerry input monitor using ESP32, but not using NimBLE ?? (MidiBle example)
2020-10-25 22:52:27 +01:00
lathoub cc1d4ef1e1
Merge pull request #22 from wakwak-koba/ESP32_NimBLE
Fixed not being able to pair with Windows when using NimBLE, thank you @wakwak-koba !
2020-10-25 19:13:08 +01:00
wakwak_koba d8746c2967 Revert examples 2020-10-25 06:14:46 +09:00
wakwak_koba ab02fbc108 Fixed not being able to pair with Windows when using NimBLE
and, consideration for boards that don't implement the `LED_BUILTIN` constant
2020-10-23 08:12:52 +09:00
lathoub 9b41d732ef
Update README.md 2020-10-18 07:49:50 +02:00
16 changed files with 1255 additions and 364 deletions

10
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,10 @@
name: build
on: [pull_request, push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Build on Arduino CLI
run: bash ci/build-arduino.sh

4
.gitignore vendored
View File

@ -3,3 +3,7 @@ examples/.DS_Store
src/.DS_Store src/.DS_Store
.vscode/settings.json .vscode/settings.json
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
test/msvc/.vs
test/msvc/x64
test/msvc/ConsoleApplication2.vcxproj.user
test/msvc/ConsoleApplication2.vcxproj.filters

View File

@ -1,4 +1,6 @@
# Arduino BLE-MIDI Transport # Arduino BLE-MIDI Transport
[![arduino-library-badge](https://www.ardu-badge.com/badge/BLE-MIDI.svg?)](https://www.ardu-badge.com/BLE-MIDI)
This library implements the BLE-MIDI transport layer for the [FortySevenEffects Arduino MIDI Library](https://github.com/FortySevenEffects/arduino_midi_library) This library implements the BLE-MIDI transport layer for the [FortySevenEffects Arduino MIDI Library](https://github.com/FortySevenEffects/arduino_midi_library)
## Installation ## Installation
@ -9,7 +11,7 @@ When installing this library from the Arduino IDE, the dependency be downloaded
When manually installing this library, you have to manually download [Arduino MIDI Library](https://github.com/FortySevenEffects/arduino_midi_library) from github and install it in the same directory as this library - without this additional install, this library will not be able to compile. When manually installing this library, you have to manually download [Arduino MIDI Library](https://github.com/FortySevenEffects/arduino_midi_library) from github and install it in the same directory as this library - without this additional install, this library will not be able to compile.
When using `ESP32` consider using NimBLE (`NimBLE-Arduino`). When using `ESP32` consider using NimBLE (`NimBLE-Arduino`).
When using the `Arduino NANO 33 BLE`, you have to install `ArduinoBLE` When using the `Arduino NANO 33 BLE` or `Arduino NANO RP2040 Connect`, you must install `ArduinoBLE`
## Usage ## Usage
### Basic / Default ### Basic / Default
@ -65,6 +67,7 @@ will create a instance named `BLEMIDI` and listens to incoming MIDI.
## Tested boards/modules ## Tested boards/modules
- ESP32 (OOB BLE and NimBLE) - ESP32 (OOB BLE and NimBLE)
- Arduino NANO 33 BLE - Arduino NANO 33 BLE
- Arduino NANO RP2040 Connect
## Other Transport protocols: ## Other Transport protocols:
The libraries below the same calling mechanism (API), making it easy to interchange the transport layer. The libraries below the same calling mechanism (API), making it easy to interchange the transport layer.

54
ci/build-arduino.sh Normal file
View File

@ -0,0 +1,54 @@
#!/bin/bash
# Exit immediately if a command exits with a non-zero status.
set -e
# Enable the globstar shell option
shopt -s globstar
# Make sure we are inside the github workspace
cd $GITHUB_WORKSPACE
# Create directories
mkdir $HOME/Arduino
mkdir $HOME/Arduino/libraries
# Install Arduino IDE
export PATH=$PATH:$GITHUB_WORKSPACE/bin
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
arduino-cli config init
arduino-cli config set library.enable_unsafe_install true
# arduino-cli core update-index --additional-urls https://arduino.esp8266.com/stable/package_esp8266com_index.json
arduino-cli core update-index --additional-urls https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
arduino-cli core update-index
# Install Arduino AVR core
arduino-cli core install arduino:avr
arduino-cli core install arduino:samd
# arduino-cli core install esp8266:esp8266
arduino-cli core install esp32:esp32
# List the boards
arduino-cli board list
# Link Arduino library
ln -s $GITHUB_WORKSPACE $HOME/Arduino/libraries/CI_Test_Library
arduino-cli lib install "MIDI library"
arduino-cli lib install ArduinoBLE
arduino-cli lib install NimBLE-Arduino
# Compile all *.ino files for the Arduino Uno
# for f in **/AVR_*.ino ; do
# arduino-cli compile -b arduino:avr:uno $f
# done
# Compile all *.ino files for the Arduino Uno
# for f in **/SAMD_*.ino ; do
# arduino-cli compile -b arduino:samd:mkrzero $f
# done
# Compile all *.ino files for the Arduino Uno
# for f in **/ESP8266_*.ino ; do
# arduino-cli compile -b arduino:esp8266:??? $f
# done
# Compile all *.ino files for the Arduino Uno
for f in **/*.ino ; do
arduino-cli compile -b arduino:esp32:??? $f
done

0
doc/spec.md Normal file
View File

View File

@ -1,7 +1,7 @@
#include <BLEMIDI_Transport.h> #include <BLEMIDI_Transport.h>
#include <hardware/BLEMIDI_ESP32_NimBLE.h> //#include <hardware/BLEMIDI_ESP32_NimBLE.h>
//#include <hardware/BLEMIDI_ESP32.h> #include <hardware/BLEMIDI_ESP32.h>
//#include <hardware/BLEMIDI_nRF52.h> //#include <hardware/BLEMIDI_nRF52.h>
//#include <hardware/BLEMIDI_ArduinoBLE.h> //#include <hardware/BLEMIDI_ArduinoBLE.h>
@ -11,7 +11,9 @@ unsigned long t0 = millis();
bool isConnected = false; bool isConnected = false;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// // When BLE connected, LED will turn on (indication that connection was successful)
// When receiving a NoteOn, LED will go out, on NoteOff, light comes back on.
// This is an easy and conveniant way to show that the connection is alive and working.
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void setup() void setup()
{ {
@ -20,11 +22,22 @@ void setup()
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW); digitalWrite(LED_BUILTIN, LOW);
BLEMIDI.setHandleConnected(OnConnected); BLEMIDI.setHandleConnected([]() {
BLEMIDI.setHandleDisconnected(OnDisconnected); isConnected = true;
digitalWrite(LED_BUILTIN, HIGH);
});
MIDI.setHandleNoteOn(OnNoteOn); BLEMIDI.setHandleDisconnected([]() {
MIDI.setHandleNoteOff(OnNoteOff); isConnected = false;
digitalWrite(LED_BUILTIN, LOW);
});
MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity) {
digitalWrite(LED_BUILTIN, LOW);
});
MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity) {
digitalWrite(LED_BUILTIN, HIGH);
});
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -38,38 +51,6 @@ void loop()
{ {
t0 = millis(); t0 = millis();
MIDI.sendNoteOn (60, 100, 1); // note 60, velocity 127 on channel 1 MIDI.sendNoteOn (60, 100, 1); // note 60, velocity 100 on channel 1
} }
} }
// ====================================================================================
// Event handlers for incoming MIDI messages
// ====================================================================================
// -----------------------------------------------------------------------------
// Device connected
// -----------------------------------------------------------------------------
void OnConnected() {
isConnected = true;
digitalWrite(LED_BUILTIN, HIGH);
}
// -----------------------------------------------------------------------------
// Device disconnected
// -----------------------------------------------------------------------------
void OnDisconnected() {
isConnected = false;
digitalWrite(LED_BUILTIN, LOW);
}
// -----------------------------------------------------------------------------
// Received note on
// -----------------------------------------------------------------------------
void OnNoteOn(byte channel, byte note, byte velocity) {
}
// -----------------------------------------------------------------------------
// Received note off
// -----------------------------------------------------------------------------
void OnNoteOff(byte channel, byte note, byte velocity) {
}

View File

@ -0,0 +1,141 @@
/**
* --------------------------------------------------------
* This example shows how to use client MidiBLE
* Client BLEMIDI works im a similar way Server (Common) BLEMIDI, but with some exception.
*
* The most importart exception is read() method. This function works as usual, but
* now it manages machine-states BLE connection too. The
* read() function must be called several times continuously in order to scan BLE device
* and connect with the server. In this example, read() is called in a "multitask function of
* FreeRTOS", but it can be called in loop() function as usual.
*
* Some BLEMIDI_CREATE_INSTANCE() are added in MidiBLE-Client to be able to choose a specific server to connect
* or to connect to the first server which has the MIDI characteristic. You can choose the server by typing in the name field
* the name of the server or the BLE address of the server. If you want to connect
* to the first MIDI server BLE found by the device, you just have to set the name field empty ("").
*
* FOR ADVANCED USERS: Other advanced BLE configurations can be changed in hardware/BLEMIDI_Client_ESP32.h
* #defines in the head of the file (IMPORTANT: Only the first user defines must be modified). These configurations
* are related to security (password, pairing and securityCallback()), communication params, the device name
* and other stuffs. Modify defines at your own risk.
*
*
*
* @auth RobertoHE
* --------------------------------------------------------
*/
#include <Arduino.h>
#include <BLEMIDI_Transport.h>
#include <hardware/BLEMIDI_Client_ESP32.h>
//#include <hardware/BLEMIDI_ESP32_NimBLE.h>
//#include <hardware/BLEMIDI_ESP32.h>
//#include <hardware/BLEMIDI_nRF52.h>
//#include <hardware/BLEMIDI_ArduinoBLE.h>
BLEMIDI_CREATE_DEFAULT_INSTANCE(); //Connect to first server found
//BLEMIDI_CREATE_INSTANCE("",MIDI) //Connect to the first server found
//BLEMIDI_CREATE_INSTANCE("f2:c1:d9:36:e7:6b",MIDI) //Connect to a specific BLE address server
//BLEMIDI_CREATE_INSTANCE("MyBLEserver",MIDI) //Connect to a specific name server
#ifndef LED_BUILTIN
#define LED_BUILTIN 2 //modify for match with yout board
#endif
void ReadCB(void *parameter); //Continuos Read function (See FreeRTOS multitasks)
unsigned long t0 = millis();
bool isConnected = false;
/**
* -----------------------------------------------------------------------------
* When BLE is connected, LED will turn on (indicating that connection was successful)
* When receiving a NoteOn, LED will go out, on NoteOff, light comes back on.
* This is an easy and conveniant way to show that the connection is alive and working.
* -----------------------------------------------------------------------------
*/
void setup()
{
Serial.begin(115200);
MIDI.begin(MIDI_CHANNEL_OMNI);
BLEMIDI.setHandleConnected([]()
{
Serial.println("---------CONNECTED---------");
isConnected = true;
digitalWrite(LED_BUILTIN, HIGH);
});
BLEMIDI.setHandleDisconnected([]()
{
Serial.println("---------NOT CONNECTED---------");
isConnected = false;
digitalWrite(LED_BUILTIN, LOW);
});
MIDI.setHandleNoteOn([](byte channel, byte note, byte velocity)
{
Serial.print("NoteON: CH: ");
Serial.print(channel);
Serial.print(" | ");
Serial.print(note);
Serial.print(", ");
Serial.println(velocity);
digitalWrite(LED_BUILTIN, LOW);
});
MIDI.setHandleNoteOff([](byte channel, byte note, byte velocity)
{
digitalWrite(LED_BUILTIN, HIGH);
});
xTaskCreatePinnedToCore(ReadCB, //See FreeRTOS for more multitask info
"MIDI-READ",
3000,
NULL,
1,
NULL,
1); //Core0 or Core1
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void loop()
{
//MIDI.read(); // This function is called in the other task
if (isConnected && (millis() - t0) > 1000)
{
t0 = millis();
MIDI.sendNoteOn(60, 100, 1); // note 60, velocity 100 on channel 1
vTaskDelay(250/portTICK_PERIOD_MS);
MIDI.sendNoteOff(60, 0, 1);
}
}
/**
* This function is called by xTaskCreatePinnedToCore() to perform a multitask execution.
* In this task, read() is called every millisecond (approx.).
* read() function performs connection, reconnection and scan-BLE functions.
* Call read() method repeatedly to perform a successfull connection with the server
* in case connection is lost.
*/
void ReadCB(void *parameter)
{
// Serial.print("READ Task is started on core: ");
// Serial.println(xPortGetCoreID());
for (;;)
{
MIDI.read();
vTaskDelay(1 / portTICK_PERIOD_MS); //Feed the watchdog of FreeRTOS.
//Serial.println(uxTaskGetStackHighWaterMark(NULL)); //Only for debug. You can see the watermark of the free resources assigned by the xTaskCreatePinnedToCore() function.
}
vTaskDelay(1);
}

View File

@ -1,11 +1,11 @@
name=BLE-MIDI name=BLE-MIDI
version=2.1.0 version=2.2
author=lathoub author=lathoub
maintainer=lathoub <lathoub@gmail.com> maintainer=lathoub <lathoub@gmail.com>
sentence=BLE-MIDI I/Os for Arduino sentence=BLE-MIDI I/Os for Arduino
paragraph=MIDI over Bluetooth Low Energy (BLE-MIDI) 1.0 for Arduino paragraph=MIDI over Bluetooth Low Energy (BLE-MIDI) 1.0 for Arduino
category=Communication category=Communication
url=https://github.com/lathoub/Arduino-BLE-MIDI url=https://github.com/lathoub/Arduino-BLE-MIDI
architectures=esp32,samd,megaavr,mbed,nrf52 architectures=esp32,samd,megaavr,mbed,apollo3,mbed_nano,mbed_portenta
includes=BLEMIDI_Transport.h includes=BLEMIDI_Transport.h
depends=MIDI Library, NimBLE-Arduino, ArduinoBLE depends=MIDI Library, NimBLE-Arduino, ArduinoBLE

View File

@ -2,13 +2,6 @@
#include "BLEMIDI_Namespace.h" #include "BLEMIDI_Namespace.h"
// As specified in
// Specification for MIDI over Bluetooth Low Energy (BLE-MIDI)
// Version 1.0a, NOvember 1, 2015
// 3. BLE Service and Characteristics Definitions
#define SERVICE_UUID "03b80e5a-ede8-4b33-a751-6ce34ec4c700"
#define CHARACTERISTIC_UUID "7772e5db-3868-4112-a1a9-f2669d106bf3"
#if ARDUINO #if ARDUINO
#include <Arduino.h> #include <Arduino.h>
#else #else

View File

@ -12,7 +12,18 @@
BEGIN_BLEMIDI_NAMESPACE BEGIN_BLEMIDI_NAMESPACE
template<class T, class _Settings = DefaultSettings> using namespace MIDI_NAMESPACE;
// As specified in
// Specification for MIDI over Bluetooth Low Energy (BLE-MIDI)
// Version 1.0a, November 1, 2015
// 3. BLE Service and Characteristics Definitions
static const char *const SERVICE_UUID = "03b80e5a-ede8-4b33-a751-6ce34ec4c700";
static const char *const CHARACTERISTIC_UUID = "7772e5db-3868-4112-a1a9-f2669d106bf3";
#define MIDI_TYPE 0x80
template <class T, class _Settings = DefaultSettings>
class BLEMIDI_Transport class BLEMIDI_Transport
{ {
typedef _Settings Settings; typedef _Settings Settings;
@ -32,7 +43,7 @@ private:
T mBleClass; T mBleClass;
public: public:
BLEMIDI_Transport(const char* deviceName) BLEMIDI_Transport(const char *deviceName)
{ {
strncpy(mDeviceName, deviceName, sizeof(mDeviceName)); strncpy(mDeviceName, deviceName, sizeof(mDeviceName));
@ -48,6 +59,11 @@ public:
mBleClass.begin(mDeviceName, this); mBleClass.begin(mDeviceName, this);
} }
void end()
{
mBleClass.end();
}
bool beginTransmission(MIDI_NAMESPACE::MidiType type) bool beginTransmission(MIDI_NAMESPACE::MidiType type)
{ {
getMidiTimestamp(&mTxBuffer[0], &mTxBuffer[1]); getMidiTimestamp(&mTxBuffer[0], &mTxBuffer[1]);
@ -70,7 +86,7 @@ public:
void endTransmission() void endTransmission()
{ {
if (mTxBuffer[mTxIndex - 1] == 0xF7) if (mTxBuffer[mTxIndex - 1] == SystemExclusiveEnd)
{ {
if (mTxIndex >= sizeof(mTxBuffer)) if (mTxIndex >= sizeof(mTxBuffer))
{ {
@ -83,7 +99,7 @@ public:
{ {
mTxBuffer[mTxIndex - 1] = mTimestampLow; // or generate new ? mTxBuffer[mTxIndex - 1] = mTimestampLow; // or generate new ?
} }
mTxBuffer[mTxIndex++] = 0xF7; mTxBuffer[mTxIndex++] = SystemExclusiveEnd;
} }
mBleClass.write(mTxBuffer, mTxIndex); mBleClass.write(mTxBuffer, mTxIndex);
@ -99,10 +115,10 @@ public:
{ {
uint8_t byte; uint8_t byte;
auto success = mBleClass.available(&byte); auto success = mBleClass.available(&byte);
if (!success) return mRxIndex; if (!success)
return mRxIndex;
mRxBuffer[mRxIndex++] = byte; mRxBuffer[mRxIndex++] = byte;
return mRxIndex; return mRxIndex;
} }
@ -117,7 +133,6 @@ protected:
The header byte contains the topmost 6 bits of timing information for MIDI events in the BLE The header byte contains the topmost 6 bits of timing information for MIDI events in the BLE
packet. The remaining 7 bits of timing information for individual MIDI messages encoded in a packet. The remaining 7 bits of timing information for individual MIDI messages encoded in a
packet is expressed by timestamp bytes. packet is expressed by timestamp bytes.
Timestamp Byte Timestamp Byte
bit 7 Set to 1. bit 7 Set to 1.
bits 6-0 timestampLow: Least Significant 7 bits of timestamp information. bits 6-0 timestampLow: Least Significant 7 bits of timestamp information.
@ -152,7 +167,7 @@ protected:
and the MSB of both bytes are set to indicate that this is a header byte. and the MSB of both bytes are set to indicate that this is a header byte.
Both bytes are placed into the first two position of an array in preparation for a MIDI message. Both bytes are placed into the first two position of an array in preparation for a MIDI message.
*/ */
static void getMidiTimestamp (uint8_t *header, uint8_t *timestamp) static void getMidiTimestamp(uint8_t *header, uint8_t *timestamp)
{ {
auto currentTimeStamp = millis() & 0x01FFF; auto currentTimeStamp = millis() & 0x01FFF;
@ -160,25 +175,38 @@ protected:
*timestamp = (currentTimeStamp & 0x7F) | 0x80; // 7 bits plus MSB *timestamp = (currentTimeStamp & 0x7F) | 0x80; // 7 bits plus MSB
} }
static void setMidiTimestamp (uint8_t header, uint8_t *timestamp) static uint16_t setMidiTimestamp(uint8_t header, uint8_t timestamp)
{ {
auto timestampHigh = 0x3f & header;
auto timestampLow = 0x7f & timestamp;
return (timestampLow + (timestampHigh << 7));
} }
public: public:
// callbacks // callbacks
void(*_connectedCallback)() = nullptr; void (*_connectedCallback)() = nullptr;
void(*_disconnectedCallback)() = nullptr; void (*_disconnectedCallback)() = nullptr;
BLEMIDI_Transport &setName(const char *deviceName)
{
strncpy(mDeviceName, deviceName, sizeof(mDeviceName));
return *this;
};
public: public:
void setHandleConnected(void(*fptr)()) { BLEMIDI_Transport &setHandleConnected(void (*fptr)())
{
_connectedCallback = fptr; _connectedCallback = fptr;
return *this;
} }
void setHandleDisconnected(void(*fptr)()) { BLEMIDI_Transport &setHandleDisconnected(void (*fptr)())
{
_disconnectedCallback = fptr; _disconnectedCallback = fptr;
return *this;
} }
/* /*
The general form of a MIDI message follows: The general form of a MIDI message follows:
n-byte MIDI Message n-byte MIDI Message
Byte 0 MIDI message Status byte, Bit 7 is Set to 1. Byte 0 MIDI message Status byte, Bit 7 is Set to 1.
@ -208,83 +236,179 @@ 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(byte* buffer, size_t length)
/**
* If #define RUNNING_ENABLE is commented/disabled, it will transform all incoming runningStatus messages in full midi messages.
* Else, it will put in the buffer the same info that it had received (runningStatus will be not transformated).
* It recommend not use runningStatus by default. Only use if parser accepts runningStatus and your application has a so high transmission rate.
*/
#define RUNNING_ENABLE
void receive(byte *buffer, size_t length)
{ {
// Pointers used to search through payload. // Pointers used to search through payload.
byte lPtr = 0; int lPtr = 0;
byte rPtr = 0; int rPtr = 0;
// lastStatus used to capture runningStatus // lastStatus used to capture runningStatus
byte lastStatus; byte lastStatus;
// Decode first packet -- SHALL be "Full MIDI message" // previousStatus used to continue a runningStatus interrupted by a timeStamp or a System Message.
lPtr = 2; //Start at first MIDI status -- SHALL be "MIDI status" byte previousStatus = InvalidType;
byte headerByte = buffer[lPtr++];
auto timestampHigh = 0x3f & headerByte;
byte timestampByte = buffer[lPtr++];
uint16_t timestamp = 0;
bool sysExContinuation = false;
bool runningStatusContinuation = false;
if (timestampByte >= MIDI_TYPE) // if bit 7 is 1, it's a timestampByte
{
timestamp = setMidiTimestamp(headerByte, timestampByte);
// what do to with the timestamp?
}
else // if bit 7 is 0, it's the Continuation of a previous SysEx
{
sysExContinuation = true;
lPtr--; // the second byte is part of the SysEx
}
//While statement contains incrementing pointers and breaks when buffer size exceeded. //While statement contains incrementing pointers and breaks when buffer size exceeded.
while (true) while (true)
{ {
lastStatus = buffer[lPtr]; lastStatus = buffer[lPtr];
if( (buffer[lPtr] < 0x80)) if (previousStatus == InvalidType)
return; // Status message not present, bail {
if ((lastStatus < MIDI_TYPE) && !sysExContinuation)
return; // Status message not present and it is not a runningStatus continuation, bail
}
else if (lastStatus < MIDI_TYPE)
{
lastStatus = previousStatus;
runningStatusContinuation = true;
}
// Point to next non-data byte // Point to next non-data byte
rPtr = lPtr; rPtr = lPtr;
while( (buffer[rPtr + 1] < 0x80) && (rPtr < (length - 1)) ) while ((buffer[rPtr + 1] < MIDI_TYPE) && (rPtr < (length - 1)))
rPtr++; rPtr++;
if (buffer[rPtr + 1] == 0xF7) rPtr++;
// look at l and r pointers and decode by size. if (!runningStatusContinuation)
if( rPtr - lPtr < 1 ) {
// Time code or system
mBleClass.add(lastStatus);
} else if( rPtr - lPtr < 2 ) {
mBleClass.add(lastStatus);
mBleClass.add(buffer[lPtr + 1]);
} else if( rPtr - lPtr < 3 ) {
mBleClass.add(lastStatus);
mBleClass.add(buffer[lPtr + 1]);
mBleClass.add(buffer[lPtr + 2]);
} else {
// Too much data
// If not System Common or System Real-Time, send it as running status
switch(buffer[lPtr] & 0xF0)
{ {
case 0x80: // If not System Common or System Real-Time, send it as running status
case 0x90:
case 0xA0: auto midiType = lastStatus & 0xF0;
case 0xB0: if (sysExContinuation)
case 0xE0: midiType = SystemExclusive;
switch (midiType)
{
case NoteOff:
case NoteOn:
case AfterTouchPoly:
case ControlChange:
case PitchBend:
#ifdef RUNNING_ENABLE
mBleClass.add(lastStatus);
#endif
for (auto i = lPtr; i < rPtr; i = i + 2) for (auto i = lPtr; i < rPtr; i = i + 2)
{ {
#ifndef RUNNING_ENABLE
mBleClass.add(lastStatus); mBleClass.add(lastStatus);
#endif
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 ProgramChange:
case 0xD0: case AfterTouchChannel:
#ifdef RUNNING_ENABLE
mBleClass.add(lastStatus);
#endif
for (auto i = lPtr; i < rPtr; i = i + 1) for (auto i = lPtr; i < rPtr; i = i + 1)
{ {
#ifndef RUNNING_ENABLE
mBleClass.add(lastStatus); mBleClass.add(lastStatus);
#endif
mBleClass.add(buffer[i + 1]); mBleClass.add(buffer[i + 1]);
} }
break; break;
case 0xF0: case SystemExclusive:
mBleClass.add(buffer[lPtr]); mBleClass.add(lastStatus);
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;
} }
} }
else
{
#ifndef RUNNING_ENABLE
auto midiType = lastStatus & 0xF0;
switch (midiType)
{
case NoteOff:
case NoteOn:
case AfterTouchPoly:
case ControlChange:
case PitchBend:
//3 bytes full Midi -> 2 bytes runningStatus
for (auto i = lPtr; i <= rPtr; i = i + 2)
{
mBleClass.add(lastStatus);
mBleClass.add(buffer[i]);
mBleClass.add(buffer[i + 1]);
}
break;
case ProgramChange:
case AfterTouchChannel:
//2 bytes full Midi -> 1 byte runningStatus
for (auto i = lPtr; i <= rPtr; i = i + 1)
{
mBleClass.add(lastStatus);
mBleClass.add(buffer[i]);
}
break;
default:
break;
}
#else
mBleClass.add(lastStatus);
for (auto i = lPtr; i <= rPtr; i++)
mBleClass.add(buffer[i]);
#endif
runningStatusContinuation = false;
}
if (++rPtr >= length)
return; // end of packet
if (lastStatus < SystemExclusive) //exclude System Message. They must not be RunningStatus
{
previousStatus = lastStatus;
}
timestampByte = buffer[rPtr++];
if (timestampByte >= MIDI_TYPE) // is bit 7 set?
{
timestamp = setMidiTimestamp(headerByte, timestampByte);
// what do to with the timestamp?
}
// Point to next status // Point to next status
lPtr = rPtr + 2; lPtr = rPtr;
if(lPtr >= length) if (lPtr >= length)
return; //end of packet return; //end of packet
} }
} }
}; };
struct MySettings : public MIDI_NAMESPACE::DefaultSettings struct MySettings : public MIDI_NAMESPACE::DefaultSettings
@ -293,4 +417,3 @@ struct MySettings : public MIDI_NAMESPACE::DefaultSettings
}; };
END_BLEMIDI_NAMESPACE END_BLEMIDI_NAMESPACE

View File

@ -1,95 +0,0 @@
#pragma once
// Headers for ESP32 BLE
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
BEGIN_BLEMIDI_NAMESPACE
class BLEMIDI_Client_ESP32
{
private:
BLEClient* _client = nullptr;
BLEMIDI<class BLEMIDI_Client_ESP32>* _bleMidiTransport = nullptr;
public:
BLEMIDI_Client_ESP32()
{
}
bool begin(const char*, BLEMIDI<class BLEMIDI_Client_ESP32>*);
void write(uint8_t* data, uint8_t length)
{
_characteristic->setValue(data, length);
_characteristic->notify();
}
void receive(uint8_t* buffer, size_t length)
{
// Post the items to the back of the queue
// (drop the first 2 items)
for (size_t i = 2; i < length; i++)
xQueueSend(_bleMidiTransport->mRxQueue, &buffer[i], portMAX_DELAY);
}
void connected()
{
if (_bleMidiTransport->_connectedCallback)
_bleMidiTransport->_connectedCallback();
}
void disconnected()
{
if (_bleMidiTransport->_disconnectedCallback)
_bleMidiTransport->_disconnectedCallback();
}
};
class MyClientCallbacks: public BLEClientCallbacks {
public:
MyClientCallbacks(BLEMIDI_Client_ESP32* bluetoothEsp32)
: _bluetoothEsp32(bluetoothEsp32) {
}
protected:
BLEMIDI_Client_ESP32* _bluetoothEsp32 = nullptr;
void onConnect(BLEClient*) {
if (_bluetoothEsp32)
_bluetoothEsp32->connected();
};
void onDisconnect(BLEClient*) {
if (_bluetoothEsp32)
_bluetoothEsp32->disconnected();
}
};
bool BLEMIDI_Client_ESP32::begin(const char* deviceName, BLEMIDI<class BLEMIDI_ESP32>* bleMidiTransport)
{
_bleMidiTransport = bleMidiTransport;
BLEDevice::init(deviceName);
_client = BLEDevice::createClient();
_client->setCallbacks(new MyClientCallbacks(this));
// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device. Specify that we want active scanning and start the
// scan to run for 5 seconds.
pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(this));
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->setActiveScan(true);
doScan = true;
pBLEScan->start(10, scanCompleteCB);
return true;
}
END_BLEMIDI_NAMESPACE

View File

@ -75,6 +75,11 @@ public:
bool begin(const char*, BLEMIDI_Transport<class BLEMIDI_ArduinoBLE>*); bool begin(const char*, BLEMIDI_Transport<class BLEMIDI_ArduinoBLE>*);
void end()
{
}
void write(uint8_t* buffer, size_t length) void write(uint8_t* buffer, size_t length)
{ {
// TODO: test length // TODO: test length
@ -165,6 +170,7 @@ protected:
{ {
if (_bleMidiTransport->_disconnectedCallback) if (_bleMidiTransport->_disconnectedCallback)
_bleMidiTransport->_disconnectedCallback(); _bleMidiTransport->_disconnectedCallback();
_central = nullptr; _central = nullptr;
} }

View File

@ -0,0 +1,636 @@
#pragma once
/*
#############################################
########## USER DEFINES BEGINNING ###########
####### Modify only these parameters ########
#############################################
*/
/*
##### BLE DEVICE NAME #####
*/
/**
* Set always the same name independently of name server
*/
//#define BLEMIDI_CLIENT_FIXED_NAME "BleMidiClient"
#ifndef BLEMIDI_CLIENT_FIXED_NAME //Not modify
/**
* When client tries to connect to specific server, BLE name is composed as follows:
* BLEMIDI_CLIENT_NAME_PREFIX + <NameServer/addrServer> + BLEMIDI_CLIENT_NAME_SUBFIX
*
* example:
* BLEMIDI_CLIENT_NAME_PREFIX "Client-"
* <NameServer/addrServer> "AX-Edge"
* BLEMIDI_CLIENT_NAME_SUBFIX "-Midi1"
*
* Result: "Client-AX-Edge-Midi1"
*/
#define BLEMIDI_CLIENT_NAME_PREFIX "C-"
#define BLEMIDI_CLIENT_NAME_SUBFIX ""
/**
* When client tries to connect to the first midi server found:
*/
#define BLEMIDI_CLIENT_DEFAULT_NAME "BLEMIDI-CLIENT"
#endif //Not modify
/*
###### TX POWER #####
*/
/**
* Set power transmision
*
* ESP_PWR_LVL_N12 // Corresponding to -12dbm Minimum
* ESP_PWR_LVL_N9 // Corresponding to -9dbm
* ESP_PWR_LVL_N6 // Corresponding to -6dbm
* ESP_PWR_LVL_N3 // Corresponding to -3dbm
* ESP_PWR_LVL_N0 // Corresponding to 0dbm
* ESP_PWR_LVL_P3 // Corresponding to +3dbm
* ESP_PWR_LVL_P6 // Corresponding to +6dbm
* ESP_PWR_LVL_P9 // Corresponding to +9dbm Maximum
*/
#define BLEMIDI_TX_PWR ESP_PWR_LVL_P9
/*
###### SECURITY #####
*/
/** Set the IO capabilities of the device, each option will trigger a different pairing method.
* BLE_HS_IO_KEYBOARD_ONLY - Passkey pairing
* BLE_HS_IO_DISPLAY_YESNO - Numeric comparison pairing
* BLE_HS_IO_NO_INPUT_OUTPUT - DEFAULT setting - just works pairing
*/
#define BLEMIDI_CLIENT_SECURITY_CAP BLE_HS_IO_NO_INPUT_OUTPUT
/** Set the security method.
* bonding
* man in the middle protection
* pair. secure connections
*
* More info in nimBLE lib
*
* Uncomment what you need
* These are the default values.
* You can select some simultaneously.
*/
#define BLEMIDI_CLIENT_BOND
//#define BLEMIDI_CLIENT_MITM
#define BLEMIDI_CLIENT_PAIR
/**
* This callback function defines what will be done when server requieres PassKey.
* Add your custom code here.
*/
static uint32_t userOnPassKeyRequest()
{
//FILL WITH YOUR CUSTOM AUTH METHOD CODE or PASSKEY
//FOR EXAMPLE:
uint32_t passkey = 123456;
//Serial.println("Client Passkey Request");
/** return the passkey to send to the server */
return passkey;
};
/*
###### BLE COMMUNICATION PARAMS ######
*/
/** Set connection parameters:
* If you only use one connection, put recomended BLE server param communication
* (you may scan it ussing "nRF Connect" app or other similar apps).
*
* If you use more than one connection adjust, for example, settings like 15ms interval, 0 latency, 120ms timout.
* These settings may be safe for 3 clients to connect reliably, set faster values if you have less
* connections.
*
* Min interval (unit: 1.25ms): 12 * 1.25ms = 15 ms,
* Max interval (unit: 1.25ms): 12 * 1.25ms = 15,
* 0 latency (Number of intervals allowed to skip),
* TimeOut (unit: 10ms) 51 * 10ms = 510ms. Timeout should be minimum 100ms.
*/
#define BLEMIDI_CLIENT_COMM_MIN_INTERVAL 6 // 7.5ms
#define BLEMIDI_CLIENT_COMM_MAX_INTERVAL 35 // 40ms
#define BLEMIDI_CLIENT_COMM_LATENCY 0 //
#define BLEMIDI_CLIENT_COMM_TIMEOUT 200 //2000ms
/*
###### BLE FORCE NEW CONNECTION ######
*/
/**
* This parameter force to skip the "soft-reconnection" and force to create a new connection after a disconnect event.
* "Soft-reconnection" save some time and energy in comparation with performming a new connection, but some BLE devices
* don't support or don't perform correctly a "soft-reconnection" after a disconnection event.
* Uncomment this define if your device doesn't work propertily after a reconnection.
*
*/
//#define BLEMIDI_FORCE_NEW_CONNECTION
/**
*
*/
/*
#############################################
############ USER DEFINES END ###############
#############################################
*/
// Headers for ESP32 nimBLE
#include <NimBLEDevice.h>
BEGIN_BLEMIDI_NAMESPACE
#ifdef BLEMIDI_CLIENT_BOND
#define BLEMIDI_CLIENT_BOND_DUMMY BLE_SM_PAIR_AUTHREQ_BOND
#else
#define BLEMIDI_CLIENT_BOND_DUMMY 0x00
#endif
#ifdef BLEMIDI_CLIENT_MITM
#define BLEMIDI_CLIENT_MITM_DUMMY BLE_SM_PAIR_AUTHREQ_MITM
#else
#define BLEMIDI_CLIENT_MITM_DUMMY 0x00
#endif
#ifdef BLEMIDI_CLIENT_PAIR
#define BLEMIDI_CLIENT_PAIR_DUMMY BLE_SM_PAIR_AUTHREQ_SC
#else
#define BLEMIDI_CLIENT_PAIR_DUMMY 0x00
#endif
/** Set the security method.
* bonding
* man in the middle protection
* pair. secure connections
*
* More info in nimBLE lib
*/
#define BLEMIDI_CLIENT_SECURITY_AUTH (BLEMIDI_CLIENT_BOND_DUMMY | BLEMIDI_CLIENT_MITM_DUMMY | BLEMIDI_CLIENT_PAIR_DUMMY)
/** Define a class to handle the callbacks when advertisments are received */
class AdvertisedDeviceCallbacks : public NimBLEAdvertisedDeviceCallbacks
{
public:
NimBLEAdvertisedDevice advDevice;
bool doConnect = false;
bool scanDone = false;
bool specificTarget = false;
bool enableConnection = false;
std::string nameTarget;
protected:
void onResult(NimBLEAdvertisedDevice *advertisedDevice)
{
if (enableConnection) //not begin() or end()
{
Serial.print("Advertised Device found: ");
Serial.println(advertisedDevice->toString().c_str());
if (advertisedDevice->isAdvertisingService(NimBLEUUID(SERVICE_UUID)))
{
Serial.println("Found MIDI Service");
if (!specificTarget || (advertisedDevice->getName() == nameTarget.c_str() || advertisedDevice->getAddress() == nameTarget))
{
/** Ready to connect now */
doConnect = true;
/** Save the device reference in a public variable that the client can use*/
advDevice = *advertisedDevice;
/** stop scan before connecting */
NimBLEDevice::getScan()->stop();
}
else
{
Serial.println("Name error");
}
}
else
{
doConnect = false;
}
}
};
};
/** Define a funtion to handle the callbacks when scan ends */
void scanEndedCB(NimBLEScanResults results);
/** Define the class that performs Client Midi (nimBLE) */
class BLEMIDI_Client_ESP32
{
private:
BLEClient *_client = nullptr;
BLEAdvertising *_advertising = nullptr;
BLERemoteCharacteristic *_characteristic = nullptr;
BLERemoteService *pSvc = nullptr;
bool firstTimeSend = true; //First writeValue get sends like Write with reponse for clean security flags. After first time, all messages are send like WriteNoResponse for increase transmision speed.
BLEMIDI_Transport<class BLEMIDI_Client_ESP32> *_bleMidiTransport = nullptr;
bool specificTarget = false;
friend class AdvertisedDeviceCallbacks;
friend class MyClientCallbacks;
friend class MIDI_NAMESPACE::MidiInterface<BLEMIDI_Transport<BLEMIDI_Client_ESP32>, MySettings>; //
AdvertisedDeviceCallbacks myAdvCB;
protected:
QueueHandle_t mRxQueue;
public:
BLEMIDI_Client_ESP32()
{
}
bool begin(const char *, BLEMIDI_Transport<class BLEMIDI_Client_ESP32> *);
bool end()
{
myAdvCB.enableConnection = false;
xQueueReset(mRxQueue);
_client->disconnect();
_client = nullptr;
return true;
}
void write(uint8_t *data, uint8_t length)
{
if (!myAdvCB.enableConnection)
return;
if (_characteristic == NULL)
return;
if (firstTimeSend)
{
_characteristic->writeValue(data, length, true);
firstTimeSend = false;
return;
}
if (!_characteristic->writeValue(data, length, !_characteristic->canWriteNoResponse()))
firstTimeSend = true;
return;
}
bool available(byte *pvBuffer);
void add(byte value)
{
// called from BLE-MIDI, to add it to a buffer here
xQueueSend(mRxQueue, &value, portMAX_DELAY / 2);
}
protected:
void receive(uint8_t *buffer, size_t length)
{
// forward the buffer so that it can be parsed
_bleMidiTransport->receive(buffer, length);
}
void connectCallbacks(MIDI_NAMESPACE::MidiInterface<BLEMIDI_Transport<BLEMIDI_Client_ESP32>, MySettings> *MIDIcallback);
void connected()
{
if (_bleMidiTransport->_connectedCallback)
{
_bleMidiTransport->_connectedCallback();
}
firstTimeSend = true;
}
void disconnected()
{
if (_bleMidiTransport->_disconnectedCallback)
{
_bleMidiTransport->_disconnectedCallback();
}
firstTimeSend = true;
}
void notifyCB(NimBLERemoteCharacteristic *pRemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify);
void scan();
bool connect();
};
/** Define the class that performs interruption callbacks */
class MyClientCallbacks : public BLEClientCallbacks
{
public:
MyClientCallbacks(BLEMIDI_Client_ESP32 *bluetoothEsp32)
: _bluetoothEsp32(bluetoothEsp32)
{
}
protected:
BLEMIDI_Client_ESP32 *_bluetoothEsp32 = nullptr;
uint32_t onPassKeyRequest()
{
return userOnPassKeyRequest();
};
void onConnect(BLEClient *pClient)
{
//Serial.println("##Connected##");
//pClient->updateConnParams(BLEMIDI_CLIENT_COMM_MIN_INTERVAL, BLEMIDI_CLIENT_COMM_MAX_INTERVAL, BLEMIDI_CLIENT_COMM_LATENCY, BLEMIDI_CLIENT_COMM_TIMEOUT);
vTaskDelay(1);
if (_bluetoothEsp32)
{
_bluetoothEsp32->connected();
}
};
void onDisconnect(BLEClient *pClient)
{
//Serial.print(pClient->getPeerAddress().toString().c_str());
//Serial.println(" Disconnected - Starting scan");
if (_bluetoothEsp32)
{
_bluetoothEsp32->disconnected();
#ifdef BLEMIDI_FORCE_NEW_CONNECTION
// Try reconnection or search a new one
_bluetoothEsp32->scan();
#endif // BLEMIDI_FORCE_NEW_CONNECTION
}
#ifdef BLEMIDI_FORCE_NEW_CONNECTION
// Renew Client
NimBLEDevice::deleteClient(pClient);
NimBLEDevice::createClient();
pClient = nullptr;
#endif // BLEMIDI_FORCE_NEW_CONNECTION
//Try reconnection or search a new one
NimBLEDevice::getScan()->start(1, scanEndedCB);
}
bool onConnParamsUpdateRequest(NimBLEClient *pClient, const ble_gap_upd_params *params)
{
if (params->itvl_min < BLEMIDI_CLIENT_COMM_MIN_INTERVAL)
{ /** 1.25ms units */
return false;
}
else if (params->itvl_max > BLEMIDI_CLIENT_COMM_MAX_INTERVAL)
{ /** 1.25ms units */
return false;
}
else if (params->latency > BLEMIDI_CLIENT_COMM_LATENCY)
{ /** Number of intervals allowed to skip */
return false;
}
else if (params->supervision_timeout > BLEMIDI_CLIENT_COMM_TIMEOUT)
{ /** 10ms units */
return false;
}
pClient->updateConnParams(params->itvl_min, params->itvl_max, params->latency, params->supervision_timeout);
return true;
};
};
/*
##########################################
############# IMPLEMENTATION #############
##########################################
*/
bool BLEMIDI_Client_ESP32::begin(const char *deviceName, BLEMIDI_Transport<class BLEMIDI_Client_ESP32> *bleMidiTransport)
{
_bleMidiTransport = bleMidiTransport;
std::string strDeviceName(deviceName);
if (strDeviceName == "") // Connect to the first midi server found
{
myAdvCB.specificTarget = false;
myAdvCB.nameTarget = "";
#ifdef BLEMIDI_CLIENT_FIXED_NAME
strDeviceName = BLEMIDI_CLIENT_FIXED_NAME;
#else
strDeviceName = BLEMIDI_CLIENT_DEFAULT_NAME;
#endif
}
else // Connect to a specific name or address
{
myAdvCB.specificTarget = true;
myAdvCB.nameTarget = strDeviceName;
#ifdef BLEMIDI_CLIENT_FIXED_NAME
strDeviceName = BLEMIDI_CLIENT_FIXED_NAME;
#else
strDeviceName = BLEMIDI_CLIENT_NAME_PREFIX + strDeviceName + BLEMIDI_CLIENT_NAME_SUBFIX;
#endif
}
Serial.println(strDeviceName.c_str());
NimBLEDevice::init(strDeviceName);
// To communicate between the 2 cores.
// Core_0 runs here, core_1 runs the BLE stack
mRxQueue = xQueueCreate(256, sizeof(uint8_t)); // TODO Settings::MaxBufferSize
NimBLEDevice::setSecurityIOCap(BLEMIDI_CLIENT_SECURITY_CAP); // Attention, it may need a passkey
NimBLEDevice::setSecurityAuth(BLEMIDI_CLIENT_SECURITY_AUTH);
/** Optional: set the transmit power, default is 3db */
NimBLEDevice::setPower(BLEMIDI_TX_PWR); /** +9db */
myAdvCB.enableConnection = true;
scan();
return true;
}
bool BLEMIDI_Client_ESP32::available(byte *pvBuffer)
{
if (myAdvCB.enableConnection)
{
if (_client == nullptr || !_client->isConnected()) //Try to connect/reconnect
{
if (myAdvCB.doConnect)
{
myAdvCB.doConnect = false;
if (!connect())
{
scan();
}
}
else if (myAdvCB.scanDone)
{
scan();
}
}
// return 1 byte from the Queue
return xQueueReceive(mRxQueue, (void *)pvBuffer, 0); // return immediately when the queue is empty
}
else
{
return false;
}
}
/** Notification receiving handler callback */
void BLEMIDI_Client_ESP32::notifyCB(NimBLERemoteCharacteristic *pRemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify)
{
if (this->_characteristic == pRemoteCharacteristic) //Redundant protection
{
receive(pData, length);
}
}
void BLEMIDI_Client_ESP32::scan()
{
// Retrieve a Scanner and set the callback you want to use to be informed when a new device is detected.
// Specify that you want active scanning and start the
// scan to run for 3 seconds.
myAdvCB.scanDone = true;
NimBLEScan *pBLEScan = BLEDevice::getScan();
if (!pBLEScan->isScanning())
{
pBLEScan->setAdvertisedDeviceCallbacks(&myAdvCB);
pBLEScan->setInterval(600);
pBLEScan->setWindow(500);
pBLEScan->setActiveScan(true);
Serial.println("Scanning...");
pBLEScan->start(1, scanEndedCB);
}
};
bool BLEMIDI_Client_ESP32::connect()
{
using namespace std::placeholders; //<- for bind funtion in callback notification
#ifndef BLEMIDI_FORCE_NEW_CONNECTION
/** Check if we have a client we should reuse first
* Special case when we already know this device
* This saves considerable time and power.
*/
if (_client)
{
if (_client == NimBLEDevice::getClientByPeerAddress(myAdvCB.advDevice.getAddress()))
{
if (_client->connect(&myAdvCB.advDevice, false))
{
if (_characteristic->canNotify())
{
if (_characteristic->subscribe(true, std::bind(&BLEMIDI_Client_ESP32::notifyCB, this, _1, _2, _3, _4)))
{
//Re-connection SUCCESS
return true;
}
}
/** Disconnect if subscribe failed */
_client->disconnect();
}
/* If any connection problem exits, delete previous client and try again in the next attemp as new client*/
NimBLEDevice::deleteClient(_client);
_client = nullptr;
return false;
}
/*If client does not match, delete previous client and create a new one*/
NimBLEDevice::deleteClient(_client);
_client = nullptr;
}
#endif //BLEMIDI_FORCE_NEW_CONNECTION
if (NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS)
{
Serial.println("Max clients reached - no more connections available");
return false;
}
// Create and setup a new client
_client = BLEDevice::createClient();
_client->setClientCallbacks(new MyClientCallbacks(this), false);
_client->setConnectionParams(BLEMIDI_CLIENT_COMM_MIN_INTERVAL, BLEMIDI_CLIENT_COMM_MAX_INTERVAL, BLEMIDI_CLIENT_COMM_LATENCY, BLEMIDI_CLIENT_COMM_TIMEOUT);
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
_client->setConnectTimeout(15);
if (!_client->connect(&myAdvCB.advDevice))
{
/** Created a client but failed to connect, don't need to keep it as it has no data */
NimBLEDevice::deleteClient(_client);
_client = nullptr;
//Serial.println("Failed to connect, deleted client");
return false;
}
if (!_client->isConnected())
{
//Serial.println("Failed to connect");
_client->disconnect();
NimBLEDevice::deleteClient(_client);
_client = nullptr;
return false;
}
Serial.print("Connected to: ");
Serial.print(myAdvCB.advDevice.getName().c_str());
Serial.print(" / ");
Serial.println(_client->getPeerAddress().toString().c_str());
/*
Serial.print("RSSI: ");
Serial.println(_client->getRssi());
*/
/** Now we can read/write/subscribe the charateristics of the services we are interested in */
pSvc = _client->getService(SERVICE_UUID);
if (pSvc) /** make sure it's not null */
{
_characteristic = pSvc->getCharacteristic(CHARACTERISTIC_UUID);
if (_characteristic) /** make sure it's not null */
{
if (_characteristic->canNotify())
{
if (_characteristic->subscribe(true, std::bind(&BLEMIDI_Client_ESP32::notifyCB, this, _1, _2, _3, _4)))
{
//Connection SUCCESS
return true;
}
}
}
}
//If anything fails, disconnect and delete client
_client->disconnect();
NimBLEDevice::deleteClient(_client);
_client = nullptr;
return false;
};
/** Callback to process the results of the last scan or restart it */
void scanEndedCB(NimBLEScanResults results)
{
// Serial.println("Scan Ended");
}
END_BLEMIDI_NAMESPACE
/*! \brief Create an instance for ESP32 named <DeviceName>, and adviertise it like "Prefix + <DeviceName> + Subfix"
It will try to connect to a specific server with equal name or addr than <DeviceName>. If <DeviceName> is "", it will connect to first midi server
*/
#define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \
BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_Client_ESP32> BLE##Name(DeviceName); \
MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_Client_ESP32>, BLEMIDI_NAMESPACE::MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_Client_ESP32> &)BLE##Name);
/*! \brief Create a default instance for ESP32 named BLEMIDI-CLIENT.
It will try to connect to first midi ble server found.
*/
#define BLEMIDI_CREATE_DEFAULT_INSTANCE() \
BLEMIDI_CREATE_INSTANCE("", MIDI)

View File

@ -11,11 +11,11 @@ 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;
BLEMIDI_Transport<class BLEMIDI_ESP32>* _bleMidiTransport = nullptr; BLEMIDI_Transport<class BLEMIDI_ESP32> *_bleMidiTransport = nullptr;
friend class MyServerCallbacks; friend class MyServerCallbacks;
friend class MyCharacteristicCallbacks; friend class MyCharacteristicCallbacks;
@ -28,15 +28,20 @@ public:
{ {
} }
bool begin(const char*, BLEMIDI_Transport<class BLEMIDI_ESP32>*); bool begin(const char *, BLEMIDI_Transport<class BLEMIDI_ESP32> *);
void write(uint8_t* buffer, size_t length) void end()
{
Serial.println("end");
}
void write(uint8_t *buffer, size_t length)
{ {
_characteristic->setValue(buffer, length); _characteristic->setValue(buffer, length);
_characteristic->notify(); _characteristic->notify();
} }
bool available(byte* 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
} }
@ -48,7 +53,7 @@ public:
} }
protected: protected:
void receive(uint8_t* buffer, size_t length) void receive(uint8_t *buffer, size_t length)
{ {
// parse the incoming buffer // parse the incoming buffer
_bleMidiTransport->receive(buffer, length); _bleMidiTransport->receive(buffer, length);
@ -64,47 +69,59 @@ protected:
{ {
if (_bleMidiTransport->_disconnectedCallback) if (_bleMidiTransport->_disconnectedCallback)
_bleMidiTransport->_disconnectedCallback(); _bleMidiTransport->_disconnectedCallback();
end();
} }
}; };
class MyServerCallbacks: public BLEServerCallbacks { class MyServerCallbacks : public BLEServerCallbacks
{
public: public:
MyServerCallbacks(BLEMIDI_ESP32* bluetoothEsp32) MyServerCallbacks(BLEMIDI_ESP32 *bluetoothEsp32)
: _bluetoothEsp32(bluetoothEsp32) { : _bluetoothEsp32(bluetoothEsp32)
{
} }
protected: protected:
BLEMIDI_ESP32* _bluetoothEsp32 = nullptr; BLEMIDI_ESP32 *_bluetoothEsp32 = nullptr;
void onConnect(BLEServer*) { void onConnect(BLEServer *)
{
if (_bluetoothEsp32) if (_bluetoothEsp32)
_bluetoothEsp32->connected(); _bluetoothEsp32->connected();
}; };
void onDisconnect(BLEServer*) { void onDisconnect(BLEServer *server)
{
if (_bluetoothEsp32) if (_bluetoothEsp32)
_bluetoothEsp32->disconnected(); _bluetoothEsp32->disconnected();
server->getAdvertising()->start();
} }
}; };
class MyCharacteristicCallbacks: public BLECharacteristicCallbacks { class MyCharacteristicCallbacks : public BLECharacteristicCallbacks
{
public: public:
MyCharacteristicCallbacks(BLEMIDI_ESP32* bluetoothEsp32) MyCharacteristicCallbacks(BLEMIDI_ESP32 *bluetoothEsp32)
: _bluetoothEsp32(bluetoothEsp32 ) { : _bluetoothEsp32(bluetoothEsp32)
{
} }
protected: protected:
BLEMIDI_ESP32* _bluetoothEsp32 = nullptr; BLEMIDI_ESP32 *_bluetoothEsp32 = nullptr;
void onWrite(BLECharacteristic * characteristic) { void onWrite(BLECharacteristic *characteristic)
{
std::string rxValue = characteristic->getValue(); std::string rxValue = characteristic->getValue();
if (rxValue.length() > 0) { if (rxValue.length() > 0)
{
_bluetoothEsp32->receive((uint8_t *)(rxValue.c_str()), rxValue.length()); _bluetoothEsp32->receive((uint8_t *)(rxValue.c_str()), rxValue.length());
} }
} }
}; };
bool BLEMIDI_ESP32::begin(const char* deviceName, BLEMIDI_Transport<class BLEMIDI_ESP32>* bleMidiTransport) bool BLEMIDI_ESP32::begin(const char *deviceName, BLEMIDI_Transport<class BLEMIDI_ESP32> *bleMidiTransport)
{ {
_bleMidiTransport = bleMidiTransport; _bleMidiTransport = bleMidiTransport;
@ -126,37 +143,38 @@ bool BLEMIDI_ESP32::begin(const char* deviceName, BLEMIDI_Transport<class BLEMID
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_WRITE_NR BLECharacteristic::PROPERTY_WRITE_NR);
);
// Add CCCD 0x2902 to allow notify // Add CCCD 0x2902 to allow notify
_characteristic->addDescriptor(new BLE2902()); _characteristic->addDescriptor(new BLE2902());
_characteristic->setCallbacks(new MyCharacteristicCallbacks(this)); _characteristic->setCallbacks(new MyCharacteristicCallbacks(this));
auto _security = new BLESecurity();
_security->setAuthenticationMode(ESP_LE_AUTH_BOND);
// Start the service // Start the service
service->start(); service->start();
auto advertisementData = BLEAdvertisementData();
advertisementData.setFlags(0x04);
advertisementData.setCompleteServices(BLEUUID(SERVICE_UUID));
advertisementData.setName(deviceName);
// Start advertising // Start advertising
_advertising = _server->getAdvertising(); _advertising = _server->getAdvertising();
_advertising->setAdvertisementData(advertisementData); _advertising->addServiceUUID(service->getUUID());
_advertising->setAppearance(0x00);
_advertising->start(); _advertising->start();
Serial.println("begin");
return true; return true;
} }
/*! \brief Create an instance for ESP32 named <DeviceName> /*! \brief Create an instance for ESP32 named <DeviceName>
*/ */
#define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \ #define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \
BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32> BLE##Name(DeviceName); \ BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32> BLE##Name(DeviceName); \
MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32>, BLEMIDI_NAMESPACE::MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32> &)BLE##Name); MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32>, BLEMIDI_NAMESPACE::MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32> &)BLE##Name);
/*! \brief Create a default instance for ESP32 named BLE-MIDI /*! \brief Create a default instance for ESP32 named BLE-MIDI
*/ */
#define BLEMIDI_CREATE_DEFAULT_INSTANCE() \ #define BLEMIDI_CREATE_DEFAULT_INSTANCE() \
BLEMIDI_CREATE_INSTANCE("BLE-MIDI", MIDI) BLEMIDI_CREATE_INSTANCE("Esp32-BLE-MIDI", MIDI)
END_BLEMIDI_NAMESPACE END_BLEMIDI_NAMESPACE

View File

@ -8,11 +8,11 @@ BEGIN_BLEMIDI_NAMESPACE
class BLEMIDI_ESP32_NimBLE class BLEMIDI_ESP32_NimBLE
{ {
private: private:
BLEServer* _server = nullptr; BLEServer *_server = nullptr;
BLEAdvertising* _advertising = nullptr; BLEAdvertising *_advertising = nullptr;
BLECharacteristic* _characteristic = nullptr; BLECharacteristic *_characteristic = nullptr;
BLEMIDI_Transport<class BLEMIDI_ESP32_NimBLE>* _bleMidiTransport = nullptr; BLEMIDI_Transport<class BLEMIDI_ESP32_NimBLE> *_bleMidiTransport = nullptr;
friend class MyServerCallbacks; friend class MyServerCallbacks;
friend class MyCharacteristicCallbacks; friend class MyCharacteristicCallbacks;
@ -25,18 +25,22 @@ public:
{ {
} }
bool begin(const char*, BLEMIDI_Transport<class BLEMIDI_ESP32_NimBLE>*); bool begin(const char *, BLEMIDI_Transport<class BLEMIDI_ESP32_NimBLE> *);
void write(uint8_t* buffer, size_t length) void end()
{
}
void write(uint8_t *buffer, size_t length)
{ {
_characteristic->setValue(buffer, length); _characteristic->setValue(buffer, length);
_characteristic->notify(); _characteristic->notify();
} }
bool available(byte* pvBuffer) bool available(byte *pvBuffer)
{ {
// return 1 byte from the Queue // return 1 byte from the Queue
return xQueueReceive(mRxQueue, (void*)pvBuffer, 0); // return immediately when the queue is empty return xQueueReceive(mRxQueue, (void *)pvBuffer, 0); // return immediately when the queue is empty
} }
void add(byte value) void add(byte value)
@ -46,7 +50,7 @@ public:
} }
protected: protected:
void receive(uint8_t* buffer, size_t length) void receive(uint8_t *buffer, size_t length)
{ {
// forward the buffer so it can be parsed // forward the buffer so it can be parsed
_bleMidiTransport->receive(buffer, length); _bleMidiTransport->receive(buffer, length);
@ -65,44 +69,52 @@ protected:
} }
}; };
class MyServerCallbacks: public BLEServerCallbacks { class MyServerCallbacks : public BLEServerCallbacks
{
public: public:
MyServerCallbacks(BLEMIDI_ESP32_NimBLE* bluetoothEsp32) MyServerCallbacks(BLEMIDI_ESP32_NimBLE *bluetoothEsp32)
: _bluetoothEsp32(bluetoothEsp32) { : _bluetoothEsp32(bluetoothEsp32)
{
} }
protected: protected:
BLEMIDI_ESP32_NimBLE* _bluetoothEsp32 = nullptr; BLEMIDI_ESP32_NimBLE *_bluetoothEsp32 = nullptr;
void onConnect(BLEServer*) { void onConnect(BLEServer *)
{
if (_bluetoothEsp32) if (_bluetoothEsp32)
_bluetoothEsp32->connected(); _bluetoothEsp32->connected();
}; };
void onDisconnect(BLEServer*) { void onDisconnect(BLEServer *)
{
if (_bluetoothEsp32) if (_bluetoothEsp32)
_bluetoothEsp32->disconnected(); _bluetoothEsp32->disconnected();
} }
}; };
class MyCharacteristicCallbacks: public BLECharacteristicCallbacks { class MyCharacteristicCallbacks : public BLECharacteristicCallbacks
{
public: public:
MyCharacteristicCallbacks(BLEMIDI_ESP32_NimBLE* bluetoothEsp32) MyCharacteristicCallbacks(BLEMIDI_ESP32_NimBLE *bluetoothEsp32)
: _bluetoothEsp32(bluetoothEsp32 ) { : _bluetoothEsp32(bluetoothEsp32)
{
} }
protected: protected:
BLEMIDI_ESP32_NimBLE* _bluetoothEsp32 = nullptr; BLEMIDI_ESP32_NimBLE *_bluetoothEsp32 = nullptr;
void onWrite(BLECharacteristic * characteristic) { void onWrite(BLECharacteristic *characteristic)
{
std::string rxValue = characteristic->getValue(); std::string rxValue = characteristic->getValue();
if (rxValue.length() > 0) { if (rxValue.length() > 0)
{
_bluetoothEsp32->receive((uint8_t *)(rxValue.c_str()), rxValue.length()); _bluetoothEsp32->receive((uint8_t *)(rxValue.c_str()), rxValue.length());
} }
} }
}; };
bool BLEMIDI_ESP32_NimBLE::begin(const char* deviceName, BLEMIDI_Transport<class BLEMIDI_ESP32_NimBLE>* bleMidiTransport) bool BLEMIDI_ESP32_NimBLE::begin(const char *deviceName, BLEMIDI_Transport<class BLEMIDI_ESP32_NimBLE> *bleMidiTransport)
{ {
_bleMidiTransport = bleMidiTransport; _bleMidiTransport = bleMidiTransport;
@ -114,6 +126,7 @@ bool BLEMIDI_ESP32_NimBLE::begin(const char* deviceName, BLEMIDI_Transport<class
_server = BLEDevice::createServer(); _server = BLEDevice::createServer();
_server->setCallbacks(new MyServerCallbacks(this)); _server->setCallbacks(new MyServerCallbacks(this));
_server->advertiseOnDisconnect(true);
// Create the BLE Service // Create the BLE Service
auto service = _server->createService(BLEUUID(SERVICE_UUID)); auto service = _server->createService(BLEUUID(SERVICE_UUID));
@ -124,35 +137,34 @@ bool BLEMIDI_ESP32_NimBLE::begin(const char* deviceName, BLEMIDI_Transport<class
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE |
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::NOTIFY |
NIMBLE_PROPERTY::WRITE_NR NIMBLE_PROPERTY::WRITE_NR);
);
_characteristic->setCallbacks(new MyCharacteristicCallbacks(this)); _characteristic->setCallbacks(new MyCharacteristicCallbacks(this));
auto _security = new NimBLESecurity();
_security->setAuthenticationMode(ESP_LE_AUTH_BOND);
// Start the service // Start the service
service->start(); service->start();
auto advertisementData = BLEAdvertisementData();
advertisementData.setFlags(0x04);
advertisementData.setCompleteServices(BLEUUID(SERVICE_UUID));
advertisementData.setName(deviceName);
// Start advertising // Start advertising
_advertising = _server->getAdvertising(); _advertising = _server->getAdvertising();
_advertising->setAdvertisementData(advertisementData); _advertising->addServiceUUID(service->getUUID());
_advertising->setAppearance(0x00);
_advertising->start(); _advertising->start();
return true; return true;
} }
/*! \brief Create an instance for ESP32 named <DeviceName> /*! \brief Create an instance for ESP32 named <DeviceName>
*/ */
#define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \ #define BLEMIDI_CREATE_INSTANCE(DeviceName, Name) \
BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32_NimBLE> BLE##Name(DeviceName); \ BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32_NimBLE> BLE##Name(DeviceName); \
MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32_NimBLE>, BLEMIDI_NAMESPACE::MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32_NimBLE> &)BLE##Name); MIDI_NAMESPACE::MidiInterface<BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32_NimBLE>, BLEMIDI_NAMESPACE::MySettings> Name((BLEMIDI_NAMESPACE::BLEMIDI_Transport<BLEMIDI_NAMESPACE::BLEMIDI_ESP32_NimBLE> &)BLE##Name);
/*! \brief Create a default instance for ESP32 named BLE-MIDI /*! \brief Create a default instance for ESP32 named BLE-MIDI
*/ */
#define BLEMIDI_CREATE_DEFAULT_INSTANCE() \ #define BLEMIDI_CREATE_DEFAULT_INSTANCE() \
BLEMIDI_CREATE_INSTANCE("Esp32-BLE-MIDI", MIDI) BLEMIDI_CREATE_INSTANCE("Esp32-NimBLE-MIDI", MIDI)
END_BLEMIDI_NAMESPACE END_BLEMIDI_NAMESPACE

View File

@ -24,6 +24,11 @@ public:
bool begin(const char*, BLEMIDI_NAMESPACE::BLEMIDI_Transport<class BLEMIDI_nRF52>*); bool begin(const char*, BLEMIDI_NAMESPACE::BLEMIDI_Transport<class BLEMIDI_nRF52>*);
void end()
{
}
void write(uint8_t* buffer, size_t length) void write(uint8_t* buffer, size_t length)
{ {
} }