Experimental BLE project showing how IO can be made with an App over BLE. Pointer to matching App will be added when ready, initially this works with: - Android App [nRF-Master Control Panel], supports Write,Read,Notify - Android Project [BluetoothLeGatt]

Dependencies:   BLE_API mbed nRF51822

This is an experimental project for BLE (Bluetooth LE == Bluetooth Low Energy == Bluetooth Smart).

  • It supports general IO over BLE with Read/Notify/Write support.
  • It is compatible with FOTA using Android App "nRF Master Control Panel" (20150126)
  • IO supported by:
    • Custom Android App is in the WIKI under: Android-App, developed from Android Sample "BluetoothLeGatt"
    • Android App: nRF-MCP (Master Control Panel)
    • iOS App LightBlue.
    • General HRM, HTM, Battery and similar apps should be able to access the matching services.
  • It includes combinations of code from other projects, alternative code included can be tried by moving comments (, //)
  • 20150126 bleIO r25: It compiles for both "Nordic nRF51822" and "Nordic nRF51822 FOTA" platforms
  • 20150126 The matching bleIO App (in wiki) doesn't support FOTA yet, use Android App "nRF Master Control Panel"

Feedback and ideas greatly appreciated!!!

Revision:
23:78aad4e53ae2
Parent:
22:533275e76f55
Child:
25:1c6c2895f729
--- a/main.cpp	Sun Jan 11 20:01:40 2015 +0000
+++ b/main.cpp	Mon Jan 26 17:51:53 2015 +0000
@@ -8,7 +8,7 @@
 //    - https://developer.mbed.org/users/garimagupta002/notebook/ble-uart-lcd-demo/  (Advertise UUID16+UUID128)
 //    - http://developer.mbed.org/teams/UCL-IoT/code/BLE_LED_Controller/             (With matching Android App, uses BLE-UART)
 //    - https://developer.mbed.org/users/todotani/code/BLE_Health_Thermometer2-010/wiki/BLE_Health_Thermometer2-010 //Temperature handles
-//    - 
+//    - https://developer.mbed.org/users/rosterloh84/code/Buddi_Blueband (Disconnect Reasons)
 //    - miscellaneous adopted from more samples...
 // Reference:
 //    - nRF51822:
@@ -28,6 +28,7 @@
 // ToDo: and ToCheck:
 //    - Handle All return codes for all functions not void, including BLE not BLE_ERROR_NONE, as a minimum output some debug and log event in non-volatile memory for diagnostics.
 //    - Re-check where voltatile needed
+//    - ToCheck(Maybe in App): device.CreateBond(), device.SetPairingConfirmation(), gatt.refresh(to clear ble cache when changing services in devlopment)
 //    - Evaluate setting: IS_SRVC_CHANGED_CHARACT_PRESENT, see: https://devzone.nordicsemi.com/question/22751/nrftoobox-on-android-not-recognizing-changes-in-application-type-running-on-nordic-pcb/?answer=23097#post-id-23097
 //    - invalid or untested reference code commented with "//x ", feel free to delete or experiment
 //    - valid alternate code commented with "//a " prefix to indicate alternnative is valid code
@@ -90,8 +91,8 @@
 // Inputs: (Simultaneous DigitalIn and InteruptIn is OK)
 DigitalIn       bB1in(BUTTON1); //nRF51822p0.16==pin22 //if(bB1in){}
 DigitalIn       bB2in(BUTTON2); //nRF51822p0.17==pin25 //if(bB2in){}
-InterruptIn     B1int(BUTTON1); //nRF51822p0.18==pin26 //B1int.rise(&onB1rise);  
-InterruptIn     B2int(BUTTON2); //nRF51822p0.19==pin27 //B1int.fall(&onB1fall);
+InterruptIn     B1int(BUTTON1); //nRF51822p0.16==pin22 //B1int.rise(&onB1rise);  
+InterruptIn     B2int(BUTTON2); //nRF51822p0.17==pin25 //B1int.fall(&onB1fall);
 
 // Outputs:
 //a DigitalOut      bL1out(LED1);   // Direct LED1 drive
@@ -381,8 +382,7 @@
     ble.updateCharacteristicValue(IOr4.getValueHandle(), sIOr4.pu, sizeof(sIOr4)); // Update r4 data so ready for read (Doesn't Trigger Notify)
 }
 
-//PR: Notify: Doing Notify of Press and Release since n4 contains status of multiple inputs so need both bits to be correct. If Notify Characteristic is single button then notify could be on just press or just release.
-
+//PR: Notify: Doing Notify on both Press and Release since n4 contains status of multiple inputs so need both bits to be correct. If Notify Characteristic is single button then notify could be on just press or just release.
 void onB1press(void)        // B1 Press == *Notify*
 {   // Update Characteristics that include this button
     uB1press++;             // Flag/Count Events (allows detect any missed processing)
@@ -424,15 +424,26 @@
 void Callback_BLE_onDisconnect(Gap::Handle_t tHandle, Gap::DisconnectionReason_t eReason)
 {   //PR: onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range
 
+
     //   REMOTE_USER_TERMINATED_CONNECTION = 0x13 = 19,
     //   LOCAL_HOST_TERMINATED_CONNECTION  = 0x16 = 22,
     //   CONN_INTERVAL_UNACCEPTABLE        = 0x3B = 59,
-    DEBUG("\nBLEi: Callback_BLE_Disconnect(Handle:%d, eReason:0x%02x), Restarting Advertising\n",tHandle,eReason );//PR: Occurs properly when click disconnect in App nRFToolbox:HRM
+    DEBUG("\nBLEi: Callback_BLE_Disconnect(Handle:%d, eReason:0x%02x=", tHandle, eReason );//PR: Occurs properly when click disconnect in App nRFToolbox:HRM
+    switch(eReason) {
+        case Gap::REMOTE_USER_TERMINATED_CONNECTION: DEBUG("REMOTE_USER_TERMINATED_CONNECTION"); break;
+        case Gap::CONN_INTERVAL_UNACCEPTABLE:        DEBUG("CONN_INTERVAL_UNACCEPTABLE"); break;
+        case Gap::LOCAL_HOST_TERMINATED_CONNECTION:  DEBUG("LOCAL_HOST_TERMINATED_CONNECTION"); break;
+        default:                                     DEBUG("UNKNOWN"); break;
+    }    
+    DEBUG("), Restarting Advertising\n", tHandle, eReason );//PR: Occurs properly when click disconnect in App nRFToolbox:HRM
 
     //DEBUG("Wait10sec...\n");wait(10.0); //PR: Optional to test effect on advertising
     ble.startAdvertising(); // restart advertising
+
+    //TODO: LED Mode to Indicate Advertising until something else changes LED Mode?
 }
 
+
 void Callback_BLE_onConnect(Gap::Handle_t tHandle, Gap::addr_type_t ePeerAddrType, const Gap::address_t c6PeerAddr, const Gap::ConnectionParams_t *params)
 {
     DEBUG("\nBLEi: Callback_BLE_Connect(Handle:%d, eType:%d, Add:%u ...)\n", tHandle, ePeerAddrType, c6PeerAddr);
@@ -456,6 +467,26 @@
     //x #endif // #if UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL
 }
 
+#ifdef NOT_DEFINED
+void Callback_BLE_onDataRead(const GattCharacteristicReadAuthCBParams *pParams) //NotAvailableOnlineYet20150114 
+{
+    GattAttribute::Handle_t tHandle=pParams->charHandle;
+    
+    //Handle Changes to Service Characteristics:
+    if(!ble.getGapState().connected){ //Ensure BLE still connected
+        DEBUG("BLEi: Callback_BLE_onDataRead() while disconnected!!");
+    } else if (tHandle == IOr4.getValueHandle()) {     // IOr4 Characteristic?
+        DEBUG("BLEi: Callback_BLE_onDataRead() while disconnected!!");
+        vFillIO(); // Update the data for this Characteristic
+        vShowIO();          
+    //} else if (tHandle == IOw8.getValueHandle()) { // Writeonly, Continue with no changes, App can read back whatever was last written
+    //} else if (tHandle == IOr4.getValueHandle()) { // Notifyonly, shouldn't occur, is automatically sent when Notify changes, anything needed should be in IOr4
+    } else {
+        DEBUG("\n  Unknown onRead(tHandle:%d)\n\n", tHandle);
+    }  
+}
+#endif 
+
 static volatile bool bNotifySent = false; //Volatile, don't optimize, changes under interrupt control
 static volatile unsigned uNotifyBLE;
 void Callback_BLE_onNotifySent(unsigned uNotify)    //TODO: Consider renaming to onNotifySent(uNotified)
@@ -468,6 +499,7 @@
 void Callback_BLE_onDataWritten(const GattCharacteristicWriteCBParams *pParams)
 {   // This occurs when use nRF-MCP to save a new Characteristic Value (SingleUpASrrowIcon) such as New Heart Rate Control Point (unsent if incorrect length)
     GattAttribute::Handle_t tHandle=pParams->charHandle;
+    uint16_t uLen; 
 
     //Warning: *data may not be NULL terminated
     DEBUG("\nBLEi: Callback_BLE_onDataWritten(Handle:%d, eOp:%d, uOffset:%u uLen:%u Data0[0x%02x]=Data[%*s]\n", tHandle, pParams->op, pParams->offset, pParams->len, (char)(pParams->data[0]), pParams->len, pParams->data);
@@ -492,39 +524,25 @@
     //Handle Changes to Service Characteristics:
     if(!ble.getGapState().connected){ //Ensure BLE still connected
         DEBUG("BLEi: Callback_BLE_onDataWritten() while disconnected!!");
+    } else if (tHandle == IOw8.getValueHandle()) {     // This occurs from Write by App nRF-MCP since has Write Property set
+        ble.readCharacteristicValue(tHandle, sIOw8.pu, &uLen); //Update Characteristic with new information (Option: Verify length or a checksum first)
+        vShowIO();
+        bAppControl = true; //Host has taken control of LEDs
+        fL1level = (((float)sIOw8.s.L1pwm100)/100.0); if(fL1level>1.0){fL1level=1.0;}; fL1pwm=fL1level; //Set LED1 Level
+        fL2level = (((float)sIOw8.s.L2pwm255)/255.0); if(fL2level>1.0){fL2level=1.0;}; fL2pwm=fL2level; //Set LED1 Level
+        DEBUG("  L1:%d==%f  L2:%d==%f\n", sIOw8.s.L1pwm100, fL1level, sIOw8.s.L2pwm255, fL2level);
+        //TODO: Update Outputs and settings (Includes flags for: Factory Reset, Enter Test Mode, Enter Demo Mode)
+    
+    //} else if (tHandle == LinkLossHandle) {        // TODO: Handle LinkLoss Changes
+        //x pServiceLinkLoss->setAlertLevel( AlertLevel_t  newLevel )  
+        //x Can be Triggered by MCP or BluetoothLEGatt sample changing Linkloss setting:
+        //x Alert=1:  Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x01]=Data[])
+        //x Alert=2:  Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x02]=Data[])
+    //} else if (tHandle == IOr4.getValueHandle()) { // Readonly, shouldn't occur
+    //} else if (tHandle == IOn4.getValueHandle()) { // Notifyonly, shouldn't occur
     } else {
-        uint16_t uLen; 
-        if (tHandle == IOw8.getValueHandle()) {     // This occurs from Write by App nRF-MCP since has Write Property set
-            ble.readCharacteristicValue(tHandle, sIOw8.pu, &uLen); //Update Characteristic with new information (Option: Verify length or a checksum first)
-            vShowIO();
-            
-            bAppControl = true; //Host has taken control of LEDs
-            fL1level = (((float)sIOw8.s.L1pwm100)/100.0); if(fL1level>1.0){fL1level=1.0;}; fL1pwm=fL1level; //Set LED1 Level
-            fL2level = (((float)sIOw8.s.L2pwm255)/255.0); if(fL2level>1.0){fL2level=1.0;}; fL2pwm=fL2level; //Set LED1 Level
-            DEBUG("  L1:%d==%f  L2:%d==%f\n", sIOw8.s.L1pwm100, fL1level, sIOw8.s.L2pwm255, fL2level);
-
-            //TODO: Update Outputs and settings: Direct LED Control or Output Control, Or Configuration (Includes flags for: Factory Reset, Enter Test Mode, Enter Demo Mode)
-
-        //} else if (tHandle == IOr4.getValueHandle()) { // Readonly, shouldn't occur
-        //    ble.readCharacteristicValue(tHandle, pIOr4, &uLen);
-        //    DEBUG("  IOr4[%d]:%02X %02X %02X %02X\n", uLen, pIOr4[0], pIOr4[1], pIOr4[2], pIOr4[3]);
-        //    //TODO: Update Outputs
-        //} else if (tHandle == IOn4.getValueHandle()) { // Readonly, shouldn't occur
-        //    ble.readCharacteristicValue(tHandle, pIOn4, &uLen);
-        //    DEBUG("  IOn4[%d]:%02X %02X %02X %02X\n", uLen, pIOn4[0], pIOn4[1], pIOn4[2], pIOn4[3]);
-        //    //TODO: Update Outputs
-        } else {
-            DEBUG("\n  Unknown onWrite(tHandle:%d)\n\n", tHandle);
-        }
+        DEBUG("\n  Unknown onWrite(tHandle:%d)\n\n", tHandle);
     }
-
-    //LinkLoss:
-    //x pServiceLinkLoss->setAlertLevel( AlertLevel_t  newLevel )  
-    //x Triggered by BluetoothLEGatt sample changing Linkloss setting:
-    //x Alert=1:  Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x01]=Data[])
-    //x Alert=2:  Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x02]=Data[])
-
-    //vShowIO(); //Show IO Characteristic Status
 }
 
 void Callback_BLE_onUpdatesEnabled(Gap::Handle_t tHandle) // Notifications
@@ -662,7 +680,7 @@
     ble.onUpdatesEnabled(Callback_BLE_onUpdatesEnabled);//PR: Occurs when host enables notify on a Characteristic that has Notify property set
     ble.onUpdatesDisabled(Callback_BLE_onUpdatesDisabled);    //TODO:
     ble.onConfirmationReceived(Callback_BLE_onConfirmRx);     //TODO:
-    //ble.setReadAuthorizationCallback(Callback_BLE_onDataRead) //TODO: Test new callback "setReadAuthorizationCallback()", then can read sensors live instead of polling them continuously.   
+    //NotAvailableOnlineYet20150114 ble.setReadAuthorizationCallback(Callback_BLE_onDataRead);//TODO: Test new callback "setReadAuthorizationCallback()", then can read sensors live instead of polling them continuously.   
     
     //BLE2: Setup Services (with their initial values and options)
     DEBUG("BLE: Setup Services\n");
@@ -758,3 +776,5 @@
     }
 }
 //========== end of main.cpp ==========
+
+