This program enables a RedBearlab nRF51822 to be used as a "bridge device" with full bi-directional communication between MIDI through standard MIDI cables and BLE-MIDI. MIDI cables are connected to the UART. This allows for example to send MIDI data to synthesizers directly from a computer or a tablet via BLE-MIDI and vice-versa, "wires-free" . The Midi Manufacturers Association BLE-MIDI Specification is used. This project is inspired by Matthias Frick's "blidino" project which implements a USB-MIDI to BLE-MIDI bridge with the nRF51822 and is available at https://github.com/sieren/blidino. I owe to him all the BLE-MIDI to MIDI parsing part.

Dependencies:   BLE_API BufferedSerial mbed nRF51822

/media/uploads/popcornell/wp_20160713_22_30_15_rich.jpg

Video

Files at this revision

API Documentation at this revision

Comitter:
popcornell
Date:
Tue Aug 09 12:57:23 2016 +0000
Commit message:
first

Changed in this revision

BLEMIDI_MIDI_Parser.h Show annotated file Show diff for this revision Revisions of this file
BLE_API.lib Show annotated file Show diff for this revision Revisions of this file
BufferedSerial.lib Show annotated file Show diff for this revision Revisions of this file
MIDI_BLEMIDI_Parser.h Show annotated file Show diff for this revision Revisions of this file
config.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
nRF51822.lib Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLEMIDI_MIDI_Parser.h	Tue Aug 09 12:57:23 2016 +0000
@@ -0,0 +1,534 @@
+/*
+ *  Copyright (c) 2014 Matthias Frick   
+ *  
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ *
+ */
+
+#ifndef ____BLE_MIDI_Parser__
+#define ____BLE_MIDI_Parser__
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+
+
+
+
+
+    const int kMaxBufferSize=256; // max lenght for sysex buffer size 
+
+    uint8_t midiBuffer[3];
+    uint8_t sysExBuffer[kMaxBufferSize];
+    uint8_t alterSysExBuffer[kMaxBufferSize];
+    int midiBufferPtr ;   // int midiBufferPtr = 0;
+    int sysExRecBufferPtr ;  // int sysExRecBufferPtr = 0;
+    int sysExBufferPtr ;     // int sysExBufferPtr = 0; 
+
+
+    // MIDI event messages, state & stamps
+    int midiEventKind;
+    int midiEventNote;
+    int midiEventVelocity;
+    int midiState;   //int midiState = MIDI_STATE_TIMESTAMP;
+    int timestamp;
+
+
+    bool useTimestamp ; // bool useTimestamp = true;
+    
+    int lastTimestamp;
+    long lastTimestampRecorded ;  //  long lastTimestampRecorded = 0; 
+    int zeroTimestampCount;     //   int zeroTimestampCount = 0; 
+    //Receiver *midiRecv;
+
+
+
+
+////////////////////////////////////
+
+
+  static int MIDI_STATE_TIMESTAMP = 0;
+  static int MIDI_STATE_WAIT = 1;
+  static int MIDI_STATE_SIGNAL_2BYTES_2 = 21;
+  static int MIDI_STATE_SIGNAL_3BYTES_2 = 31;
+  static int MIDI_STATE_SIGNAL_3BYTES_3 = 32;
+  static int MIDI_STATE_SIGNAL_SYSEX = 41;
+
+  // for Timestamp
+  static int MAX_TIMESTAMP = 8192;
+  static int BUFFER_LENGTH_MILLIS = 10;
+
+
+  // for RPN/NRPN messages
+  static int PARAMETER_MODE_NONE = 0;
+  static int PARAMETER_MODE_RPN = 1;
+  static int PARAMETER_MODE_NRPN = 2;
+  int parameterMode = 0;
+  int parameterNumber = 0x3fff;
+  int parameterValue = 0x3fff;
+
+    void addByteToMidiBuffer(uint8_t midiEvent)
+    {
+      midiBuffer[midiBufferPtr] = midiEvent;
+      midiBufferPtr++;
+    }
+
+    void addByteToSysExBuffer(uint8_t midiEvent)
+    {
+      sysExBuffer[sysExBufferPtr] = midiEvent;
+      sysExBufferPtr++;
+    }
+
+    uint8_t replaceLastByteInSysExBuffer(uint8_t midiEvent)
+    {
+      sysExBufferPtr--;
+      uint8_t lastEvt = sysExBuffer[sysExBufferPtr];
+      sysExBuffer[sysExBufferPtr] = midiEvent;
+      sysExBufferPtr++;
+      return lastEvt;
+    }
+
+    void sendSysex()
+    {
+      
+      for(int i = 0 ; i<=sysExBufferPtr; i++ ) { // send sysex message on the UART 
+      UART.putc(sysExBuffer[i]) ; 
+      }
+      //midiRecv->SendSysEx(sysExBuffer, sysExBufferPtr, 0);
+    }
+
+    void createSysExRecovery()
+    {
+      sysExRecBufferPtr = sysExBufferPtr;
+      memcpy(alterSysExBuffer, sysExBuffer, sysExBufferPtr);
+    }
+
+    void sendSysexRecovery()
+    {
+     
+     for(int i = 0 ; i<=sysExRecBufferPtr; i++ ) { 
+      UART.putc(alterSysExBuffer[i]) ; 
+      }
+     // midiRecv->SendSysEx(alterSysExBuffer, sysExRecBufferPtr, 0);
+    }
+
+    uint8_t replaceLastByteInRecoveryBuffer(uint8_t midiEvent)
+    {
+      sysExRecBufferPtr--;
+      uint8_t lastEvt = alterSysExBuffer[sysExRecBufferPtr];
+      alterSysExBuffer[sysExRecBufferPtr] = midiEvent;
+      sysExRecBufferPtr++;
+      return lastEvt;
+    }
+
+    void addByteToRecoveryBuffer(uint8_t midiEvent)
+    {
+      alterSysExBuffer[sysExRecBufferPtr] = midiEvent;
+      sysExRecBufferPtr++;
+    }
+
+    void resetMidiBuffer()
+    {
+      memset(&midiBuffer[0], 0, sizeof(midiBuffer));
+      midiBufferPtr = 0;
+    }
+
+    void resetSysExBuffer()
+    {
+      memset(&sysExBuffer[0], 0, kMaxBufferSize);
+      sysExBufferPtr = 0;
+    }
+
+    void resetRecoveryBuffer()
+    {
+      memset(&alterSysExBuffer[0], 0, sizeof(alterSysExBuffer));
+      sysExRecBufferPtr = 0;
+    }
+
+    void sendMidi(uint8_t size)  // send MIDI Message on the UART 
+    {
+      for(int i = 0 ; i<=size ; i++ ) { 
+      UART.putc(midiBuffer[i]) ; 
+      }
+      
+    }
+
+ 
+
+    void parseMidiEvent(uint8_t header, const uint8_t event)
+    {
+      uint8_t midiEvent = event & 0xff;
+    
+      // printf((char*)midiEvent);
+      if (midiState == MIDI_STATE_TIMESTAMP)
+      {
+       // printf("Timestamp");
+        if ((midiEvent & 0x80) == 0)
+        {
+          // running status
+          midiState = MIDI_STATE_WAIT;
+        }
+
+        if (midiEvent == 0xf7)
+        {
+          // make sure this is the end of sysex
+          // and send alternative recovery stream
+          if (sysExRecBufferPtr > 0)
+          {
+            uint8_t removed = replaceLastByteInRecoveryBuffer(midiEvent);
+            sendSysexRecovery();
+            resetRecoveryBuffer();
+          }
+          midiState = MIDI_STATE_TIMESTAMP;
+          return;
+        }
+        else
+        {
+          // reset alternative sysex stream
+           resetRecoveryBuffer();
+        }
+      } // end of timestamp
+
+      if (midiState == MIDI_STATE_TIMESTAMP)
+      {
+        timestamp = ((header & 0x3f) << 7) | (midiEvent & 0x7f);
+        midiState = MIDI_STATE_WAIT;
+      }
+      else if (midiState == MIDI_STATE_WAIT)
+      {
+        switch (midiEvent & 0xf0) {
+          case 0xf0: {
+            switch (midiEvent) {
+              case 0xf0:
+                resetRecoveryBuffer();
+                resetSysExBuffer();
+                addByteToSysExBuffer(midiEvent);
+                midiState = MIDI_STATE_SIGNAL_SYSEX;
+                break;
+              case 0xf1:
+              case 0xf3:
+                // 0xf1 MIDI Time Code Quarter Frame. : 2bytes
+                // 0xf3 Song Select. : 2bytes
+                midiEventKind = midiEvent;
+                addByteToMidiBuffer(midiEvent);
+                midiState = MIDI_STATE_SIGNAL_2BYTES_2;
+                break;
+              case 0xf2:
+                // 0xf2 Song Position Pointer. : 3bytes
+                midiEventKind = midiEvent;
+                addByteToMidiBuffer(midiEvent);
+                midiState = MIDI_STATE_SIGNAL_3BYTES_2;
+                break;
+              case 0xf6:
+                // 0xf6 Tune Request : 1byte
+                addByteToMidiBuffer(midiEvent);
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+              case 0xf8:
+                // 0xf8 Timing Clock : 1byte
+                //#pragma mark send timeclock // no on mbed OS 
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+              case 0xfa:
+                // 0xfa Start : 1byte
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+              case 0xfb:
+                // 0xfb Continue : 1byte
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+              case 0xfc:
+                // 0xfc Stop : 1byte
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+              case 0xfe:
+                // 0xfe Active Sensing : 1byte
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+              case 0xff:
+                // 0xff Reset : 1byte
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+
+              default:
+                break;
+            }
+          }
+          break;
+          case 0x80:
+          case 0x90:
+          case 0xa0:
+          case 0xb0:
+          case 0xe0:
+            // 3bytes pattern
+            midiEventKind = midiEvent;
+            midiState = MIDI_STATE_SIGNAL_3BYTES_2;
+            break;
+          case 0xc0: // program change
+          case 0xd0: // channel after-touch
+            // 2bytes pattern
+            midiEventKind = midiEvent;
+            midiState = MIDI_STATE_SIGNAL_2BYTES_2;
+            break;
+          default:
+            // 0x00 - 0x70: running status
+            if ((midiEventKind & 0xf0) != 0xf0) {
+              // previous event kind is multi-bytes pattern
+              midiEventNote = midiEvent;
+              midiState = MIDI_STATE_SIGNAL_3BYTES_3;
+            }
+            break;
+        }
+      }
+      else if (midiState == MIDI_STATE_SIGNAL_2BYTES_2)
+      {
+        switch (midiEventKind & 0xf0)
+        {
+            // 2bytes pattern
+          case 0xc0: // program change
+            midiEventNote = midiEvent;
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+          case 0xd0: // channel after-touch
+            midiEventNote = midiEvent;
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+          case 0xf0:
+          {
+            switch (midiEventKind)
+            {
+              case 0xf1:
+                // 0xf1 MIDI Time Code Quarter Frame. : 2bytes
+                midiEventNote = midiEvent;
+                addByteToMidiBuffer(midiEventNote);
+                sendMidi(2);
+                resetMidiBuffer();
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+              case 0xf3:
+                // 0xf3 Song Select. : 2bytes
+                midiEventNote = midiEvent;
+                addByteToMidiBuffer(midiEventNote);
+                sendMidi(2);
+                resetMidiBuffer();
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+              default:
+                // illegal state
+                midiState = MIDI_STATE_TIMESTAMP;
+                break;
+            }
+          }
+            break;
+          default:
+            // illegal state
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+        }
+      }
+      else if (midiState == MIDI_STATE_SIGNAL_3BYTES_2)
+      {
+        switch (midiEventKind & 0xf0)
+        {
+          case 0x80:
+          case 0x90:
+          case 0xa0:
+          case 0xb0:
+          case 0xe0:
+          case 0xf0:
+            // 3bytes pattern
+            midiEventNote = midiEvent;
+            midiState = MIDI_STATE_SIGNAL_3BYTES_3;
+            break;
+          default:
+            // illegal state
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+        }
+      }
+      else if (midiState == MIDI_STATE_SIGNAL_3BYTES_3)
+      {
+        switch (midiEventKind & 0xf0)
+        {
+            // 3bytes pattern
+          case 0x80: // note off
+           
+            midiEventVelocity = midiEvent;
+            addByteToMidiBuffer(midiEventKind);
+            addByteToMidiBuffer(midiEventNote);
+            addByteToMidiBuffer(midiEventVelocity);
+            sendMidi(3);
+            resetMidiBuffer();
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+          case 0x90: // note on
+            midiEventVelocity = midiEvent;
+            //timeToWait = calculateTimeToWait(timestamp);
+            
+            addByteToMidiBuffer(midiEventKind);
+            addByteToMidiBuffer(midiEventNote);
+            addByteToMidiBuffer(midiEventVelocity);
+            sendMidi(3);
+            resetMidiBuffer();
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+          case 0xa0: // control polyphonic key pressure
+            midiEventVelocity = midiEvent;
+            addByteToMidiBuffer(midiEventKind);
+            addByteToMidiBuffer(midiEventNote);
+            addByteToMidiBuffer(midiEventVelocity);
+            sendMidi(3);
+            resetMidiBuffer();
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+          case 0xb0: // control change
+            midiEventVelocity = midiEvent;
+            switch (midiEventNote & 0x7f)
+            {
+              case 98:
+                // NRPN LSB
+                parameterNumber &= 0x3f80;
+                parameterNumber |= midiEventVelocity & 0x7f;
+                parameterMode = PARAMETER_MODE_NRPN;
+                break;
+              case 99:
+                // NRPN MSB
+                parameterNumber &= 0x007f;
+                parameterNumber |= (midiEventVelocity & 0x7f) << 7;
+                parameterMode = PARAMETER_MODE_NRPN;
+                break;
+              case 100:
+                // RPN LSB
+                parameterNumber &= 0x3f80;
+                parameterNumber |= midiEventVelocity & 0x7f;
+                parameterMode = PARAMETER_MODE_RPN;
+                break;
+              case 101:
+                // RPN MSB
+                parameterNumber &= 0x007f;
+                parameterNumber |= (midiEventVelocity & 0x7f) << 7;
+                parameterMode = PARAMETER_MODE_RPN;
+                break;
+              case 38:
+                // data LSB
+                parameterValue &= 0x3f80;
+                parameterValue |= midiEventVelocity & 0x7f;
+
+                if (parameterNumber != 0x3fff) {
+                  if (parameterMode == PARAMETER_MODE_RPN)
+                  {
+                    addByteToMidiBuffer(midiEventKind);
+                    addByteToMidiBuffer(parameterNumber);
+                    addByteToMidiBuffer(parameterValue);
+                    sendMidi(3);
+                    resetMidiBuffer();
+                  }
+                  else if (parameterMode == PARAMETER_MODE_NRPN)
+                  {
+                    addByteToMidiBuffer(midiEventKind);
+                    addByteToMidiBuffer(parameterNumber);
+                    addByteToMidiBuffer(parameterValue);
+                    sendMidi(3);
+                    resetMidiBuffer();
+                  }
+                }
+                break;
+              case 6:
+                // data MSB
+                parameterValue &= 0x007f;
+                parameterValue |= (midiEventVelocity & 0x7f) << 7;
+
+                if (parameterNumber != 0x3fff)
+                {
+                  if (parameterMode == PARAMETER_MODE_RPN)
+                  {
+                    addByteToMidiBuffer(midiEventKind);
+                    addByteToMidiBuffer(parameterNumber);
+                    addByteToMidiBuffer(parameterValue);
+                    sendMidi(3);
+                    resetMidiBuffer();
+                  }
+                  else if (parameterMode == PARAMETER_MODE_NRPN)
+                  {
+                    addByteToMidiBuffer(midiEventKind);
+                    addByteToMidiBuffer(parameterNumber);
+                    addByteToMidiBuffer(parameterValue);
+                    sendMidi(3);
+                    resetMidiBuffer();
+                  }
+                }
+                break;
+              default:
+                // do nothing
+                break;
+            }
+            addByteToMidiBuffer(midiEventKind);
+            addByteToMidiBuffer(midiEventNote);
+            addByteToMidiBuffer(midiEventVelocity);
+            sendMidi(3);
+            resetMidiBuffer();
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+          case 0xe0: // pitch bend
+            midiEventVelocity = midiEvent;
+            addByteToMidiBuffer(midiEventKind);
+            addByteToMidiBuffer(midiEventNote);
+            addByteToMidiBuffer(midiEventVelocity);
+            sendMidi(3);
+            resetMidiBuffer();
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+          case 0xf0: // Song Position Pointer.
+            midiEventVelocity = midiEvent;
+            addByteToMidiBuffer(midiEventKind);
+            addByteToMidiBuffer(midiEventNote);
+            addByteToMidiBuffer(midiEventVelocity);
+            sendMidi(3);
+            resetMidiBuffer();
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+          default:
+            // illegal state
+            midiState = MIDI_STATE_TIMESTAMP;
+            break;
+        }
+      }
+      else if (midiState == MIDI_STATE_SIGNAL_SYSEX)
+      {
+        if (midiEvent == 0xf7)
+        {
+          uint8_t repEvt = replaceLastByteInSysExBuffer(midiEvent);
+
+          resetRecoveryBuffer();
+          createSysExRecovery();
+          replaceLastByteInRecoveryBuffer(repEvt);
+          addByteToRecoveryBuffer(midiEvent);
+          sendSysex();
+          resetSysExBuffer();
+          midiState = MIDI_STATE_TIMESTAMP;
+        }
+        else
+        {
+          addByteToSysExBuffer(midiEvent);
+        }
+
+      }
+    }
+     
+
+#endif /* defined(____BLEParser__) */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_API.lib	Tue Aug 09 12:57:23 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#d494ad3e87bd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BufferedSerial.lib	Tue Aug 09 12:57:23 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/sam_grove/code/BufferedSerial/#a0d37088b405
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MIDI_BLEMIDI_Parser.h	Tue Aug 09 12:57:23 2016 +0000
@@ -0,0 +1,473 @@
+/*
+ *  Original work Copyright (c) 2015 Francois Best  
+ *  
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ *
+ */
+
+
+/* 
+*  Modified work by Samuele Cornell.
+*  The following code is adapted from Francois Best's Arduino MIDI Library v4.2 
+*  (see https://github.com/FortySevenEffects/arduino_midi_library)  
+*/
+
+
+
+namespace MIDI {  
+
+#define SysExMaxSize 128 
+#define Use1ByteParsing 0
+
+typedef uint8_t byte ; // byte isn't defined in mbed OS
+
+typedef uint8_t StatusByte;
+typedef uint8_t DataByte;
+typedef uint8_t Channel;
+
+
+
+/*! Enumeration of MIDI types */
+enum MidiType
+{
+    InvalidType           = 0x00,    ///< For notifying errors
+    NoteOff               = 0x80,    ///< Note Off
+    NoteOn                = 0x90,    ///< Note On
+    AfterTouchPoly        = 0xA0,    ///< Polyphonic AfterTouch
+    ControlChange         = 0xB0,    ///< Control Change / Channel Mode
+    ProgramChange         = 0xC0,    ///< Program Change
+    AfterTouchChannel     = 0xD0,    ///< Channel (monophonic) AfterTouch
+    PitchBend             = 0xE0,    ///< Pitch Bend
+    SystemExclusive       = 0xF0,    ///< System Exclusive
+    TimeCodeQuarterFrame  = 0xF1,    ///< System Common - MIDI Time Code Quarter Frame
+    SongPosition          = 0xF2,    ///< System Common - Song Position Pointer
+    SongSelect            = 0xF3,    ///< System Common - Song Select
+    TuneRequest           = 0xF6,    ///< System Common - Tune Request
+    Clock                 = 0xF8,    ///< System Real Time - Timing Clock
+    Start                 = 0xFA,    ///< System Real Time - Start
+    Continue              = 0xFB,    ///< System Real Time - Continue
+    Stop                  = 0xFC,    ///< System Real Time - Stop
+    ActiveSensing         = 0xFE,    ///< System Real Time - Active Sensing
+    SystemReset           = 0xFF,    ///< System Real Time - System Reset
+};
+
+
+struct MidiMessage 
+{
+    /*! The maximum size for the System Exclusive array.
+    */
+    static const unsigned sSysExMaxSize = SysExMaxSize;   // this 
+
+    /*! The MIDI channel on which the message was recieved.
+     \n Value goes from 1 to 16.
+     */
+    Channel channel;
+
+    /*! The type of the message
+     (see the MidiType enum for types reference)
+     */
+    MidiType type;
+
+    /*! The first data byte.
+     \n Value goes from 0 to 127.
+     */
+    DataByte data1;
+
+    /*! The second data byte.
+     If the message is only 2 bytes long, this one is null.
+     \n Value goes from 0 to 127.
+     */
+    DataByte data2;
+
+    /*! System Exclusive dedicated byte array.
+     \n Array length is stocked on 16 bits,
+     in data1 (LSB) and data2 (MSB)
+     */
+    DataByte sysexArray[sSysExMaxSize];
+
+    /*! This boolean indicates if the message is valid or not.
+     There is no channel consideration here,
+     validity means the message respects the MIDI norm.
+     */
+    bool valid;
+
+    inline unsigned getSysExSize() const
+    {
+        const unsigned size = unsigned(data2) << 8 | data1;
+        return size > sSysExMaxSize ? sSysExMaxSize : size;
+    } 
+ 
+    MidiMessage() {  // initialize 
+    
+    channel=0;
+    type= InvalidType ;
+    data1= 0 ; 
+    data2= 0 ; 
+    valid =false ; 
+    } 
+    
+    
+}; 
+   
+
+    StatusByte  mRunningStatus_RX;
+    StatusByte  mRunningStatus_TX;
+    Channel     mInputChannel= 1 ; // default 1
+    uint8_t     mPendingMessage[3];
+    uint8_t     mPendingMessageExpectedLenght = 0;
+    uint8_t     mPendingMessageIndex= 0;
+    
+    
+    
+    MidiMessage mMessage;
+    
+   
+
+inline void resetInput()
+{
+    mPendingMessageIndex = 0;
+    mPendingMessageExpectedLenght = 0;
+    mRunningStatus_RX = InvalidType;
+}
+
+MidiType getTypeFromStatusByte(uint8_t inStatus)
+{
+    if ((inStatus  < 0x80) ||
+        (inStatus == 0xf4) ||
+        (inStatus == 0xf5) ||
+        (inStatus == 0xf9) ||
+        (inStatus == 0xfD))
+    {
+        // Data bytes and undefined.
+        return InvalidType;
+    }
+    if (inStatus < 0xf0)
+    {
+        // Channel message, remove channel nibble.
+        return MidiType(inStatus & 0xf0);
+    }
+
+    return MidiType(inStatus);
+}
+
+/*! \brief Returns channel in the range 1-16
+ */
+  
+  inline Channel getChannelFromStatusByte(uint8_t inStatus)
+  {
+    return (inStatus & 0x0f) + 1;
+  }
+
+  
+  bool isChannelMessage(MidiType inType)
+  {
+     return (inType == NoteOff          ||
+            inType == NoteOn            ||
+            inType == ControlChange     ||
+            inType == AfterTouchPoly    ||
+            inType == AfterTouchChannel ||
+            inType == PitchBend         ||
+            inType == ProgramChange);
+   }
+
+
+
+bool MIDI_to_BLEMIDI_Parser (void ) { 
+
+
+ if (UART.readable() == 0)
+        // No data available.
+        return false;
+
+    // Parsing algorithm:
+    // Get a byte from the serial buffer.
+    // If there is no pending message to be recomposed, start a new one.
+    //  - Find type and channel (if pertinent)
+    //  - Look for other bytes in buffer, call parser recursively,
+    //    until the message is assembled or the buffer is empty.
+    // Else, add the extracted byte to the pending message, and check validity.
+    // When the message is done, store it.
+
+    const uint8_t extracted = UART.getc();
+
+    if (mPendingMessageIndex == 0)
+    {
+        // Start a new pending message
+        mPendingMessage[0] = extracted;
+
+        // Check for running status first
+        if (isChannelMessage(getTypeFromStatusByte(mRunningStatus_RX)))
+        {
+            // Only these types allow Running Status
+
+            // If the status byte is not received, prepend it
+            // to the pending message
+            if (extracted < 0x80)
+            {
+                mPendingMessage[0]   = mRunningStatus_RX;
+                mPendingMessage[1]   = extracted;
+                mPendingMessageIndex = 1;
+            }
+            // Else: well, we received another status byte,
+            // so the running status does not apply here.
+            // It will be updated upon completion of this message.
+        }
+
+        switch (getTypeFromStatusByte(mPendingMessage[0]))
+        {
+            // 1 byte messages
+            case Start:
+            case Continue:
+            case Stop:
+            case Clock:
+            case ActiveSensing:
+            case SystemReset:
+            case TuneRequest:
+            
+                // Handle the message type directly here.
+                mMessage.type    = getTypeFromStatusByte(mPendingMessage[0]);
+                mMessage.channel = 0;
+                mMessage.data1   = 0;
+                mMessage.data2   = 0;
+                mMessage.valid   = true;
+
+                // \fix Running Status broken when receiving Clock messages.
+                // Do not reset all input attributes, Running Status must remain unchanged.
+                //resetInput();
+
+                // We still need to reset these
+                mPendingMessageIndex = 0;
+                mPendingMessageExpectedLenght = 0;
+
+                return true;
+                break;
+
+                // 2 bytes messages
+            case ProgramChange:
+            case AfterTouchChannel:
+            case TimeCodeQuarterFrame:
+            case SongSelect:
+                mPendingMessageExpectedLenght = 2;
+                break;
+
+                // 3 bytes messages
+            case NoteOn:
+            case NoteOff:
+            case ControlChange:
+            case PitchBend:
+            case AfterTouchPoly:
+            case SongPosition:
+                mPendingMessageExpectedLenght = 3;
+                break;
+
+            case SystemExclusive:
+                // The message can be any lenght
+                // between 3 and MidiMessage::sSysExMaxSize bytes
+                mPendingMessageExpectedLenght = MidiMessage::sSysExMaxSize;
+                mRunningStatus_RX = InvalidType;
+                mMessage.sysexArray[0] = SystemExclusive;
+                break;
+
+            case InvalidType:
+            default:
+                // This is obviously wrong. Let's get the hell out'a here.
+                resetInput();
+                return false;
+                break;
+        }
+
+        if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1))
+        {
+            // Reception complete
+            mMessage.type    = getTypeFromStatusByte(mPendingMessage[0]);
+            mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]);
+            mMessage.data1   = mPendingMessage[1];
+
+            // Save data2 only if applicable
+            if (mPendingMessageExpectedLenght == 3)
+                mMessage.data2 = mPendingMessage[2];
+            else
+                mMessage.data2 = 0;
+
+            mPendingMessageIndex = 0;
+            mPendingMessageExpectedLenght = 0;
+            mMessage.valid = true;
+            return true;
+        }
+        else
+        {
+            // Waiting for more data
+            mPendingMessageIndex++;
+        }
+
+        if (Use1ByteParsing==1)
+        {
+            // Message is not complete.
+            return false;
+        }
+        else
+        {
+            // Call the parser recursively
+            // to parse the rest of the message.
+            return MIDI_to_BLEMIDI_Parser();
+        }
+    }
+    else
+    {
+        // First, test if this is a status byte
+        if (extracted >= 0x80)
+        {
+            // Reception of status bytes in the middle of an uncompleted message
+            // are allowed only for interleaved Real Time message or EOX
+            switch (extracted)
+            {
+                case Clock:
+                case Start:
+                case Continue:
+                case Stop:
+                case ActiveSensing:
+                case SystemReset:
+
+                    // Here we will have to extract the one-byte message,
+                    // pass it to the structure for being read outside
+                    // the MIDI class, and recompose the message it was
+                    // interleaved into. Oh, and without killing the running status..
+                    // This is done by leaving the pending message as is,
+                    // it will be completed on next calls.
+
+                    mMessage.type    = (MidiType)extracted;
+                    mMessage.data1   = 0;
+                    mMessage.data2   = 0;
+                    mMessage.channel = 0;
+                    mMessage.valid   = true;
+                    return true;
+
+                    break;
+
+                    // End of Exclusive
+                case 0xf7:
+                    if (mMessage.sysexArray[0] == SystemExclusive)
+                    {
+                        // Store the last byte (EOX)
+                        mMessage.sysexArray[mPendingMessageIndex++] = 0xf7;
+                        mMessage.type = SystemExclusive;
+
+                        // Get length
+                        mMessage.data1   = mPendingMessageIndex & 0xff; // LSB
+                        mMessage.data2   = mPendingMessageIndex >> 8;   // MSB
+                        mMessage.channel = 0;
+                        mMessage.valid   = true;
+
+                        resetInput();
+                        return true;
+                    }
+                    else
+                    {
+                        // Well well well.. error.
+                        resetInput();
+                        return false;
+                    }
+
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        // Add extracted data byte to pending message
+        if (mPendingMessage[0] == SystemExclusive)
+            mMessage.sysexArray[mPendingMessageIndex] = extracted;
+        else
+            mPendingMessage[mPendingMessageIndex] = extracted;
+
+        // Now we are going to check if we have reached the end of the message
+        if (mPendingMessageIndex >= (mPendingMessageExpectedLenght - 1))
+        {
+            // "FML" case: fall down here with an overflown SysEx..
+            // This means we received the last possible data byte that can fit
+            // the buffer. If this happens, try increasing MidiMessage::sSysExMaxSize.
+            if (mPendingMessage[0] == SystemExclusive)
+            {
+                resetInput();
+                return false;
+            }
+
+            mMessage.type = getTypeFromStatusByte(mPendingMessage[0]);
+
+            if (isChannelMessage(mMessage.type))
+                mMessage.channel = getChannelFromStatusByte(mPendingMessage[0]);
+            else
+                mMessage.channel = 0;
+
+            mMessage.data1 = mPendingMessage[1];
+
+            // Save data2 only if applicable
+            if (mPendingMessageExpectedLenght == 3)
+                mMessage.data2 = mPendingMessage[2];
+            else
+                mMessage.data2 = 0;
+
+            // Reset local variables
+            mPendingMessageIndex = 0;
+            mPendingMessageExpectedLenght = 0;
+
+            mMessage.valid = true;
+
+            // Activate running status (if enabled for the received type)
+            switch (mMessage.type)
+            {
+                case NoteOff:
+                case NoteOn:
+                case AfterTouchPoly:
+                case ControlChange:
+                case ProgramChange:
+                case AfterTouchChannel:
+                case PitchBend:
+                    // Running status enabled: store it from received message
+                    mRunningStatus_RX = mPendingMessage[0];
+                    break;
+
+                default:
+                    // No running status
+                    mRunningStatus_RX = InvalidType;
+                    break;
+            }
+            return true;
+        }
+        else
+        {
+            // Then update the index of the pending message.
+            mPendingMessageIndex++;
+
+            if (Use1ByteParsing==1)
+            {
+                // Message is not complete.
+                return false;
+            }
+            else
+            {
+                // Call the parser recursively to parse the rest of the message.
+                return MIDI_to_BLEMIDI_Parser();
+            }
+        }
+    }
+}
+
+
+} // end namespace 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config.h	Tue Aug 09 12:57:23 2016 +0000
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (c) 2016 Samuele Cornell  
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ *
+ */
+
+#define UART_RX_PIN D0 // RX  UART Pin  
+
+#define UART_TX_PIN D1 // TX UART Pin 
+
+// i have used DFRobot MIDI Shield but there are other commercially available similar products, also it is possible to interface directly a MIDI cable via an optocoupler (several projects are already available online ) 
+
+#define LIGHT_SHOW 1 // 0 if visual feedback isn't needed  (saves energy )
+
+#define TX_LED D6 // the state of this led will change whenever a message is to be sent over ble-midi
+
+#define RX_LED D7 // the state of this led will change whenever a message received over ble-midi
+
+
+/*******************************************************************************************************
+PERFORMANCE TWEAKS
+*******************************************************************************************************/
+
+
+#define BUFSERIAL_LENGHT 256 // define the software circular buffer lenght used for the UART. 
+
+
+#define ONLY_MIDI_to_BLEMIDI 0 // if only unidirectional MIDI to BLE-MIDI is desired set this to 1  
+
+
+#define ONLY_BLEMIDI_to_MIDI 0 // if only unidirectional BLE-MIDI to MIDI is desired set this to 1 
+
+// unidirectional operation allows to save energy. It also leads to better performance as if ONLY MIDI to BLE MIDI is required, for example it is  possible to shorten the SENDBLE_INTERVAL
+// without reliability issues (to a certain extent).   
+
+#define SENDBLEMIDI_INTERVAL 0.01 // this defines how frequently MIDI Events from the UART are polled, parsed and then sent via BLE-MIDI. 
+                                 // a lower value means less latency but it also increase energy comsuption and if is set too low can cause reliability issues in MIDI to BLE-MIDI operation (especially for long SysEx messages).  
+
+
+/***************************************************************************************************************
+CONNECTION PARAMETERS 
+***************************************************************************************************************/
+
+namespace Config { 
+
+// 
+const int minConnectionInterval = 6; // (1.25 ms units)  
+const int maxConnectionInterval = 15; // (1.25 ms units)
+const int slaveLatency          = 0;
+const int supervisionTimeout    = 500; // (10 ms units)
+
+
+
+} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Aug 09 12:57:23 2016 +0000
@@ -0,0 +1,406 @@
+/*  
+ *  Copyright (c) 2016 Samuele Cornell  
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to deal
+ *  in the Software without restriction, including without limitation the rights
+ *  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in all
+ *  copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *  SOFTWARE.
+ *
+ */
+ 
+ /*
+ *   Thanks to Matthias Frick and his project blidino https://github.com/sieren/blidino 
+ *   which also uses RedBearslab nRF51822 and implements a USB-MIDI to BLE-MIDI bridge. 
+ *   His work made this possible and served as the main inspiration for this project . 
+ *   The content of BLEMIDI_MIDI_Parser.h file is for the most part taken from his blidino project.  
+ */
+
+#include "mbed.h"
+
+#include "ble/BLE.h"
+
+#include "BufferedSerial.h"
+
+#include "config.h"
+
+BufferedSerial UART(UART_TX_PIN,UART_RX_PIN,BUFSERIAL_LENGHT) ; //UART_RX_PIN,BUFSERIAL_LENGHT  
+
+#if ONLY_MIDI_to_BLEMIDI==0 
+
+#include "BLEMIDI_MIDI_Parser.h" 
+
+#endif
+
+#if ONLY_BLEMIDI_to_MIDI==0   
+
+#include "MIDI_BLEMIDI_Parser.h"
+
+#endif
+
+
+
+#define TXRX_BUF_LEN                    20 
+
+#define RX_BUF_LEN                      256 
+
+
+#if LIGHT_SHOW==1
+DigitalOut redled(RX_LED);  // sets the two LEDS on the MIDI Shield as outputs, these will be used as a visual feedback for debug 
+DigitalOut greenled(TX_LED); //
+#endif 
+
+
+/******************************************************************************************************************************
+*INITIALIZE VARIABLES, BUFFERS and BLE-MIDI Service and Characteristic
+******************************************************************************************************************************/
+
+Ticker sendBLEMIDI_Ticker ; 
+Ticker sendData_Ticker ; 
+ 
+Timer t; // timer used for BLE-MIDI timestamps 
+
+bool isConnected; 
+
+
+////////////////////////////////////////////
+bool sendBLEMIDI_flag = false ; 
+
+////////////
+
+
+BLEDevice ble; // BLE_API  
+
+static Gap::ConnectionParams_t connectionParams;
+
+
+// MIDI BLE Service and Characteristic UUID ( see Apple BLE-MIDI Spec. and Midi manufacter Association BLE-MIDI Spec.) 
+
+static const uint8_t service_uuid[] = {0x03, 0xB8, 0x0E, 0x5A, 0xED, 0xE8, 0x4B, 0x33, 0xA7, 0x51, 0x6C, 0xE3, 0x4E, 0xC4, 0xC7, 0};
+static const uint8_t characteristic_uuid[]   = {0x77, 0x72, 0xE5, 0xDB, 0x38, 0x68, 0x41, 0x12, 0xA1, 0xA9, 0xF2, 0x66, 0x9D, 0x10, 0x6B, 0xF3};
+
+static const uint8_t service_uuid_rev[] = {0, 0xC7, 0xC4, 0x4E, 0xE3, 0x6C, 0x51, 0xA7, 0x33, 0x4B, 0xE8, 0xED, 0x5A, 0x0E, 0xB8, 0x03};
+
+uint8_t txPayload[TXRX_BUF_LEN] = {0,};
+
+
+GattCharacteristic  midiCharacteristic(characteristic_uuid, txPayload, 0, 20,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
+                                                   GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE |
+                                                                   GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY |
+                                                                     GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
+
+GattCharacteristic *midiChars[] = {&midiCharacteristic};
+GattService BLEMIDIService(service_uuid, midiChars,sizeof(midiChars) / sizeof(GattCharacteristic *));
+ 
+ 
+                                
+/*********************************************************************************************************************
+MIDI to BLE-MIDI  
+*********************************************************************************************************************/
+
+                                
+#if ONLY_BLEMIDI_to_MIDI==0     
+               
+
+void sendBLEMIDI_Callback (void)
+{
+
+    sendBLEMIDI_flag = true ; 
+    
+    /**** This callback is called within an ISR with frequency set by the sendBLEMIDI_Ticker, because it is called in an Interrupt context it is preferably 
+    doing the MIDI to BLEMIDI task in the main, the callback only set a flag which would be checked in the main loop. 
+    This is because all the BLEMIDI to MIDI conversion is already performed within Interrupt context. ( thus as a consequence BLEMIDI to MIDI has higher priority )  
+    *****/
+}
+
+
+
+void sendBLEMIDI(void) 
+{
+
+ 
+// MIDI::MIDI_to_BLEMIDI_Parser() parses incoming MIDI events from the UART (see MIDI_BLEMIDI_Parser.h) 
+    if(isConnected == true && MIDI::MIDI_to_BLEMIDI_Parser()==true) {
+
+        // a valid MIDI message has been parsed from the UART buffer
+
+#if LIGHT_SHOW==1
+        greenled = !(greenled);
+#endif
+
+        uint8_t BLEmidi_out[SysExMaxSize] ;
+        uint8_t SysEx_Array_lenght ;
+
+        uint16_t ticks = t.read_us() & 0x1fff; // read timer for timestamps 
+
+        if(MIDI::mMessage.sysexArray[0] == MIDI::SystemExclusive)   { // message is  SysEx
+
+
+            SysEx_Array_lenght = MIDI::mMessage.getSysExSize() ; // get SysEx message lenght
+
+            uint8_t position = 0; // position for SysexArray 
+
+            // header
+           
+            BLEmidi_out[position++] = 0x80 | ((ticks >> 7) & 0x3f); // header & timestampHigh
+            BLEmidi_out[position++] = 0x80 | (ticks & 0x7f); // timestampLow
+
+            for (int i = 0; i < SysEx_Array_lenght; i++) {
+                if (i == SysEx_Array_lenght - 1) {
+                    // modify last byte
+                    BLEmidi_out[position++] = 0x80 | (ticks & 0x7f);
+
+                    if (position == 20) {
+                        
+                        
+                        ble.updateCharacteristicValue(midiCharacteristic.getValueAttribute().getHandle(), BLEmidi_out, 20);
+
+                        position = 0;
+                        // header
+                        BLEmidi_out[position++] = 0x80 | (ticks >> 7) & 0x3f;
+                    }
+                }
+                BLEmidi_out[position++] = MIDI::mMessage.sysexArray[i];
+                if (position == 20) {
+                  ble.updateCharacteristicValue(midiCharacteristic.getValueAttribute().getHandle(), BLEmidi_out, 20);
+                
+                    position = 0;
+                    // header
+                    BLEmidi_out[position++] = 0x80 | (ticks >> 7) & 0x3f;
+                }
+
+                ticks = t.read_us() & 0x1fff;
+            }
+
+            if (position > 0) {
+                // send remains
+             ble.updateCharacteristicValue(midiCharacteristic.getValueAttribute().getHandle(), BLEmidi_out, position);
+             
+            }
+            
+           
+            MIDI::mMessage.sysexArray[0]= 0 ; // reset
+
+        } 
+
+
+        // message is not SysEx
+        
+        
+        else {
+            
+            
+            if(MIDI::mMessage.data1 == 0 ) { // no data1 only status 
+            
+            BLEmidi_out[0] = 0x80 | ((ticks >> 7) & 0x3f);
+            BLEmidi_out[1] = 0x80 | (ticks & 0x7f);
+            BLEmidi_out[2] = MIDI::mMessage.channel+MIDI::mMessage.type;
+        
+             ble.updateCharacteristicValue(midiCharacteristic.getValueAttribute().getHandle(), BLEmidi_out , 3);
+            
+            }
+            
+            if(MIDI::mMessage.data2 == 0 ) { // no data2 
+            
+            BLEmidi_out[0] = 0x80 | ((ticks >> 7) & 0x3f);
+            BLEmidi_out[1] = 0x80 | (ticks & 0x7f);
+            BLEmidi_out[2] = MIDI::mMessage.channel+MIDI::mMessage.type;
+            BLEmidi_out[3] = MIDI::mMessage.data1 ;
+
+            ble.updateCharacteristicValue(midiCharacteristic.getValueAttribute().getHandle(), BLEmidi_out , 4);
+            
+            } 
+            
+            if(MIDI::mMessage.data2 != 0 ) { 
+            
+            BLEmidi_out[0] = 0x80 | ((ticks >> 7) & 0x3f);
+            BLEmidi_out[1] = 0x80 | (ticks & 0x7f);
+            BLEmidi_out[2] = MIDI::mMessage.channel+MIDI::mMessage.type;
+            BLEmidi_out[3] = MIDI::mMessage.data1 ;
+            BLEmidi_out[4] = MIDI::mMessage.data2 ;
+
+            ble.updateCharacteristicValue(midiCharacteristic.getValueAttribute().getHandle(), BLEmidi_out , 5);
+            
+            } 
+
+        }// end else
+
+    }// outer if
+
+// invalid message or not connected
+
+}
+
+#endif 
+
+
+/******************************************************************************************************************************
+* BLE CALLBACKS 
+******************************************************************************************************************************/
+ 
+                                
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) 
+{
+    //device disconnected 
+    
+    isConnected = false ; 
+    
+#if ONLY_BLEMIDI_to_MIDI==0   
+   sendBLEMIDI_Ticker.detach() ; // stop Ticker to save energy 
+#endif
+    
+    ble.startAdvertising(); // start advertising
+}
+
+
+void connectionCallback(const Gap::ConnectionCallbackParams_t* params) {
+
+
+isConnected=true ; 
+
+// try update conn.parameters 
+
+connectionParams.minConnectionInterval        = Config::minConnectionInterval;
+connectionParams.maxConnectionInterval        = Config::maxConnectionInterval;
+connectionParams.slaveLatency                 = Config::slaveLatency;
+connectionParams.connectionSupervisionTimeout = Config::supervisionTimeout;
+
+ble.updateConnectionParams(params->handle ,&connectionParams);
+
+
+//start timers here
+#if ONLY_BLEMIDI_to_MIDI==0    
+sendBLEMIDI_Ticker.attach( sendBLEMIDI_Callback, SENDBLEMIDI_INTERVAL); // every SENDBLEMIDI_INTERVAL seconds calls sendBLEMIDI_Callback (ISR)   
+
+t.start();  // start the timer used for BLEMIDI timestamps  
+
+#endif 
+
+} 
+
+
+/****************************************************************************************************************************
+BLE-MIDI to MIDI 
+****************************************************************************************************************************/
+
+
+#if ONLY_MIDI_to_BLEMIDI==0 
+
+void parseIncoming(uint8_t *buffer, uint16_t bytesRead) {  // parse BLE-MIDI Events that have been written on the MIDI Characteristic 
+  for (int i = 1; i < bytesRead; i++)
+  {
+    parseMidiEvent(buffer[0], buffer[i]); // parse and send through UART the MIDI Events received through BLE (see BLE_MIDI_Parser.h)
+  }
+}
+                                
+
+
+void onDataWritten(const GattWriteCallbackParams *Handler) // this functions is called within an ISR every time data has been written on nRF51822 GATT Server MIDI Characteristic   
+{
+
+#if LIGHT_SHOW==1
+    redled = !(redled) ;
+#endif
+
+    uint8_t buf[TXRX_BUF_LEN];
+    uint16_t bytesRead;
+    if (Handler->handle == midiCharacteristic.getValueAttribute().getHandle()) {
+        ble.readCharacteristicValue(midiCharacteristic.getValueAttribute().getHandle(),
+                                    buf, &bytesRead);
+        parseIncoming(buf, bytesRead);
+
+    }
+
+}
+  
+#endif  
+
+
+/**************************************
+MAIN 
+***************************************/
+
+int main(void)
+{
+
+
+#if LIGHT_SHOW==1
+    redled = 1;
+    greenled = 1;
+#endif
+
+
+
+    UART.baud(31250) ; // set UART baud rate to 31250 (MIDI standard)
+
+    ble.init();
+    ble.onDisconnection(disconnectionCallback);
+    ble.onConnection(connectionCallback) ;
+
+#if ONLY_MIDI_to_BLEMIDI==0
+    ble.onDataWritten(onDataWritten);
+#endif
+    
+    //conn. parameters ( rejected on iOS/OSX  see Apple BLE peripheral design guidelines but can work on Android ) 
+    
+    connectionParams.minConnectionInterval        = Config::minConnectionInterval;
+    connectionParams.maxConnectionInterval        = Config::maxConnectionInterval;
+    connectionParams.slaveLatency                 = Config::slaveLatency;
+    connectionParams.connectionSupervisionTimeout = Config::supervisionTimeout;
+    ble.setPreferredConnectionParams(&connectionParams);
+    ble.getPreferredConnectionParams(&connectionParams);
+    
+    
+    /* setup advertising */
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
+                                     (const uint8_t *)"nRF51", sizeof("nRF51") - 1);
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
+                                     (const uint8_t *)service_uuid_rev, sizeof(service_uuid_rev));
+
+    ble.accumulateScanResponse(GapAdvertisingData::SHORTENED_LOCAL_NAME,
+                               (const uint8_t *)"nRF51", sizeof("nRF51") - 1);
+    ble.accumulateScanResponse(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,(const uint8_t *)service_uuid_rev, sizeof(service_uuid_rev));
+    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+
+    /* 100ms; in multiples of 0.625ms. */
+    ble.setAdvertisingInterval(160);
+
+    // set adv_timeout, in seconds
+    ble.setAdvertisingTimeout(0);
+    ble.addService(BLEMIDIService);
+
+    //Set Device Name
+    ble.setDeviceName((const uint8_t *)"nRF51");
+
+    ble.startAdvertising();
+    
+  
+    while(1)   { //main loop
+
+#if ONLY_BLEMIDI_to_MIDI==0    
+            if(sendBLEMIDI_flag == true ) { // check if the flag is set 
+
+            sendBLEMIDI_flag=false ;
+            sendBLEMIDI() ; // parse MIDI Events from UART and send them over BLE
+
+        }
+#endif
+
+        ble.waitForEvent(); // sleep 
+
+    } // end main loop
+
+} // end main
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Aug 09 12:57:23 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/4f6c30876dfa
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF51822.lib	Tue Aug 09 12:57:23 2016 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#088f5738bf18