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:
8:f187ba55aed2
Parent:
7:1097d012b01a
Child:
9:2d11beda333f
--- a/main.cpp	Sun Dec 14 20:35:15 2014 +0000
+++ b/main.cpp	Tue Dec 16 16:44:56 2014 +0000
@@ -18,7 +18,10 @@
 //    - onDataSent() maybe only occuring when confirmed receive by phone, as onDataSent() didn't happen when phone moved out of range.
 //    - onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range, OnTimeout didn't occur at all.
 // 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
+//    - 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
+//
 //==========End of PR's Header
 
 //==========Historic Licencing from original imported sample from mbed website [BLE_HeartRate] ==========
@@ -50,10 +53,10 @@
 //Services
 #include "BatteryService.h"
 #include "DeviceInformationService.h"
-//#include "DFUService"                 //TODO: DFU and FOTA Support
 #include "HealthThermometerService.h"   
 #include "HeartRateService.h"
 #include "LinkLossService.h"            //TODO: How support this?
+//#include "DFUService"                 //TODO: DFU and FOTA Support
 //#include "UARTService.h"              //TODO: Add a UART Channel for streaming data like logs?
 
 //==========Debug Console==========
@@ -83,8 +86,18 @@
 float       f_led2level = 0.0;          //Initial Brightness (Typically 0.0~0.5)
 
 //==========BLE==========
+const static char     pcDeviceName[]    = "blePRv04"; //PR: Why can App nRF-MCP modify this even though flagged as Const, maybe only temporary mod till App restarts?
 BLEDevice   ble;
-const static char     pcDeviceName[]    = "blePRv04"; //PR: Why can App nRF-MCP modify this even though flagged as Const, maybe only temporary mod till App restarts?
+    HealthThermometerService    *pServiceHTM; 
+    BatteryService              *pServiceBattery;
+    HeartRateService            *pServiceHRM;
+    DeviceInformationService    *pServiceDeviceInfo;
+    LinkLossService             *pServiceLinkLoss;
+    //UARTService               *pServiceUART;
+        //pServiceUART->getTXCharacteristicHandle();
+        //pServiceUART->getRXCharacteristicHandle();
+        //ble.updateCharacteristicValue(pServiceUART->getRXCharacteristicHandle(), pData, uLen); // Tx to App
+
 
 //==========UUID==========
 //UUID16 List - Advertising these required by App nRF-Toolbox:HRM&HTM 
@@ -250,6 +263,38 @@
 
     //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", pParams->charHandle, pParams->op, pParams->offset, pParams->len, (char)(pParams->data[0]), pParams->len, pParams->data);
+
+    //Triggered by BluetoothLEGatt sample changing Linkloss setting:
+    //Alert=1:  Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x01]=Data[]
+    //Alert=2:  Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x02]=Data[]
+
+/* From mbed project BLE_LoopbackUART:
+    if ((uartServicePtr != NULL) && (params->charHandle == uartServicePtr->getTXCharacteristicHandle())) {
+        uint16_t bytesRead = params->len;
+        DEBUG("received %u bytes\n\r", bytesRead);
+        ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(), params->data, bytesRead);
+    }
+*/
+    //if(ble.getGapState().connected){ //Ensure BLE still connected
+      //  if(params->charHandle == ble.getTXCharacteristicHandle())
+//            htmService.updateTemperature( update_htm() );
+//            hrmService.updateHeartRate( update_hrm() );
+//            battService.updateBatteryLevel( update_batt() );
+
+
+ /*   switch(pParams->op){
+        case GATTS_CHAR_OP_INVALID:
+        GATTS_CHAR_OP_WRITE_REQ  
+        GATTS_CHAR_OP_WRITE_CMD
+        GATTS_CHAR_OP_SIGN_WRITE_CMD         //< Signed Write Command
+        GATTS_CHAR_OP_PREP_WRITE_REQ         //< Prepare Write Request
+        GATTS_CHAR_OP_EXEC_WRITE_REQ_CANCEL  //< Execute Write Request: Cancel all prepared writes
+        GATTS_CHAR_OP_EXEC_WRITE_REQ_NOW     //< Execute Write Request: Immediately execute all prepared writes
+    }
+*/
+
+
+
 }
 
 void Callback_BLE_onUpdatesEnabled(Gap::Handle_t tHandle)
@@ -262,7 +307,54 @@
 {
     printf("\nBLEi: Link loss alert[%d]\n", level);
 }
+//==========HRM==========
+//Adopted 2014Dec from http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/
+uint8_t update_hrm(void)//(bool bInit)
+{
+    static uint8_t u8_hrm = 100;
+    u8_hrm++;
+    if (u8_hrm >= 175) {
+        u8_hrm = 100;
+        DEBUG("BLE: HRM Rollover175->100 ");
+    }
+    DEBUG("[HRM:%d]", u8_hrm);   
+    pServiceHRM->updateHeartRate( u8_hrm );// Update Characteristic so sent by BLE
+    return(u8_hrm);
+}
+//==========HTM:Internal Temperature==========
+//Adopted 2014Dec from: https://developer.mbed.org/users/takafuminaka/code/BLE_HTM_by_InTempSensr/
+// Service:  https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml
+// HTM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml
 
+//****Although nRF-MCP displays float OK, the HTM Apps don't, its possible IEEE format required like in the original code:BLE_HTM_by_InTempSensr 
+float update_htm(void)
+{
+    //static float fTemperature = 0;//-123.456;
+    int32_t i32_temp;
+    sd_temp_get(&i32_temp);   //Read the nRF Internal Temperature (Die in 0.25'C steps, Counting From TBD), TODO:Check Scaling
+    float fTemperature = (float(i32_temp)/4.0) - 16.0;   // Scale&Shift (0.25'C from -16'C?)
+
+    //{//Force to IEEE format to match needs of Apps like nRF-HTM and nRF-Toolbox:HTM
+    // PR: Didn't work 20141213, might need 5byte style from BLE_HTM_by_InTempSensr if this is really necessary. OK in nRF-MCP for now.
+    //    uint8_t  exponent = 0xFE; //exponent is -2
+    //    uint32_t mantissa = (uint32_t)(fTemperature*100);
+    //    uint32_t temp_ieee11073 = ((((uint32_t)exponent) << 24) | (mantissa)); //Note: Assumes Mantissa within 24bits
+    //    memcpy(((uint8_t*)&fTemperature)+1, (uint8_t*)&temp_ieee11073, 4); //Overwrite with IEEE format float
+    //}
+
+    pServiceHTM->updateTemperature( fTemperature );// Update Characteristic so sent by BLE
+    DEBUG("[HTMi:%d HTMf:%f]", i32_temp, fTemperature);
+    return(fTemperature);
+}
+//==========Battery==========
+uint8_t update_batt(void)
+{
+    static uint8_t u8_BattPercent=33; //Level: 0..100% 
+    u8_BattPercent <= 50 ? u8_BattPercent=100 : u8_BattPercent--; // Simulate Battery Decay
+    pServiceBattery->updateBatteryLevel( u8_BattPercent ); // Update Characteristic so sent by BLE
+    DEBUG("[BATT:%d%%]", u8_BattPercent);
+    return(u8_BattPercent);
+}
 //==========main==========
 int main(void)
 {
@@ -271,7 +363,10 @@
 
     //Restart TeraTerm just before Pressing Reset on mbed, 9600-8N1(No Flow Control)
     DEBUG("\nBLE: ___%s___\n", pcDeviceName); 
-    DEBUG("BLE: Connect App for Data: nRF-MCP, nRF-Toolbox:HRM, etc.\n");
+    DEBUG("BLE: Connect App for Data: nRF-MCP, nRF-Toolbox:HRM/HTM, Android Sample BluetoothLeGatt, etc.\n");
+    DEBUG("BLE: BluetoothLeGatt: App->mbed: LinkLoss->AlertLevel(UpArrow)\n"); 
+    DEBUG("BLE: BluetoothLeGatt: App->mbed: BatteryService->BatteryLevel(DownArrow)\n"); 
+    DEBUG("BLE: BluetoothLeGatt: mbed->App: BatteryService->BatteryLevel->EnableNotify(ThreeDownArrows), Also App Acks the send=DEBUG('SentI')\n"); 
 
     Ticker ticker1;                             //PR: Timer Object(Structure)
     ticker1.attach(CallbackTicker1, 2.0);       //PR: Timer Handler, Float=PeriodSeconds
@@ -285,6 +380,14 @@
     ble.onDataWritten(Callback_BLE_onDataWritten);
     ble.onTimeout(Callback_BLE_onTimeout);
     ble.onUpdatesEnabled(Callback_BLE_onUpdatesEnabled);
+    
+    DEBUG("BLE: Handles:\n");
+    //DEBUG(" Service: BLE: %d\n", ble.getHandle());
+    //DEBUG(" Characteristic:BattLevel: %d\n", batteryLevelCharacteristic.getValueAttribute().getHandle());
+    //DFUService
+
+    
+    
 
 //ble_error_t readCharacteristicValue  ( uint16_t  handle,    uint8_t *const  buffer,    uint16_t *const  lengthP  ) 
 //ble_error_t  updateCharacteristicValue (uint16_t handle, const uint8_t *value, uint16_t size, bool localOnly=false) 
@@ -293,11 +396,18 @@
     //BLE2: Setup Services (with their initial values and options)
     DEBUG("BLE: Setup Services\n");
     // *Order here affects order in nRF-MCP Discovery of Services
-    HealthThermometerService    htmService(ble, 33.3, HealthThermometerService::LOCATION_EAR); 
-    BatteryService              battService(ble, 10);
-    HeartRateService            hrmService(ble, (uint8_t)111, HeartRateService::LOCATION_FINGER);
-    DeviceInformationService    deviceInfo(ble, "Maker", pcDeviceName, "sn1234", "hw00", "fw00", "sw00");//(BLEDevice), pcManufacturer, pcModelNumber, pcSerialNumber, pcHWver, pcFWver, pcSWver
-    LinkLossService             linkLoss(ble, Callback_BLE_onLinkLoss, LinkLossService::HIGH_ALERT); //New20141213, TBD
+    DeviceInformationService    ServiceDeviceInfo(ble, "Maker", pcDeviceName, "sn1234", "hw00", "fw00", "sw00");//(BLEDevice), pcManufacturer, pcModelNumber, pcSerialNumber, pcHWver, pcFWver, pcSWver
+        pServiceDeviceInfo      = &ServiceDeviceInfo; DEBUG("   Handle Service DeviceInfo:%d\n", ServiceDeviceInfo);
+    LinkLossService             ServiceLinkLoss(ble, Callback_BLE_onLinkLoss, LinkLossService::HIGH_ALERT); //New20141213, TBD
+        pServiceLinkLoss        = &ServiceLinkLoss;
+    BatteryService              ServiceBattery(ble, 10);
+        pServiceBattery         = &ServiceBattery;
+    HeartRateService            ServiceHRM(ble, (uint8_t)111, HeartRateService::LOCATION_FINGER);
+        pServiceHRM             = &ServiceHRM;
+    HealthThermometerService    ServiceHTM(ble, 33.3, HealthThermometerService::LOCATION_EAR); 
+        pServiceHTM             = &ServiceHTM;
+    //UARTService               ServiceUART(ble);
+    //  pServiceUART            = &ServiceUART;
 
     //BLE3: Setup advertising
     // Note the Advertising payload is limited to 31bytes, so careful don't overflow this. Multiple UUID16's or a single UUID128 are possible in advertising.
@@ -345,15 +455,12 @@
   
             // Read Sensors, and update matching Service Characteristics (only if connected)
             // *Order here doesn't affect order in nRF-MCP Discovery of Services
-            float   update_htm(void); //prototype
-            uint8_t update_hrm(void); //prototype
-            uint8_t update_batt(void);//prototype
             //TBD: Maybe save power by not Tx unless enabled by App?
-            // The Services are discovered if they were setup/started (They don't need update to be discovered)
-            htmService.updateTemperature( update_htm() );
-            hrmService.updateHeartRate( update_hrm() );
-            battService.updateBatteryLevel( update_batt() );
-            
+            // The Services are discovered if they were setup/started (They don't need update to be discovered)        
+            update_htm();
+            update_hrm();
+            update_batt();
+
             DEBUG("BLE: Wakes:%u Delta:%d ", u32_wakeevents, u32_wakeevents-u32_wakelast); //For Evaluating Timing
             u32_wakelast = u32_wakeevents;           
         } else if (b_Ticker1) {
@@ -370,50 +477,4 @@
         }
     }
 }
-
-//==========HRM==========
-//Adopted 2014Dec from http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/
-uint8_t update_hrm(void)//(bool bInit)
-{
-    static uint8_t u8_hrm = 100;
-    u8_hrm++;
-    if (u8_hrm >= 175) {
-        u8_hrm = 100;
-        DEBUG("BLE: HRM Rollover175->100 ");
-    }
-    DEBUG("[HRM:%d]", u8_hrm);   
-    return(u8_hrm);
-}
-//==========HTM:Internal Temperature==========
-//Adopted 2014Dec from: https://developer.mbed.org/users/takafuminaka/code/BLE_HTM_by_InTempSensr/
-// Service:  https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml
-// HTM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml
-
-//****Although nRF-MCP displays float OK, the HTM Apps don't, its possible IEEE format required like in the original code:BLE_HTM_by_InTempSensr 
-float update_htm(void)
-{
-    //static float fTemperature = 0;//-123.456;
-    int32_t i32_temp;
-    sd_temp_get(&i32_temp);   //Read the nRF Internal Temperature (Die in 0.25'C steps, Counting From TBD), TODO:Check Scaling
-    float fTemperature = (float(i32_temp)/4.0) - 16.0;   // Scale&Shift (0.25'C from -16'C?)
-    DEBUG("[HTMi:%d HTMf:%f]", i32_temp, fTemperature);
-
-    //{//Force to IEEE format to match needs of Apps like nRF-HTM and nRF-Toolbox:HTM
-    // PR: Didn't work 20141213, might need more of style from BLE_HTM_by_InTempSensr if this is really necessary. OK in nRF-MCP for now.
-    //    uint8_t  exponent = 0xFE; //exponent is -2
-    //    uint32_t mantissa = (uint32_t)(fTemperature*100);
-    //    uint32_t temp_ieee11073 = ((((uint32_t)exponent) << 24) | (mantissa)); //Note: Assumes Mantissa within 24bits
-    //    memcpy(((uint8_t*)&fTemperature)+1, (uint8_t*)&temp_ieee11073, 4); //Overwrite with IEEE format float
-    //}
-
-    return(fTemperature);
-}
-//==========Battery==========
-uint8_t update_batt(void)
-{
-    static uint8_t u8_BattPercent=33; //Level: 0..100% 
-    u8_BattPercent <= 50 ? u8_BattPercent=100 : u8_BattPercent--; // Simulate Battery Decay
-    DEBUG("[BATT:%d%%]", u8_BattPercent);
-    return(u8_BattPercent);
-}
 //========== end ==========