Dependencies:   BLE_API mbed nRF51822_BLE_MIDI

Dependents:   BLE_MIDI_one_note_TEST

Fork of BLE_MIDI by Kaoru Shoji

Committer:
kshoji
Date:
Mon Apr 06 09:10:07 2015 +0000
Revision:
2:dbc6f81b9ba0
Parent:
1:cba2eba64f5c
Add documents

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kshoji 0:83889dc90473 1 /* Copyright (c) 2014 mbed.org, MIT License
kshoji 0:83889dc90473 2 *
kshoji 0:83889dc90473 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
kshoji 0:83889dc90473 4 * and associated documentation files (the "Software"), to deal in the Software without
kshoji 0:83889dc90473 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
kshoji 0:83889dc90473 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
kshoji 0:83889dc90473 7 * Software is furnished to do so, subject to the following conditions:
kshoji 0:83889dc90473 8 *
kshoji 0:83889dc90473 9 * The above copyright notice and this permission notice shall be included in all copies or
kshoji 0:83889dc90473 10 * substantial portions of the Software.
kshoji 0:83889dc90473 11 *
kshoji 0:83889dc90473 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
kshoji 0:83889dc90473 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
kshoji 0:83889dc90473 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
kshoji 0:83889dc90473 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
kshoji 0:83889dc90473 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
kshoji 0:83889dc90473 17 */
kshoji 0:83889dc90473 18
kshoji 0:83889dc90473 19 #include "mbed.h"
kshoji 0:83889dc90473 20 #include "BLEMIDI.h"
kshoji 0:83889dc90473 21
kshoji 0:83889dc90473 22 void BLEMIDI::onBleDisconnection(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) {
kshoji 0:83889dc90473 23 device->startAdvertising();
kshoji 0:83889dc90473 24 isConnected = false;
kshoji 0:83889dc90473 25 }
kshoji 0:83889dc90473 26
kshoji 0:83889dc90473 27 void BLEMIDI::onBleConnection(Gap::Handle_t handle, Gap::addr_type_t type, const Gap::address_t addr, const Gap::ConnectionParams_t *params) {
kshoji 0:83889dc90473 28 isConnected = true;
kshoji 0:83889dc90473 29 }
kshoji 0:83889dc90473 30
kshoji 0:83889dc90473 31 void BLEMIDI::dataWrittenCallback(const GattCharacteristicWriteCBParams *params) {
kshoji 0:83889dc90473 32 uint16_t length;
kshoji 0:83889dc90473 33 uint8_t rxBuffer[20];
kshoji 0:83889dc90473 34
kshoji 0:83889dc90473 35 device->readCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), rxBuffer, &length);
kshoji 0:83889dc90473 36
kshoji 0:83889dc90473 37 if (length > 1) {
kshoji 0:83889dc90473 38 // parse BLE message
kshoji 0:83889dc90473 39 uint8_t header = rxBuffer[0];
kshoji 0:83889dc90473 40 for (int i = 1; i < length; i++) {
kshoji 0:83889dc90473 41 uint8_t midiEvent = rxBuffer[i];
kshoji 0:83889dc90473 42
kshoji 0:83889dc90473 43 if (midiState == MIDI_STATE_TIMESTAMP) {
kshoji 0:83889dc90473 44 if ((midiEvent & 0x80) == 0) {
kshoji 0:83889dc90473 45 // running status
kshoji 0:83889dc90473 46 midiState = MIDI_STATE_WAIT;
kshoji 0:83889dc90473 47 }
kshoji 0:83889dc90473 48
kshoji 0:83889dc90473 49 if (midiEvent == 0xf7) {
kshoji 0:83889dc90473 50 // maybe error
kshoji 0:83889dc90473 51 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 52 continue;
kshoji 0:83889dc90473 53 }
kshoji 0:83889dc90473 54 }
kshoji 0:83889dc90473 55 if (midiState == MIDI_STATE_TIMESTAMP) {
kshoji 0:83889dc90473 56 timestamp = ((header & 0x3f) << 7) | (midiEvent & 0x7f);
kshoji 0:83889dc90473 57 midiState = MIDI_STATE_WAIT;
kshoji 0:83889dc90473 58 } else if (midiState == MIDI_STATE_WAIT) {
kshoji 0:83889dc90473 59 switch (midiEvent & 0xf0) {
kshoji 0:83889dc90473 60 case 0xf0: {
kshoji 0:83889dc90473 61 switch (midiEvent) {
kshoji 0:83889dc90473 62 case 0xf0:
kshoji 0:83889dc90473 63 sysExBuffer[sysExBufferPos++] = midiEvent;
kshoji 0:83889dc90473 64 midiState = MIDI_STATE_SIGNAL_SYSEX;
kshoji 0:83889dc90473 65 break;
kshoji 0:83889dc90473 66
kshoji 0:83889dc90473 67 case 0xf1:
kshoji 0:83889dc90473 68 case 0xf3:
kshoji 0:83889dc90473 69 // 0xf1 MIDI Time Code Quarter Frame. : 2bytes
kshoji 0:83889dc90473 70 // 0xf3 Song Select. : 2bytes
kshoji 0:83889dc90473 71 midiEventKind = midiEvent;
kshoji 0:83889dc90473 72 midiState = MIDI_STATE_SIGNAL_2BYTES_2;
kshoji 0:83889dc90473 73 break;
kshoji 0:83889dc90473 74
kshoji 0:83889dc90473 75 case 0xf2:
kshoji 0:83889dc90473 76 // 0xf2 Song Position Pointer. : 3bytes
kshoji 0:83889dc90473 77 midiEventKind = midiEvent;
kshoji 0:83889dc90473 78 midiState = MIDI_STATE_SIGNAL_3BYTES_2;
kshoji 0:83889dc90473 79 break;
kshoji 0:83889dc90473 80
kshoji 0:83889dc90473 81 case 0xf6:
kshoji 0:83889dc90473 82 // 0xf6 Tune Request : 1byte
kshoji 0:83889dc90473 83 onTuneRequest();
kshoji 0:83889dc90473 84 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 85 break;
kshoji 0:83889dc90473 86 case 0xf8:
kshoji 0:83889dc90473 87 // 0xf8 Timing Clock : 1byte
kshoji 0:83889dc90473 88 onTimingClock();
kshoji 0:83889dc90473 89 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 90 break;
kshoji 0:83889dc90473 91 case 0xfa:
kshoji 0:83889dc90473 92 // 0xfa Start : 1byte
kshoji 0:83889dc90473 93 onStart();
kshoji 0:83889dc90473 94 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 95 break;
kshoji 0:83889dc90473 96 case 0xfb:
kshoji 0:83889dc90473 97 // 0xfb Continue : 1byte
kshoji 0:83889dc90473 98 onContinue();
kshoji 0:83889dc90473 99 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 100 break;
kshoji 0:83889dc90473 101 case 0xfc:
kshoji 0:83889dc90473 102 // 0xfc Stop : 1byte
kshoji 0:83889dc90473 103 onStop();
kshoji 0:83889dc90473 104 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 105 break;
kshoji 0:83889dc90473 106 case 0xfe:
kshoji 0:83889dc90473 107 // 0xfe Active Sensing : 1byte
kshoji 0:83889dc90473 108 onActiveSensing();
kshoji 0:83889dc90473 109 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 110 break;
kshoji 0:83889dc90473 111 case 0xff:
kshoji 0:83889dc90473 112 // 0xff Reset : 1byte
kshoji 0:83889dc90473 113 onReset();
kshoji 0:83889dc90473 114 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 115 break;
kshoji 0:83889dc90473 116
kshoji 0:83889dc90473 117 default:
kshoji 0:83889dc90473 118 break;
kshoji 0:83889dc90473 119 }
kshoji 0:83889dc90473 120 }
kshoji 0:83889dc90473 121 break;
kshoji 0:83889dc90473 122 case 0x80:
kshoji 0:83889dc90473 123 case 0x90:
kshoji 0:83889dc90473 124 case 0xa0:
kshoji 0:83889dc90473 125 case 0xb0:
kshoji 0:83889dc90473 126 case 0xe0:
kshoji 0:83889dc90473 127 // 3bytes pattern
kshoji 0:83889dc90473 128 midiEventKind = midiEvent;
kshoji 0:83889dc90473 129 midiState = MIDI_STATE_SIGNAL_3BYTES_2;
kshoji 0:83889dc90473 130 break;
kshoji 0:83889dc90473 131 case 0xc0: // program change
kshoji 0:83889dc90473 132 case 0xd0: // channel after-touch
kshoji 0:83889dc90473 133 // 2bytes pattern
kshoji 0:83889dc90473 134 midiEventKind = midiEvent;
kshoji 0:83889dc90473 135 midiState = MIDI_STATE_SIGNAL_2BYTES_2;
kshoji 0:83889dc90473 136 break;
kshoji 0:83889dc90473 137 default:
kshoji 0:83889dc90473 138 // 0x00 - 0x70: running status
kshoji 0:83889dc90473 139 if ((midiEventKind & 0xf0) != 0xf0) {
kshoji 0:83889dc90473 140 // previous event kind is multi-bytes pattern
kshoji 0:83889dc90473 141 midiEventNote = midiEvent;
kshoji 0:83889dc90473 142 midiState = MIDI_STATE_SIGNAL_3BYTES_3;
kshoji 0:83889dc90473 143 }
kshoji 0:83889dc90473 144 break;
kshoji 0:83889dc90473 145 }
kshoji 0:83889dc90473 146 } else if (midiState == MIDI_STATE_SIGNAL_2BYTES_2) {
kshoji 0:83889dc90473 147 switch (midiEventKind & 0xf0) {
kshoji 0:83889dc90473 148 // 2bytes pattern
kshoji 0:83889dc90473 149 case 0xc0: // program change
kshoji 0:83889dc90473 150 midiEventNote = midiEvent;
kshoji 0:83889dc90473 151 onProgramChange(midiEventKind & 0xf, midiEventNote);
kshoji 0:83889dc90473 152 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 153 break;
kshoji 0:83889dc90473 154 case 0xd0: // channel after-touch
kshoji 0:83889dc90473 155 midiEventNote = midiEvent;
kshoji 0:83889dc90473 156 onChannelAftertouch(midiEventKind & 0xf, midiEventNote);
kshoji 0:83889dc90473 157 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 158 break;
kshoji 0:83889dc90473 159 case 0xf0: {
kshoji 0:83889dc90473 160 switch (midiEventKind) {
kshoji 0:83889dc90473 161 case 0xf1:
kshoji 0:83889dc90473 162 // 0xf1 MIDI Time Code Quarter Frame. : 2bytes
kshoji 0:83889dc90473 163 midiEventNote = midiEvent;
kshoji 0:83889dc90473 164 onTimeCodeQuarterFrame(midiEventNote);
kshoji 0:83889dc90473 165 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 166 break;
kshoji 0:83889dc90473 167 case 0xf3:
kshoji 0:83889dc90473 168 // 0xf3 Song Select. : 2bytes
kshoji 0:83889dc90473 169 midiEventNote = midiEvent;
kshoji 0:83889dc90473 170 onSongSelect(midiEventNote);
kshoji 0:83889dc90473 171 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 172 break;
kshoji 0:83889dc90473 173 default:
kshoji 0:83889dc90473 174 // illegal state
kshoji 0:83889dc90473 175 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 176 break;
kshoji 0:83889dc90473 177 }
kshoji 0:83889dc90473 178 }
kshoji 0:83889dc90473 179 break;
kshoji 0:83889dc90473 180 default:
kshoji 0:83889dc90473 181 // illegal state
kshoji 0:83889dc90473 182 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 183 break;
kshoji 0:83889dc90473 184 }
kshoji 0:83889dc90473 185 } else if (midiState == MIDI_STATE_SIGNAL_3BYTES_2) {
kshoji 0:83889dc90473 186 switch (midiEventKind & 0xf0) {
kshoji 0:83889dc90473 187 case 0x80:
kshoji 0:83889dc90473 188 case 0x90:
kshoji 0:83889dc90473 189 case 0xa0:
kshoji 0:83889dc90473 190 case 0xb0:
kshoji 0:83889dc90473 191 case 0xe0:
kshoji 0:83889dc90473 192 case 0xf0:
kshoji 0:83889dc90473 193 // 3bytes pattern
kshoji 0:83889dc90473 194 midiEventNote = midiEvent;
kshoji 0:83889dc90473 195 midiState = MIDI_STATE_SIGNAL_3BYTES_3;
kshoji 0:83889dc90473 196 break;
kshoji 0:83889dc90473 197 default:
kshoji 0:83889dc90473 198 // illegal state
kshoji 0:83889dc90473 199 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 200 break;
kshoji 0:83889dc90473 201 }
kshoji 0:83889dc90473 202 } else if (midiState == MIDI_STATE_SIGNAL_3BYTES_3) {
kshoji 0:83889dc90473 203 switch (midiEventKind & 0xf0) {
kshoji 0:83889dc90473 204 // 3bytes pattern
kshoji 0:83889dc90473 205 case 0x80: // note off
kshoji 0:83889dc90473 206 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 207 onNoteOff(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 208 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 209 break;
kshoji 0:83889dc90473 210 case 0x90: // note on
kshoji 0:83889dc90473 211 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 212 if (midiEventVelocity == 0) {
kshoji 0:83889dc90473 213 onNoteOff(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 214 } else {
kshoji 0:83889dc90473 215 onNoteOn(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 216 }
kshoji 0:83889dc90473 217 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 218 break;
kshoji 0:83889dc90473 219 case 0xa0: // control polyphonic key pressure
kshoji 0:83889dc90473 220 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 221 onPolyphonicAftertouch(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 222 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 223 break;
kshoji 0:83889dc90473 224 case 0xb0: // control change
kshoji 0:83889dc90473 225 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 226 onControlChange(midiEventKind & 0xf, midiEventNote, midiEventVelocity);
kshoji 0:83889dc90473 227 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 228 break;
kshoji 0:83889dc90473 229 case 0xe0: // pitch bend
kshoji 0:83889dc90473 230 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 231 onPitchWheel(midiEventKind & 0xf, (midiEventNote & 0x7f) | ((midiEventVelocity & 0x7f) << 7));
kshoji 0:83889dc90473 232 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 233 break;
kshoji 0:83889dc90473 234 case 0xf0: // Song Position Pointer.
kshoji 0:83889dc90473 235 midiEventVelocity = midiEvent;
kshoji 0:83889dc90473 236 onSongPositionPointer((midiEventNote & 0x7f) | ((midiEventVelocity & 0x7f) << 7));
kshoji 0:83889dc90473 237 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 238 break;
kshoji 0:83889dc90473 239 default:
kshoji 0:83889dc90473 240 // illegal state
kshoji 0:83889dc90473 241 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 242 break;
kshoji 0:83889dc90473 243 }
kshoji 0:83889dc90473 244 } else if (midiState == MIDI_STATE_SIGNAL_SYSEX) {
kshoji 0:83889dc90473 245 if (midiEvent == 0xf7) {
kshoji 0:83889dc90473 246 // the end of message
kshoji 0:83889dc90473 247 // last written uint8_t is for timestamp
kshoji 1:cba2eba64f5c 248 if (sysExBufferPos > 0) {
kshoji 1:cba2eba64f5c 249 sysExBuffer[sysExBufferPos - 1] = midiEvent;
kshoji 2:dbc6f81b9ba0 250 onSystemExclusive(sysExBuffer, sysExBufferPos, false);
kshoji 1:cba2eba64f5c 251 }
kshoji 0:83889dc90473 252
kshoji 0:83889dc90473 253 sysExBufferPos = 0;
kshoji 0:83889dc90473 254 midiState = MIDI_STATE_TIMESTAMP;
kshoji 0:83889dc90473 255 } else {
kshoji 2:dbc6f81b9ba0 256 if (sysExBufferPos == 128) {
kshoji 2:dbc6f81b9ba0 257 onSystemExclusive(sysExBuffer, sysExBufferPos, true);
kshoji 2:dbc6f81b9ba0 258 sysExBufferPos = 0;
kshoji 2:dbc6f81b9ba0 259 }
kshoji 0:83889dc90473 260 sysExBuffer[sysExBufferPos++] = midiEvent;
kshoji 0:83889dc90473 261 }
kshoji 0:83889dc90473 262 }
kshoji 0:83889dc90473 263 }
kshoji 0:83889dc90473 264 }
kshoji 0:83889dc90473 265 }
kshoji 0:83889dc90473 266
kshoji 0:83889dc90473 267 BLEMIDI::BLEMIDI(BLEDevice *dev) {
kshoji 2:dbc6f81b9ba0 268 BLEMIDI(dev, "MIDI");
kshoji 2:dbc6f81b9ba0 269 }
kshoji 2:dbc6f81b9ba0 270
kshoji 2:dbc6f81b9ba0 271 BLEMIDI::BLEMIDI(BLEDevice *dev, char *deviceName) {
kshoji 0:83889dc90473 272 device = dev;
kshoji 0:83889dc90473 273 isConnected = false;
kshoji 0:83889dc90473 274 sysExBufferPos = 0;
kshoji 0:83889dc90473 275
kshoji 1:cba2eba64f5c 276 timestamp = 0;
kshoji 1:cba2eba64f5c 277 midiEventKind = 0;
kshoji 1:cba2eba64f5c 278 midiEventNote = 0;
kshoji 1:cba2eba64f5c 279 midiEventVelocity = 0;
kshoji 1:cba2eba64f5c 280
kshoji 0:83889dc90473 281 // MIDI characteristic
kshoji 0:83889dc90473 282 LongUUIDBytes_t characteristicUuid = {
kshoji 0:83889dc90473 283 0x77, 0x72, 0xe5, 0xdb, 0x38, 0x68, 0x41, 0x12,
kshoji 0:83889dc90473 284 0xa1, 0xa9, 0xf2, 0x66, 0x9d, 0x10, 0x6b, 0xf3
kshoji 0:83889dc90473 285 };
kshoji 0:83889dc90473 286
kshoji 1:cba2eba64f5c 287 midiCharacteristic = new GattCharacteristic(UUID(characteristicUuid), midi, 0, 20, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
kshoji 0:83889dc90473 288 GattCharacteristic *midiChars[] = {midiCharacteristic};
kshoji 0:83889dc90473 289
kshoji 0:83889dc90473 290 // MIDI service
kshoji 0:83889dc90473 291 LongUUIDBytes_t serviceUuid = {
kshoji 0:83889dc90473 292 0x03, 0xb8, 0x0e, 0x5a, 0xed, 0xe8, 0x4b, 0x33,
kshoji 0:83889dc90473 293 0xa7, 0x51, 0x6c, 0xe3, 0x4e, 0xc4, 0xc7, 0x00
kshoji 0:83889dc90473 294 };
kshoji 0:83889dc90473 295
kshoji 0:83889dc90473 296 GattService midiService(UUID(serviceUuid), midiChars, sizeof(midiChars) / sizeof(GattCharacteristic *));
kshoji 0:83889dc90473 297 uint8_t uuid128_list[] = {
kshoji 0:83889dc90473 298 0x00, 0xc7, 0xc4, 0x4e, 0xe3, 0x6c, 0x51, 0xa7,
kshoji 0:83889dc90473 299 0x33, 0x4b, 0xe8, 0xed, 0x5a, 0x0e, 0xb8, 0x03
kshoji 0:83889dc90473 300 };
kshoji 0:83889dc90473 301
kshoji 0:83889dc90473 302 device->init();
kshoji 0:83889dc90473 303 device->reset();
kshoji 0:83889dc90473 304
kshoji 0:83889dc90473 305 /* setup callbacks */
kshoji 0:83889dc90473 306 device->onDataWritten(this, &BLEMIDI::dataWrittenCallback);
kshoji 0:83889dc90473 307
kshoji 0:83889dc90473 308 device->addService(midiService);
kshoji 0:83889dc90473 309
kshoji 0:83889dc90473 310 /* setup advertising */
kshoji 0:83889dc90473 311 device->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t*)uuid128_list, sizeof(uuid128_list));
kshoji 0:83889dc90473 312 device->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
kshoji 2:dbc6f81b9ba0 313 device->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)deviceName, sizeof(deviceName));
kshoji 0:83889dc90473 314
kshoji 0:83889dc90473 315 device->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
kshoji 0:83889dc90473 316 device->setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */
kshoji 0:83889dc90473 317
kshoji 0:83889dc90473 318 device->startAdvertising();
kshoji 0:83889dc90473 319 tick.start();
kshoji 0:83889dc90473 320 }
kshoji 0:83889dc90473 321
kshoji 0:83889dc90473 322 bool BLEMIDI::connected() {
kshoji 0:83889dc90473 323 return isConnected;
kshoji 0:83889dc90473 324 }
kshoji 0:83889dc90473 325
kshoji 0:83889dc90473 326 void BLEMIDI::sendMidiMessage(uint8_t data0) {
kshoji 0:83889dc90473 327 if (isConnected) {
kshoji 0:83889dc90473 328 unsigned int ticks = tick.read_ms() & 0x1fff;
kshoji 1:cba2eba64f5c 329 midi[0] = 0x80 | ((ticks >> 7) & 0x3f);
kshoji 1:cba2eba64f5c 330 midi[1] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 331 midi[2] = data0;
kshoji 0:83889dc90473 332
kshoji 0:83889dc90473 333 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 3);
kshoji 0:83889dc90473 334 }
kshoji 0:83889dc90473 335 }
kshoji 0:83889dc90473 336
kshoji 0:83889dc90473 337 void BLEMIDI::sendMidiMessage(uint8_t data0, uint8_t data1) {
kshoji 0:83889dc90473 338 if (isConnected) {
kshoji 0:83889dc90473 339 unsigned int ticks = tick.read_ms() & 0x1fff;
kshoji 1:cba2eba64f5c 340 midi[0] = 0x80 | ((ticks >> 7) & 0x3f);
kshoji 1:cba2eba64f5c 341 midi[1] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 342 midi[2] = data0;
kshoji 0:83889dc90473 343 midi[3] = data1;
kshoji 0:83889dc90473 344
kshoji 0:83889dc90473 345 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 4);
kshoji 0:83889dc90473 346 }
kshoji 0:83889dc90473 347 }
kshoji 0:83889dc90473 348
kshoji 0:83889dc90473 349 void BLEMIDI::sendMidiMessage(uint8_t data0, uint8_t data1, uint8_t data2) {
kshoji 0:83889dc90473 350 if (isConnected) {
kshoji 0:83889dc90473 351 unsigned int ticks = tick.read_ms() & 0x1fff;
kshoji 1:cba2eba64f5c 352 midi[0] = 0x80 | ((ticks >> 7) & 0x3f);
kshoji 1:cba2eba64f5c 353 midi[1] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 354 midi[2] = data0;
kshoji 0:83889dc90473 355 midi[3] = data1;
kshoji 0:83889dc90473 356 midi[4] = data2;
kshoji 0:83889dc90473 357
kshoji 0:83889dc90473 358 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 5);
kshoji 0:83889dc90473 359 }
kshoji 0:83889dc90473 360 }
kshoji 0:83889dc90473 361
kshoji 0:83889dc90473 362 void BLEMIDI::sendTuneRequest() {
kshoji 0:83889dc90473 363 sendMidiMessage(0xf6);
kshoji 0:83889dc90473 364 }
kshoji 0:83889dc90473 365 void BLEMIDI::sendTimingClock() {
kshoji 0:83889dc90473 366 sendMidiMessage(0xf8);
kshoji 0:83889dc90473 367 }
kshoji 0:83889dc90473 368 void BLEMIDI::sendStart() {
kshoji 0:83889dc90473 369 sendMidiMessage(0xfa);
kshoji 0:83889dc90473 370 }
kshoji 0:83889dc90473 371 void BLEMIDI::sendContinue() {
kshoji 0:83889dc90473 372 sendMidiMessage(0xfb);
kshoji 0:83889dc90473 373 }
kshoji 0:83889dc90473 374 void BLEMIDI::sendStop() {
kshoji 0:83889dc90473 375 sendMidiMessage(0xfc);
kshoji 0:83889dc90473 376 }
kshoji 0:83889dc90473 377 void BLEMIDI::sendActiveSensing() {
kshoji 0:83889dc90473 378 sendMidiMessage(0xfe);
kshoji 0:83889dc90473 379 }
kshoji 0:83889dc90473 380 void BLEMIDI::sendReset() {
kshoji 0:83889dc90473 381 sendMidiMessage(0xff);
kshoji 0:83889dc90473 382 }
kshoji 0:83889dc90473 383 void BLEMIDI::sendProgramChange(uint8_t channel, uint8_t program) {
kshoji 0:83889dc90473 384 sendMidiMessage(0xc0 | (channel & 0xf), program);
kshoji 0:83889dc90473 385 }
kshoji 0:83889dc90473 386 void BLEMIDI::sendChannelAftertouch(uint8_t channel, uint8_t pressure) {
kshoji 0:83889dc90473 387 sendMidiMessage(0xd0 | (channel & 0xf), pressure);
kshoji 0:83889dc90473 388 }
kshoji 0:83889dc90473 389 void BLEMIDI::sendTimeCodeQuarterFrame(uint8_t timing) {
kshoji 0:83889dc90473 390 sendMidiMessage(0xf1, timing & 0x7f);
kshoji 0:83889dc90473 391 }
kshoji 0:83889dc90473 392 void BLEMIDI::sendSongSelect(uint8_t song) {
kshoji 0:83889dc90473 393 sendMidiMessage(0xf3, song & 0x7f);
kshoji 0:83889dc90473 394 }
kshoji 0:83889dc90473 395 void BLEMIDI::sendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {
kshoji 0:83889dc90473 396 sendMidiMessage(0x80 | (channel & 0xf), note, velocity);
kshoji 0:83889dc90473 397 }
kshoji 0:83889dc90473 398 void BLEMIDI::sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
kshoji 0:83889dc90473 399 sendMidiMessage(0x90 | (channel & 0xf), note, velocity);
kshoji 0:83889dc90473 400 }
kshoji 0:83889dc90473 401 void BLEMIDI::sendPolyphonicAftertouch(uint8_t channel, uint8_t note, uint8_t pressure) {
kshoji 0:83889dc90473 402 sendMidiMessage(0xa0 | (channel & 0xf), note, pressure);
kshoji 0:83889dc90473 403 }
kshoji 0:83889dc90473 404 void BLEMIDI::sendControlChange(uint8_t channel, uint8_t function, uint8_t value) {
kshoji 0:83889dc90473 405 sendMidiMessage(0xb0 | (channel & 0xf), function, value);
kshoji 0:83889dc90473 406 }
kshoji 0:83889dc90473 407 void BLEMIDI::sendPitchWheel(uint8_t channel, uint16_t amount) {
kshoji 0:83889dc90473 408 sendMidiMessage(0xe0 | (channel & 0xf), amount & 0x7f, (amount >> 7) & 0x7f);
kshoji 0:83889dc90473 409 }
kshoji 0:83889dc90473 410 void BLEMIDI::sendSongPositionPointer(uint16_t position) {
kshoji 0:83889dc90473 411 sendMidiMessage(0xf2, position & 0x7f, (position >> 7) & 0x7f);
kshoji 0:83889dc90473 412 }
kshoji 0:83889dc90473 413 void BLEMIDI::sendSystemExclusive(uint8_t * sysex, uint16_t length) {
kshoji 0:83889dc90473 414 if (isConnected) {
kshoji 0:83889dc90473 415 uint8_t position = 0;
kshoji 0:83889dc90473 416
kshoji 0:83889dc90473 417 // header
kshoji 1:cba2eba64f5c 418 uint16_t ticks = tick.read_ms() & 0x1fff;
kshoji 1:cba2eba64f5c 419 midi[position++] = 0x80 | ((ticks >> 7) & 0x3f);
kshoji 1:cba2eba64f5c 420 midi[position++] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 421
kshoji 0:83889dc90473 422 for (int i = 0; i < length; i++) {
kshoji 0:83889dc90473 423 if (i == length - 1) {
kshoji 1:cba2eba64f5c 424 // modify last byte
kshoji 1:cba2eba64f5c 425 midi[position++] = 0x80 | (ticks & 0x7f);
kshoji 0:83889dc90473 426
kshoji 0:83889dc90473 427 if (position == 20) {
kshoji 0:83889dc90473 428 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 20);
kshoji 0:83889dc90473 429
kshoji 0:83889dc90473 430 position = 0;
kshoji 0:83889dc90473 431 // header
kshoji 0:83889dc90473 432 midi[position++] = 0x80 | (ticks >> 7) & 0x3f;
kshoji 0:83889dc90473 433 }
kshoji 0:83889dc90473 434 }
kshoji 0:83889dc90473 435 midi[position++] = sysex[i];
kshoji 0:83889dc90473 436 if (position == 20) {
kshoji 0:83889dc90473 437 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, 20);
kshoji 0:83889dc90473 438
kshoji 0:83889dc90473 439 position = 0;
kshoji 0:83889dc90473 440 // header
kshoji 0:83889dc90473 441 midi[position++] = 0x80 | (ticks >> 7) & 0x3f;
kshoji 0:83889dc90473 442 }
kshoji 0:83889dc90473 443
kshoji 0:83889dc90473 444 ticks = tick.read_ms() & 0x1fff;
kshoji 0:83889dc90473 445 }
kshoji 0:83889dc90473 446
kshoji 0:83889dc90473 447 if (position > 0) {
kshoji 0:83889dc90473 448 // send remains
kshoji 0:83889dc90473 449 device->updateCharacteristicValue(midiCharacteristic->getValueAttribute().getHandle(), midi, position);
kshoji 0:83889dc90473 450 }
kshoji 0:83889dc90473 451 }
kshoji 0:83889dc90473 452 }