如何在Arduino NANO 33 BLEnRF52和iPad之间保持活动的MIDI BLE连接

问题描述

我正在使用Arduino Nano 33 BLE设备实现iPad的BLE MIDI控制器。以下代码能够:

  • 使该设备可作为BLE MIDI外设被发现
  • 与BLE MIDI中央应用程序建立连接

该连接仅在Android应用程序中稳定。 每个iOS应用(例如Garageband,AUM等)会立即关闭连接(arduino板上的LED在几秒钟内打开和关闭),但是如果设备不断发送MIDI消息(请查看在 loop()函数中注释的代码行),该连接永远保持活动状态;不幸的是,重复发送消息不是我想要实现的控制器的目的。

可能要执行BLE服务的特定配置轮询操作以符合严格的iOS标准,但是我找不到任何有效的解决方案或示例用于 Nano 33 BLE 设备,该设备不包括 loop()函数中发送注释。

#include <ArduinoBLE.h>

byte midiData[] = {0x80,0x80,0x00,0x00};

// set up the MIDI service and MIDI message characteristic:
BLEService midiservice("03B80E5A-EDE8-4B33-A751-6CE34EC4C700");
BLECharacteristic midiCharacteristic("7772E5DB-3868-4112-A1A9-F2669D106BF3",BLEWrite | BLEWriteWithoutResponse |
                                     BLENotify | BLERead,sizeof(midiData));
bool midi_connected = false;

void setup() {
  // initialize serial communication
  Serial.begin(9600);
  // initialize built in LED:
  pinMode(LED_BUILTIN,OUTPUT);
  // Initialize BLE service:
  if (!BLE.begin()) {
    Serial.println("starting BLE Failed!");
    while (true);
  }
  BLE.setLocalName("MBLE");
  BLE.setAdvertisedService(midiservice);
  BLE.setEventHandler(BLEConnected,onConnected);
  BLE.setEventHandler(BLEdisconnected,ondisconnected);
  midiCharacteristic.setEventHandler(BLEWritten,onWritten);
  midiservice.addCharacteristic(midiCharacteristic);
  BLE.addService(midiservice);

  BLE.setConnectable(true);
  BLE.setAdvertisingInterval(32);
  BLE.setConnectionInterval(32,64);
  BLE.advertise();
}

void loop() {
  BLEDevice central = BLE.central();
  if (central) {
//    midiCommand(0x90,60,127);
//    delay(250);
//    midiCommand(0x80,0);
//    delay(250);
  }
}

void onConnected(BLEDevice central) {
  digitalWrite(LED_BUILTIN,HIGH);
  midi_connected = true;
}

void ondisconnected(BLEDevice central) {
  digitalWrite(LED_BUILTIN,LOW);
  midi_connected = false;
}

void onWritten(BLEDevice central,BLECharacteristic characteristic) {
  auto buffer = characteristic.value();
  auto length = characteristic.valueLength();

  if (length > 0)
  {
    // echo on the next midi channel
    midiCommand(buffer[2],buffer[3],buffer[4]);
  }
}

void midiCommand(byte cmd,byte data1,byte  data2) {
  midiData[2] = cmd;
  midiData[3] = data1;
  midiData[4] = data2;
  midiCharacteristic.setValue(midiData,sizeof(midiData));
}

解决方法

我(最后)亲自查看了Apple提供的 MIDI BLE规范,找到了一个解决方案,说

附件应要求15 ms或更短的连接间隔。苹果建议从请求开始 连接间隔为11.25 ms,如果Apple拒绝了连接请求,则为15 ms 产品。 高于15毫秒的间隔不适合实时播放。

及以后

支持蓝牙低功耗MIDI的Apple设备在与配件建立连接后将尝试读取MIDI I / O特性。 [...]附件应以没有有效载荷的数据包响应读取的初始MIDI I / O特性。

所以我在 setup()函数中更改了连接间隔

BLE.setConnectionInterval(9,12);

并且在连接事件处理程序函数中包括几行

void onConnected(BLEDevice central) {
  digitalWrite(LED_BUILTIN,HIGH);
  midi_connected = true;
  midiCharacteristic.setValue(0);
}

就是这样!