ALways output MIDI data through BLE
main.cpp@0:cf9bce1f2f5e, 2019-10-06 (annotated)
- Committer:
- dw02136
- Date:
- Sun Oct 06 05:08:18 2019 +0000
- Revision:
- 0:cf9bce1f2f5e
1st Issue
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dw02136 | 0:cf9bce1f2f5e | 1 | /* |
dw02136 | 0:cf9bce1f2f5e | 2 | The MIT License (MIT) |
dw02136 | 0:cf9bce1f2f5e | 3 | |
dw02136 | 0:cf9bce1f2f5e | 4 | Copyright (c) 2016 British Broadcasting Corporation. |
dw02136 | 0:cf9bce1f2f5e | 5 | This software is provided by Lancaster University by arrangement with the BBC. |
dw02136 | 0:cf9bce1f2f5e | 6 | |
dw02136 | 0:cf9bce1f2f5e | 7 | Permission is hereby granted, free of charge, to any person obtaining a |
dw02136 | 0:cf9bce1f2f5e | 8 | copy of this software and associated documentation files (the "Software"), |
dw02136 | 0:cf9bce1f2f5e | 9 | to deal in the Software without restriction, including without limitation |
dw02136 | 0:cf9bce1f2f5e | 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, |
dw02136 | 0:cf9bce1f2f5e | 11 | and/or sell copies of the Software, and to permit persons to whom the |
dw02136 | 0:cf9bce1f2f5e | 12 | Software is furnished to do so, subject to the following conditions: |
dw02136 | 0:cf9bce1f2f5e | 13 | |
dw02136 | 0:cf9bce1f2f5e | 14 | The above copyright notice and this permission notice shall be included in |
dw02136 | 0:cf9bce1f2f5e | 15 | all copies or substantial portions of the Software. |
dw02136 | 0:cf9bce1f2f5e | 16 | |
dw02136 | 0:cf9bce1f2f5e | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
dw02136 | 0:cf9bce1f2f5e | 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
dw02136 | 0:cf9bce1f2f5e | 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
dw02136 | 0:cf9bce1f2f5e | 20 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
dw02136 | 0:cf9bce1f2f5e | 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
dw02136 | 0:cf9bce1f2f5e | 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
dw02136 | 0:cf9bce1f2f5e | 23 | DEALINGS IN THE SOFTWARE. |
dw02136 | 0:cf9bce1f2f5e | 24 | */ |
dw02136 | 0:cf9bce1f2f5e | 25 | |
dw02136 | 0:cf9bce1f2f5e | 26 | #include "MicroBit.h" |
dw02136 | 0:cf9bce1f2f5e | 27 | |
dw02136 | 0:cf9bce1f2f5e | 28 | const static char DEVICE_NAME[] = "MY_MICROBIT_BLE_MIDI"; |
dw02136 | 0:cf9bce1f2f5e | 29 | const uint8_t MIDI_SERVICE[16] = { |
dw02136 | 0:cf9bce1f2f5e | 30 | 0x03, 0xb8, 0x0e, 0x5a, 0xed, 0xe8, 0x4b, 0x33, 0xa7, 0x51, 0x6c, 0xe3, 0x4e, 0xc4, 0xc7, 0x00 |
dw02136 | 0:cf9bce1f2f5e | 31 | }; |
dw02136 | 0:cf9bce1f2f5e | 32 | const uint8_t MIDI_CHAR[16] = { |
dw02136 | 0:cf9bce1f2f5e | 33 | 0x77, 0x72, 0xe5, 0xdb, 0x38, 0x68, 0x41, 0x12, 0xa1, 0xa9, 0xf2, 0x66, 0x9d, 0x10, 0x6b, 0xf3 |
dw02136 | 0:cf9bce1f2f5e | 34 | }; |
dw02136 | 0:cf9bce1f2f5e | 35 | |
dw02136 | 0:cf9bce1f2f5e | 36 | MicroBit uBit; |
dw02136 | 0:cf9bce1f2f5e | 37 | Serial pc(USBTX, USBRX); |
dw02136 | 0:cf9bce1f2f5e | 38 | |
dw02136 | 0:cf9bce1f2f5e | 39 | bool isConnect = false; |
dw02136 | 0:cf9bce1f2f5e | 40 | |
dw02136 | 0:cf9bce1f2f5e | 41 | //MIDI Charactarastics/Service |
dw02136 | 0:cf9bce1f2f5e | 42 | uint8_t midiPayload[5] = { 0x80, 0x80, 0x00, 0x00, 0x00 }; |
dw02136 | 0:cf9bce1f2f5e | 43 | |
dw02136 | 0:cf9bce1f2f5e | 44 | GattCharacteristic midiChar (MIDI_CHAR, |
dw02136 | 0:cf9bce1f2f5e | 45 | midiPayload, 5, 5, |
dw02136 | 0:cf9bce1f2f5e | 46 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); |
dw02136 | 0:cf9bce1f2f5e | 47 | GattCharacteristic *midiChars[] = {&midiChar, }; |
dw02136 | 0:cf9bce1f2f5e | 48 | GattService midiService(MIDI_SERVICE, midiChars, |
dw02136 | 0:cf9bce1f2f5e | 49 | sizeof(midiChars) / sizeof(GattCharacteristic *)); |
dw02136 | 0:cf9bce1f2f5e | 50 | |
dw02136 | 0:cf9bce1f2f5e | 51 | static Gap::ConnectionParams_t connectionParams; |
dw02136 | 0:cf9bce1f2f5e | 52 | |
dw02136 | 0:cf9bce1f2f5e | 53 | //NoteOn |
dw02136 | 0:cf9bce1f2f5e | 54 | void notifyNote(uint8_t note, uint8_t velocity); |
dw02136 | 0:cf9bce1f2f5e | 55 | |
dw02136 | 0:cf9bce1f2f5e | 56 | //BLE Connection Callback |
dw02136 | 0:cf9bce1f2f5e | 57 | void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params) |
dw02136 | 0:cf9bce1f2f5e | 58 | { |
dw02136 | 0:cf9bce1f2f5e | 59 | isConnect = true; |
dw02136 | 0:cf9bce1f2f5e | 60 | pc.printf("connected. Got handle %u\r\n", params->handle); |
dw02136 | 0:cf9bce1f2f5e | 61 | uBit.display.printChar('C'); |
dw02136 | 0:cf9bce1f2f5e | 62 | |
dw02136 | 0:cf9bce1f2f5e | 63 | connectionParams.slaveLatency = 1; |
dw02136 | 0:cf9bce1f2f5e | 64 | if (uBit.ble->gap().updateConnectionParams(params->handle, &connectionParams) != BLE_ERROR_NONE) { |
dw02136 | 0:cf9bce1f2f5e | 65 | pc.printf("failed to update connection paramter\r\n"); |
dw02136 | 0:cf9bce1f2f5e | 66 | } |
dw02136 | 0:cf9bce1f2f5e | 67 | } |
dw02136 | 0:cf9bce1f2f5e | 68 | |
dw02136 | 0:cf9bce1f2f5e | 69 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) |
dw02136 | 0:cf9bce1f2f5e | 70 | { |
dw02136 | 0:cf9bce1f2f5e | 71 | isConnect = false; |
dw02136 | 0:cf9bce1f2f5e | 72 | pc.printf("Disconnected handle %u, reason %u\r\n", params->handle, params->reason); |
dw02136 | 0:cf9bce1f2f5e | 73 | pc.printf("Restarting the advertising process\r\n"); |
dw02136 | 0:cf9bce1f2f5e | 74 | uBit.display.printChar('A'); |
dw02136 | 0:cf9bce1f2f5e | 75 | |
dw02136 | 0:cf9bce1f2f5e | 76 | pc.printf("Start Advertising\r\n"); |
dw02136 | 0:cf9bce1f2f5e | 77 | uBit.ble->gap().startAdvertising(); |
dw02136 | 0:cf9bce1f2f5e | 78 | } |
dw02136 | 0:cf9bce1f2f5e | 79 | |
dw02136 | 0:cf9bce1f2f5e | 80 | int main() |
dw02136 | 0:cf9bce1f2f5e | 81 | { |
dw02136 | 0:cf9bce1f2f5e | 82 | // Initialise the micro:bit runtime. |
dw02136 | 0:cf9bce1f2f5e | 83 | pc.printf("Initialising MicroBit\r\n"); |
dw02136 | 0:cf9bce1f2f5e | 84 | uBit.ble = new BLEDevice(); |
dw02136 | 0:cf9bce1f2f5e | 85 | uBit.init(); |
dw02136 | 0:cf9bce1f2f5e | 86 | uBit.ble->init(); |
dw02136 | 0:cf9bce1f2f5e | 87 | pc.printf("Init done\r\n"); |
dw02136 | 0:cf9bce1f2f5e | 88 | |
dw02136 | 0:cf9bce1f2f5e | 89 | //Add conection and disconnection callback |
dw02136 | 0:cf9bce1f2f5e | 90 | uBit.ble->gap().onConnection(onConnectionCallback); |
dw02136 | 0:cf9bce1f2f5e | 91 | uBit.ble->gap().onDisconnection(disconnectionCallback); |
dw02136 | 0:cf9bce1f2f5e | 92 | |
dw02136 | 0:cf9bce1f2f5e | 93 | /* setup advertising */ |
dw02136 | 0:cf9bce1f2f5e | 94 | uBit.ble->gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
dw02136 | 0:cf9bce1f2f5e | 95 | //Reverse UUID for Adv |
dw02136 | 0:cf9bce1f2f5e | 96 | uint8_t TMP_ADV_SERVICE[16]; |
dw02136 | 0:cf9bce1f2f5e | 97 | for(int i = 0; i < 16; i++) |
dw02136 | 0:cf9bce1f2f5e | 98 | { |
dw02136 | 0:cf9bce1f2f5e | 99 | TMP_ADV_SERVICE[i] = MIDI_SERVICE[15-i]; |
dw02136 | 0:cf9bce1f2f5e | 100 | } |
dw02136 | 0:cf9bce1f2f5e | 101 | uBit.ble->gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, (uint8_t*)TMP_ADV_SERVICE, sizeof(TMP_ADV_SERVICE)); |
dw02136 | 0:cf9bce1f2f5e | 102 | uBit.ble->gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_COMPUTER); |
dw02136 | 0:cf9bce1f2f5e | 103 | uBit.ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
dw02136 | 0:cf9bce1f2f5e | 104 | uBit.ble->gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
dw02136 | 0:cf9bce1f2f5e | 105 | uBit.ble->setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */ |
dw02136 | 0:cf9bce1f2f5e | 106 | uBit.ble->startAdvertising(); |
dw02136 | 0:cf9bce1f2f5e | 107 | pc.printf("Start Advertising\r\n"); |
dw02136 | 0:cf9bce1f2f5e | 108 | uBit.display.printChar('A'); |
dw02136 | 0:cf9bce1f2f5e | 109 | |
dw02136 | 0:cf9bce1f2f5e | 110 | uBit.ble->gattServer().addService(midiService); |
dw02136 | 0:cf9bce1f2f5e | 111 | |
dw02136 | 0:cf9bce1f2f5e | 112 | // Insert your code here! |
dw02136 | 0:cf9bce1f2f5e | 113 | while(1) { |
dw02136 | 0:cf9bce1f2f5e | 114 | if(isConnect) { |
dw02136 | 0:cf9bce1f2f5e | 115 | for (int note = 0x1E; note < 0x5A; note ++) { |
dw02136 | 0:cf9bce1f2f5e | 116 | notifyNote(note, 0x45); |
dw02136 | 0:cf9bce1f2f5e | 117 | wait_ms(100); |
dw02136 | 0:cf9bce1f2f5e | 118 | notifyNote(note, 0x00); |
dw02136 | 0:cf9bce1f2f5e | 119 | wait_ms(100); |
dw02136 | 0:cf9bce1f2f5e | 120 | } |
dw02136 | 0:cf9bce1f2f5e | 121 | } |
dw02136 | 0:cf9bce1f2f5e | 122 | } |
dw02136 | 0:cf9bce1f2f5e | 123 | |
dw02136 | 0:cf9bce1f2f5e | 124 | // If main exits, there may still be other fibers running or registered event handlers etc. |
dw02136 | 0:cf9bce1f2f5e | 125 | // Simply release this fiber, which will mean we enter the scheduler. Worse case, we then |
dw02136 | 0:cf9bce1f2f5e | 126 | // sit in the idle task forever, in a power efficient sleep. |
dw02136 | 0:cf9bce1f2f5e | 127 | //release_fiber(); |
dw02136 | 0:cf9bce1f2f5e | 128 | } |
dw02136 | 0:cf9bce1f2f5e | 129 | |
dw02136 | 0:cf9bce1f2f5e | 130 | //NotifyNote |
dw02136 | 0:cf9bce1f2f5e | 131 | void notifyNote(uint8_t note, uint8_t velocity) |
dw02136 | 0:cf9bce1f2f5e | 132 | { |
dw02136 | 0:cf9bce1f2f5e | 133 | //Send Note |
dw02136 | 0:cf9bce1f2f5e | 134 | midiPayload[2] = 0x90; |
dw02136 | 0:cf9bce1f2f5e | 135 | midiPayload[3] = note; |
dw02136 | 0:cf9bce1f2f5e | 136 | midiPayload[4] = velocity; |
dw02136 | 0:cf9bce1f2f5e | 137 | |
dw02136 | 0:cf9bce1f2f5e | 138 | //Notify MIDI Data |
dw02136 | 0:cf9bce1f2f5e | 139 | uBit.ble->gattServer().write(midiChar.getValueAttribute().getHandle(), midiPayload, sizeof(midiPayload)); |
dw02136 | 0:cf9bce1f2f5e | 140 | } |