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!!!
Diff: main.cpp
- 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 ==========