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!!!
main.cpp@2:c77c2b06d604, 2014-12-13 (annotated)
- Committer:
- prussell
- Date:
- Sat Dec 13 14:14:39 2014 +0000
- Revision:
- 2:c77c2b06d604
- Parent:
- 1:4a25d917fb6a
- Child:
- 3:a98203f84063
+UUID Tables from strings
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
prussell | 0:0217a862b047 | 1 | //=========Header (PR) |
prussell | 0:0217a862b047 | 2 | // blePRv04, Initial: 20141210 Paul Russell (mbed user: prussell = PR) |
prussell | 0:0217a862b047 | 3 | // This sample includes code from several projects found on http://developer.mbed.org, including but not limited to: |
prussell | 0:0217a862b047 | 4 | // - http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/ |
prussell | 0:0217a862b047 | 5 | // - https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_LoopbackUART/ |
prussell | 1:4a25d917fb6a | 6 | // - https://developer.mbed.org/users/takafuminaka/code/BLE_HTM_by_InTempSensr/ |
prussell | 0:0217a862b047 | 7 | // - miscellaneous adopted from more samples... |
prussell | 0:0217a862b047 | 8 | // Reference: |
prussell | 0:0217a862b047 | 9 | // - http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/ |
prussell | 0:0217a862b047 | 10 | // - Reference: http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/docs/tip/ |
prussell | 0:0217a862b047 | 11 | // - Reference: http://developer.mbed.org/teams/Bluetooth-Low-Energy/ |
prussell | 0:0217a862b047 | 12 | // Warnings: |
prussell | 0:0217a862b047 | 13 | // - As of 20141210 it is necessary to use Android App [nRF-Master Control Panel] to ensure any previous connected |
prussell | 0:0217a862b047 | 14 | // code on mkit is properly Disconnected before trying to connect other Android nRF Apps (nRFToolbox, nRF UART 2.0, etc.). |
prussell | 0:0217a862b047 | 15 | // As UART device doesn't offer disconnect you may need to load a 3rf sample, then connect, then discoonect, to clear the link. |
prussell | 0:0217a862b047 | 16 | // Notes: |
prussell | 0:0217a862b047 | 17 | // - onDataSent() maybe only occuring when confirmed receive by phone, as onDataSent() didn't happen when phone moved out of range. |
prussell | 0:0217a862b047 | 18 | // - onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range, OnTimeout didn't occur at all. |
prussell | 0:0217a862b047 | 19 | // ToDo: and ToCheck: |
prussell | 0:0217a862b047 | 20 | // - Re-check where voltatile needed |
prussell | 0:0217a862b047 | 21 | //==========End of PR's Header |
prussell | 0:0217a862b047 | 22 | |
prussell | 0:0217a862b047 | 23 | //==========Historic Licencing from original imported sample from mbed website [BLE_HeartRate] ========== |
prussell | 0:0217a862b047 | 24 | //From: http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/ |
prussell | 0:0217a862b047 | 25 | /* mbed Microcontroller Library |
prussell | 0:0217a862b047 | 26 | * Copyright (c) 2006-2013 ARM Limited |
prussell | 0:0217a862b047 | 27 | * |
prussell | 0:0217a862b047 | 28 | * Licensed under the Apache License, Version 2.0 (the "License"); |
prussell | 0:0217a862b047 | 29 | * you may not use this file except in compliance with the License. |
prussell | 0:0217a862b047 | 30 | * You may obtain a copy of the License at |
prussell | 0:0217a862b047 | 31 | * http://www.apache.org/licenses/LICENSE-2.0 |
prussell | 0:0217a862b047 | 32 | * Unless required by applicable law or agreed to in writing, software |
prussell | 0:0217a862b047 | 33 | * distributed under the License is distributed on an "AS IS" BASIS, |
prussell | 0:0217a862b047 | 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
prussell | 0:0217a862b047 | 35 | * See the License for the specific language governing permissions and |
prussell | 0:0217a862b047 | 36 | * limitations under the License. */ |
prussell | 0:0217a862b047 | 37 | //==========end of Historic Licencing ========== |
prussell | 0:0217a862b047 | 38 | |
prussell | 0:0217a862b047 | 39 | |
prussell | 0:0217a862b047 | 40 | //==========Compile Options========== |
prussell | 0:0217a862b047 | 41 | #define ENABLE_SerialUSB_DEBUG_CONSOLE 1 //PR: Enable Debug on mbed's USB Serial Debug, Setup: Serial 9600,8,N,1,NoFlowControl (TeraTerm: http://en.sourceforge.jp/projects/ttssh2/releases/) |
prussell | 0:0217a862b047 | 42 | #define UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL 0 //PR: Option to slow the connection intervsal possibly saving power (After Connected) |
prussell | 0:0217a862b047 | 43 | |
prussell | 0:0217a862b047 | 44 | //==========Includes========== |
prussell | 0:0217a862b047 | 45 | #include "mbed.h" |
prussell | 1:4a25d917fb6a | 46 | #include "BLEDevice.h" // BLE |
prussell | 1:4a25d917fb6a | 47 | #include "nrf_soc.h" // nRF Internal Temperature Sensor |
prussell | 0:0217a862b047 | 48 | |
prussell | 0:0217a862b047 | 49 | //Services |
prussell | 0:0217a862b047 | 50 | #include "BatteryService.h" |
prussell | 0:0217a862b047 | 51 | #include "DeviceInformationService.h" |
prussell | 0:0217a862b047 | 52 | //#include "DFUService" //TODO: DFU and FOTA Support |
prussell | 1:4a25d917fb6a | 53 | #include "HealthThermometerService.h" //TODO: Temperature, #include "ble_hts.h" |
prussell | 0:0217a862b047 | 54 | #include "HeartRateService.h" |
prussell | 0:0217a862b047 | 55 | //#include "UARTService.h" //TODO: Add a UART Channel for streaming data like logs? |
prussell | 0:0217a862b047 | 56 | |
prussell | 0:0217a862b047 | 57 | //==========Debug Console========== |
prussell | 0:0217a862b047 | 58 | #if ENABLE_SerialUSB_DEBUG_CONSOLE |
prussell | 0:0217a862b047 | 59 | Serial debug_serial(USBTX, USBRX); //PR: DebugSerialOverMbedUSB 9600-8N1N |
prussell | 0:0217a862b047 | 60 | #define DEBUG(...) { debug_serial.printf(__VA_ARGS__); } |
prussell | 0:0217a862b047 | 61 | #else |
prussell | 0:0217a862b047 | 62 | #define DEBUG(...) //Do Nothing |
prussell | 0:0217a862b047 | 63 | #endif |
prussell | 0:0217a862b047 | 64 | |
prussell | 2:c77c2b06d604 | 65 | //========== This Section is to Create Debug output showing variable prep before main() ========== |
prussell | 2:c77c2b06d604 | 66 | bool u8_prep_dummy(void) { |
prussell | 2:c77c2b06d604 | 67 | DEBUG("\n\nBLE: ____Prep Memory____\n"); |
prussell | 2:c77c2b06d604 | 68 | return true; |
prussell | 2:c77c2b06d604 | 69 | } |
prussell | 2:c77c2b06d604 | 70 | const bool bPrep = u8_prep_dummy(); |
prussell | 2:c77c2b06d604 | 71 | |
prussell | 0:0217a862b047 | 72 | //==========LEDs========== |
prussell | 0:0217a862b047 | 73 | //LEDs: |
prussell | 0:0217a862b047 | 74 | //DigitalOut out_led1(LED1); //PR: Firmware heartbeat |
prussell | 0:0217a862b047 | 75 | //DigitalOut out_led2(LED2); //PR: Firmware heartbeat |
prussell | 0:0217a862b047 | 76 | PwmOut pwm_led1(LED1); //PR: Firmware Life Indicator |
prussell | 0:0217a862b047 | 77 | PwmOut pwm_led2(LED2); //TODO: Controlled by App |
prussell | 0:0217a862b047 | 78 | float f_led1level = 0.0; //Initial Brightness (Typically 0.0~0.5) |
prussell | 0:0217a862b047 | 79 | float f_led2level = 0.0; //Initial Brightness (Typically 0.0~0.5) |
prussell | 0:0217a862b047 | 80 | |
prussell | 0:0217a862b047 | 81 | //==========BLE========== |
prussell | 0:0217a862b047 | 82 | BLEDevice ble; |
prussell | 0:0217a862b047 | 83 | 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? |
prussell | 0:0217a862b047 | 84 | static const uint16_t uuid16_list[] = { //Service List (Pre-defined standard 16bit services) |
prussell | 1:4a25d917fb6a | 85 | //BLE_UUID_GAP UUID_GENERIC_ACCESS //0x1800 //Included by Default, DeviceName, Appearance, PreferredConnectionParam |
prussell | 1:4a25d917fb6a | 86 | //BLE_UUID_GATT UUID_GENERIC ATTRIBUTE //0x1801 //Included by Default, ServiceChanged, |
prussell | 1:4a25d917fb6a | 87 | GattService::UUID_BATTERY_SERVICE, //0x180F //BatteryLevel |
prussell | 1:4a25d917fb6a | 88 | GattService::UUID_DEVICE_INFORMATION_SERVICE, //0x180A //sManufacturer, sModelNumber, sSerialNumber, sHWver, sFWver, sSWver |
prussell | 1:4a25d917fb6a | 89 | GattService::UUID_HEART_RATE_SERVICE, //0x180D //HRM, BodyLocation, ControlPoint |
prussell | 1:4a25d917fb6a | 90 | //GattService::UUID_HEALTH_THERMOMETER_SERVICE, //0x1809 //HTM |
prussell | 1:4a25d917fb6a | 91 | //x GattService::UUID_DFU, //0x1530 - See UARTServiceShortUUID in BLE_API:DFUService.cpp // |
prussell | 1:4a25d917fb6a | 92 | //x GattService::UARTService, //0x0001 - See DFUServiceShortUUID in BLE_API:UARTService.cpp // |
prussell | 1:4a25d917fb6a | 93 | //GattService::UUID_ALERT_NOTIFICATION_SERVICE, = 0x1811, |
prussell | 1:4a25d917fb6a | 94 | //GattService::UUID_CURRENT_TIME_SERVICE, = 0x1805, |
prussell | 1:4a25d917fb6a | 95 | //GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, = 0x1812, |
prussell | 1:4a25d917fb6a | 96 | //GattService::UUID_IMMEDIATE_ALERT_SERVICE, = 0x1802, |
prussell | 1:4a25d917fb6a | 97 | //GattService::UUID_LINK_LOSS_SERVICE, = 0x1803, |
prussell | 1:4a25d917fb6a | 98 | //GattService::UUID_PHONE_ALERT_STATUS_SERVICE, = 0x180E, |
prussell | 1:4a25d917fb6a | 99 | //GattService::UUID_REFERENCE_TIME_UPDATE_SERVICE, = 0x1806, |
prussell | 1:4a25d917fb6a | 100 | //GattService::UUID_SCAN_PARAMETERS_SERVICE, = 0x1813, |
prussell | 1:4a25d917fb6a | 101 | }; |
prussell | 1:4a25d917fb6a | 102 | |
prussell | 2:c77c2b06d604 | 103 | //========== Prep UUID list (before main()) ========== |
prussell | 2:c77c2b06d604 | 104 | // Gatt characteristic and service UUIDs - Readable to UUID |
prussell | 2:c77c2b06d604 | 105 | const UUID stringToUUID(const char* str) { |
prussell | 2:c77c2b06d604 | 106 | uint8_t array[16] = {0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55};//Prefill 'U' so fully specified even short string |
prussell | 2:c77c2b06d604 | 107 | for(int i = 0; i < strlen(str); i++) { //Don't convert unspecified bytes past end of string |
prussell | 2:c77c2b06d604 | 108 | array[i] = str[i]; |
prussell | 2:c77c2b06d604 | 109 | } |
prussell | 2:c77c2b06d604 | 110 | |
prussell | 2:c77c2b06d604 | 111 | DEBUG("UUID: Prep[%16s] --> [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x] %c\n", |
prussell | 2:c77c2b06d604 | 112 | str, array[0], array[1], array[2], array[3], array[4], array[5], array[6], array[7], |
prussell | 2:c77c2b06d604 | 113 | array[8], array[9], array[10],array[11],array[12],array[13],array[14],array[15], array[15] ); |
prussell | 2:c77c2b06d604 | 114 | |
prussell | 2:c77c2b06d604 | 115 | return UUID(array);//TODO: Check if this array is safe or stack temporary?? |
prussell | 2:c77c2b06d604 | 116 | } |
prussell | 2:c77c2b06d604 | 117 | //const UUID SCORING_GATT_SERVICE = stringToUUID("nod.score1.serv "); |
prussell | 2:c77c2b06d604 | 118 | //const UUID THRESHOLD_GATT_CHARACTERISTIC = stringToUUID("nod.score1.thres"); |
prussell | 2:c77c2b06d604 | 119 | //const UUID DIVISOR_GATT_CHARACTERISTIC = stringToUUID("nod.score1.div "); |
prussell | 2:c77c2b06d604 | 120 | //const UUID INTERVAL_US_GATT_CHARACTERISTIC = stringToUUID("nod.score1.intus"); |
prussell | 2:c77c2b06d604 | 121 | // Strings to hex UUID "0123456789ABCDEF" |
prussell | 2:c77c2b06d604 | 122 | const UUID UUID_GATT_SERVICE_A = stringToUUID("com.test.servA"); |
prussell | 2:c77c2b06d604 | 123 | const UUID UUID_GATT_CHARACTERISTIC_A1 = stringToUUID("com.test.charA1"); |
prussell | 2:c77c2b06d604 | 124 | const UUID UUID_GATT_CHARACTERISTIC_A2 = stringToUUID("com.test.charA2"); |
prussell | 2:c77c2b06d604 | 125 | const UUID UUID_GATT_CHARACTERISTIC_SHORT = stringToUUID("com.short"); |
prussell | 2:c77c2b06d604 | 126 | |
prussell | 1:4a25d917fb6a | 127 | //==========Internal Temperature========== |
prussell | 1:4a25d917fb6a | 128 | //Adopted From: https://developer.mbed.org/users/takafuminaka/code/BLE_HTM_by_InTempSensr/ |
prussell | 1:4a25d917fb6a | 129 | // Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml |
prussell | 1:4a25d917fb6a | 130 | // HTM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml |
prussell | 1:4a25d917fb6a | 131 | uint8_t thermTempPayload[5] = { 0, 0, 0, 0, 0 }; |
prussell | 1:4a25d917fb6a | 132 | GattCharacteristic tempChar (GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, |
prussell | 1:4a25d917fb6a | 133 | thermTempPayload, sizeof(thermTempPayload), sizeof(thermTempPayload), |
prussell | 1:4a25d917fb6a | 134 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE); |
prussell | 1:4a25d917fb6a | 135 | GattCharacteristic *htmChars[] = {&tempChar, }; |
prussell | 1:4a25d917fb6a | 136 | GattService htmService(GattService::UUID_HEALTH_THERMOMETER_SERVICE, htmChars, |
prussell | 1:4a25d917fb6a | 137 | sizeof(htmChars) / sizeof(GattCharacteristic *)); |
prussell | 1:4a25d917fb6a | 138 | |
prussell | 1:4a25d917fb6a | 139 | //==========Battery========== |
prussell | 1:4a25d917fb6a | 140 | //Adopted From: https://developer.mbed.org/users/takafuminaka/code/BLE_HTM_by_InTempSensr/ |
prussell | 1:4a25d917fb6a | 141 | ///int8_t batt = 98; /* Battery level */ |
prussell | 1:4a25d917fb6a | 142 | //uint8_t read_batt = 0; /* Variable to hold battery level reads */ |
prussell | 1:4a25d917fb6a | 143 | //static uint8_t bpm2[1] = {batt}; |
prussell | 1:4a25d917fb6a | 144 | //GattCharacteristic battLevel ( GattCharacteristic::UUID_BATTERY_LEVEL_CHAR, bpm2, sizeof(bpm2), sizeof(bpm2), |
prussell | 1:4a25d917fb6a | 145 | // GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | |
prussell | 1:4a25d917fb6a | 146 | // GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); |
prussell | 1:4a25d917fb6a | 147 | //GattCharacteristic *battChars[] = {&battLevel, }; |
prussell | 1:4a25d917fb6a | 148 | //GattService battService(GattService::UUID_BATTERY_SERVICE, battChars, sizeof(battChars) / sizeof(GattCharacteristic *)); |
prussell | 1:4a25d917fb6a | 149 | |
prussell | 0:0217a862b047 | 150 | |
prussell | 0:0217a862b047 | 151 | //==========Functions:Timer========== |
prussell | 0:0217a862b047 | 152 | static volatile bool b_Ticker1 = false;//Volatile, don't optimize, changes under interrupt control |
prussell | 0:0217a862b047 | 153 | void CallbackTicker1(void) |
prussell | 0:0217a862b047 | 154 | { |
prussell | 0:0217a862b047 | 155 | static uint32_t u32_Counter; // Counter for Debug Output |
prussell | 0:0217a862b047 | 156 | |
prussell | 0:0217a862b047 | 157 | //pwm_led1 = !pwm_led1; /* Do blinky on LED1 while we're waiting for BLE events */ |
prussell | 0:0217a862b047 | 158 | f_led1level+=0.1; if (f_led1level>0.5){f_led1level = 0.1;}; pwm_led1=f_led1level;//PR: Ramp Blink |
prussell | 0:0217a862b047 | 159 | DEBUG("\nBLEi: Ticker1(%u) ", ++u32_Counter); |
prussell | 0:0217a862b047 | 160 | b_Ticker1 = true; //PR: Flag to handle Ticker1 Event in Main loop so interupts not blocked. |
prussell | 0:0217a862b047 | 161 | } |
prussell | 0:0217a862b047 | 162 | |
prussell | 0:0217a862b047 | 163 | //==========Functions:BLE========== |
prussell | 0:0217a862b047 | 164 | void Callback_BLE_onTimeout(void) |
prussell | 0:0217a862b047 | 165 | { |
prussell | 0:0217a862b047 | 166 | DEBUG("\nBLEi: Callback_BLE_onTimeout()\n" ); |
prussell | 0:0217a862b047 | 167 | //PR: Haven't seen this, even when phone moved out of range and OnDisconnect(Reason0x08) occurs |
prussell | 0:0217a862b047 | 168 | |
prussell | 0:0217a862b047 | 169 | //DEBUG("\nBLE:Callback_BLE_onTimeout(), Restarting Advertising\n" ); |
prussell | 0:0217a862b047 | 170 | //ble.startAdvertising(); |
prussell | 0:0217a862b047 | 171 | } |
prussell | 0:0217a862b047 | 172 | |
prussell | 0:0217a862b047 | 173 | //void onDisconnection (Gap::DisconnectionEventCallback_t disconnectionCallback) |
prussell | 0:0217a862b047 | 174 | void Callback_BLE_onDisconnect(Gap::Handle_t tHandle, Gap::DisconnectionReason_t eReason) |
prussell | 0:0217a862b047 | 175 | { |
prussell | 0:0217a862b047 | 176 | //PR: onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range |
prussell | 0:0217a862b047 | 177 | |
prussell | 0:0217a862b047 | 178 | // REMOTE_USER_TERMINATED_CONNECTION = 0x13 = 19, |
prussell | 0:0217a862b047 | 179 | // LOCAL_HOST_TERMINATED_CONNECTION = 0x16 = 22, |
prussell | 0:0217a862b047 | 180 | // CONN_INTERVAL_UNACCEPTABLE = 0x3B = 59, |
prussell | 0:0217a862b047 | 181 | 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 |
prussell | 0:0217a862b047 | 182 | |
prussell | 0:0217a862b047 | 183 | //DEBUG("Wait10sec...\n");wait(10.0); //PR: Optional to test effect on advertising |
prussell | 0:0217a862b047 | 184 | ble.startAdvertising(); // restart advertising |
prussell | 0:0217a862b047 | 185 | } |
prussell | 0:0217a862b047 | 186 | |
prussell | 0:0217a862b047 | 187 | //inline void BLEDevice::onConnection(Gap::ConnectionEventCallback_t connectionCallback){ transport->getGap().setOnConnection(connectionCallback);} |
prussell | 0:0217a862b047 | 188 | void Callback_BLE_onConnect(Gap::Handle_t tHandle, Gap::addr_type_t ePeerAddrType, const Gap::address_t c6PeerAddr, const Gap::ConnectionParams_t *params) |
prussell | 0:0217a862b047 | 189 | { |
prussell | 0:0217a862b047 | 190 | DEBUG("\nBLEi: Callback_BLE_Connect(Handle:%d, eType:%d, Add:%u ...)\n", tHandle, ePeerAddrType, c6PeerAddr); |
prussell | 0:0217a862b047 | 191 | |
prussell | 0:0217a862b047 | 192 | #if UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL |
prussell | 0:0217a862b047 | 193 | /* Updating connection parameters can be attempted only after a connection has been |
prussell | 0:0217a862b047 | 194 | * established. Please note that the ble-Central is still the final arbiter for |
prussell | 0:0217a862b047 | 195 | * the effective parameters; the peripheral can only hope that the request is |
prussell | 0:0217a862b047 | 196 | * honored. Please also be mindful of the constraints that might be enforced by |
prussell | 0:0217a862b047 | 197 | * the BLE stack on the underlying controller.*/ |
prussell | 0:0217a862b047 | 198 | #define MIN_CONN_INTERVAL 250 /**< Minimum connection interval (250 ms) */ |
prussell | 0:0217a862b047 | 199 | #define MAX_CONN_INTERVAL 350 /**< Maximum connection interval (350 ms). */ |
prussell | 0:0217a862b047 | 200 | #define CONN_SUP_TIMEOUT 6000 /**< Connection supervisory timeout (6 seconds). */ |
prussell | 0:0217a862b047 | 201 | #define SLAVE_LATENCY 4 |
prussell | 0:0217a862b047 | 202 | |
prussell | 0:0217a862b047 | 203 | Gap::ConnectionParams_t tGap_conn_params; |
prussell | 0:0217a862b047 | 204 | tGap_conn_params.minConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MIN_CONN_INTERVAL); |
prussell | 0:0217a862b047 | 205 | tGap_conn_params.maxConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MAX_CONN_INTERVAL); |
prussell | 0:0217a862b047 | 206 | tGap_conn_params.connectionSupervisionTimeout = Gap::MSEC_TO_GAP_DURATION_UNITS(CONN_SUP_TIMEOUT); |
prussell | 0:0217a862b047 | 207 | tGap_conn_params.slaveLatency = SLAVE_LATENCY; |
prussell | 0:0217a862b047 | 208 | ble.updateConnectionParams(tHandle, &tGap_conn_params); |
prussell | 0:0217a862b047 | 209 | #endif /* #if UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL */ |
prussell | 0:0217a862b047 | 210 | } |
prussell | 0:0217a862b047 | 211 | |
prussell | 0:0217a862b047 | 212 | static volatile bool bSent = false; //Volatile, don't optimize, changes under interrupt control |
prussell | 0:0217a862b047 | 213 | static volatile unsigned uSentBLE; |
prussell | 0:0217a862b047 | 214 | void Callback_BLE_onDataSent(unsigned uSent){ |
prussell | 0:0217a862b047 | 215 | uSentBLE=uSent; |
prussell | 1:4a25d917fb6a | 216 | DEBUG("BLEi: SentI(%u)", uSent); //TODO: PR: Why uSent always "1", expected it to match sent bytes length |
prussell | 0:0217a862b047 | 217 | bSent = true; |
prussell | 0:0217a862b047 | 218 | //PR: onDataSent() maybe only occuring when confirmed receive by phone, as onDataSent() didn't happen when phone moved out of range. |
prussell | 0:0217a862b047 | 219 | } |
prussell | 0:0217a862b047 | 220 | |
prussell | 0:0217a862b047 | 221 | void Callback_BLE_onDataWritten(const GattCharacteristicWriteCBParams *pParams) |
prussell | 0:0217a862b047 | 222 | { |
prussell | 0:0217a862b047 | 223 | // Callback_BLE_onDataWritten == This does occur when use nRF-MCP to save New Heart Rate Control Point (Ignored if incorrect length) |
prussell | 0:0217a862b047 | 224 | |
prussell | 0:0217a862b047 | 225 | //Warning: *data may not be NULL terminated |
prussell | 0:0217a862b047 | 226 | 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); |
prussell | 0:0217a862b047 | 227 | } |
prussell | 0:0217a862b047 | 228 | |
prussell | 0:0217a862b047 | 229 | void Callback_BLE_onUpdatesEnabled(Gap::Handle_t tHandle) |
prussell | 0:0217a862b047 | 230 | { |
prussell | 0:0217a862b047 | 231 | DEBUG("\nBLEi: Callback_BLE_onUpdates(Handle:%d)\r\n", tHandle); |
prussell | 0:0217a862b047 | 232 | } |
prussell | 0:0217a862b047 | 233 | |
prussell | 0:0217a862b047 | 234 | //==========main========== |
prussell | 0:0217a862b047 | 235 | int main(void) |
prussell | 0:0217a862b047 | 236 | { |
prussell | 0:0217a862b047 | 237 | f_led1level = 1; pwm_led1 = f_led1level;//Start LED1=OnMax |
prussell | 0:0217a862b047 | 238 | f_led2level = 1; pwm_led2 = f_led2level;//Start LED2=OnMax |
prussell | 1:4a25d917fb6a | 239 | DEBUG("\nBLE: ___%s___\n", pcDeviceName); //Restart TeraTerm just before Pressing Reset on mbed |
prussell | 1:4a25d917fb6a | 240 | DEBUG("BLE: Connect App for Data: nRF-MCP, nRF-Toolbox:HRM, etc.\n"); |
prussell | 0:0217a862b047 | 241 | |
prussell | 0:0217a862b047 | 242 | Ticker ticker1; //PR: Timer Object(Structure) |
prussell | 0:0217a862b047 | 243 | //ticker1.attach(CallbackTicker1, 1.0); //PR: Timer Handler, Float=PeriodSeconds |
prussell | 0:0217a862b047 | 244 | ticker1.attach(CallbackTicker1, 2.0); //PR: Timer Handler, Float=PeriodSeconds |
prussell | 0:0217a862b047 | 245 | //ticker1.attach(CallbackTicker1, 5.0); //PR: Timer Handler, Float=PeriodSeconds |
prussell | 0:0217a862b047 | 246 | |
prussell | 0:0217a862b047 | 247 | //Initialize BLE Service (and event actions) |
prussell | 0:0217a862b047 | 248 | ble.init(); |
prussell | 0:0217a862b047 | 249 | ble.onDisconnection(Callback_BLE_onDisconnect); |
prussell | 0:0217a862b047 | 250 | ble.onConnection(Callback_BLE_onConnect); //PR: Not required if no actions enabled, enabled now just for debug printf() |
prussell | 0:0217a862b047 | 251 | ble.onDataSent(Callback_BLE_onDataSent); |
prussell | 0:0217a862b047 | 252 | ble.onDataWritten(Callback_BLE_onDataWritten); |
prussell | 0:0217a862b047 | 253 | ble.onTimeout(Callback_BLE_onTimeout); |
prussell | 0:0217a862b047 | 254 | ble.onUpdatesEnabled(Callback_BLE_onUpdatesEnabled); |
prussell | 0:0217a862b047 | 255 | |
prussell | 0:0217a862b047 | 256 | //ble_error_t readCharacteristicValue ( uint16_t handle, uint8_t *const buffer, uint16_t *const lengthP ) |
prussell | 0:0217a862b047 | 257 | //ble_error_t updateCharacteristicValue (uint16_t handle, const uint8_t *value, uint16_t size, bool localOnly=false) |
prussell | 0:0217a862b047 | 258 | |
prussell | 0:0217a862b047 | 259 | /* Setup primary service. */ |
prussell | 0:0217a862b047 | 260 | uint8_t u8LoopCounter = 100; |
prussell | 0:0217a862b047 | 261 | HeartRateService hrService(ble, u8LoopCounter, HeartRateService::LOCATION_FINGER); //Start the service for BLE:HRM |
prussell | 0:0217a862b047 | 262 | |
prussell | 0:0217a862b047 | 263 | /* Setup auxiliary services. */ |
prussell | 0:0217a862b047 | 264 | BatteryService battery(ble); //Start the service for BLE:Battery |
prussell | 0:0217a862b047 | 265 | DeviceInformationService deviceInfo(ble, "Maker", pcDeviceName, "sn1234", "hw00", "fw00", "sw00");//Start the service for BLE:DeviceInfo |
prussell | 0:0217a862b047 | 266 | // (BLEDevice), pcManufacturer, pcModelNumber, pcSerialNumber, pcHWver, pcFWver, pcSWver |
prussell | 0:0217a862b047 | 267 | |
prussell | 0:0217a862b047 | 268 | /* Setup advertising. */ |
prussell | 0:0217a862b047 | 269 | ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); //PR: Advertise 1sec (1Hz) |
prussell | 0:0217a862b047 | 270 | ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); //PR: TODO |
prussell | 0:0217a862b047 | 271 | ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); //PR: BLE Only, Options(LE_GENERAL_DISCOVERABLE/LE_LIMITED_DISCOVERABLE) |
prussell | 0:0217a862b047 | 272 | ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); //PR: Might need to change for Custom Services/Characteristics |
prussell | 0:0217a862b047 | 273 | ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);//PR: TODO: Change to: UNKNOWN or custom |
prussell | 0:0217a862b047 | 274 | ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)pcDeviceName, sizeof(pcDeviceName));//PR: Product? |
prussell | 0:0217a862b047 | 275 | ble.startAdvertising(); |
prussell | 0:0217a862b047 | 276 | |
prussell | 0:0217a862b047 | 277 | DEBUG("BLE: Main Loop\n"); |
prussell | 0:0217a862b047 | 278 | |
prussell | 0:0217a862b047 | 279 | uint32_t u32_wakeevents=0, u32_wakelast=0; // Counter&Register for tracking Wake Events (to see monitor their Frequency) |
prussell | 0:0217a862b047 | 280 | while (true) { |
prussell | 0:0217a862b047 | 281 | if (b_Ticker1 && ble.getGapState().connected) { //If Ticker1 and Connected Update Data |
prussell | 0:0217a862b047 | 282 | b_Ticker1 = false; // Clear flag for next Ticker1, see CallbackTicker1() |
prussell | 0:0217a862b047 | 283 | |
prussell | 0:0217a862b047 | 284 | /* Handle sensor polling == Simulate Data */ |
prussell | 0:0217a862b047 | 285 | u8LoopCounter++; |
prussell | 0:0217a862b047 | 286 | if (u8LoopCounter >= 175) { |
prussell | 0:0217a862b047 | 287 | u8LoopCounter = 100; |
prussell | 0:0217a862b047 | 288 | DEBUG("BLE: HRM Rollover175->100 ", u8LoopCounter); |
prussell | 0:0217a862b047 | 289 | } |
prussell | 0:0217a862b047 | 290 | DEBUG("BLE: HRM:%u, Wakes:%u Delta:%d ", u8LoopCounter, u32_wakeevents, u32_wakeevents-u32_wakelast); u32_wakelast=u32_wakeevents; |
prussell | 0:0217a862b047 | 291 | hrService.updateHeartRate(u8LoopCounter); |
prussell | 0:0217a862b047 | 292 | } else if (b_Ticker1) { |
prussell | 0:0217a862b047 | 293 | b_Ticker1 = false; // Clear flag for next Ticker1, see CallbackTicker1() |
prussell | 0:0217a862b047 | 294 | DEBUG("BLE: Tick while unconnected ", u8LoopCounter); |
prussell | 0:0217a862b047 | 295 | } else if (bSent){ |
prussell | 0:0217a862b047 | 296 | bSent=false; //clear flag |
prussell | 0:0217a862b047 | 297 | //DEBUG("BLE:Sent %ubytes ", uSentBLE); |
prussell | 0:0217a862b047 | 298 | } else { |
prussell | 0:0217a862b047 | 299 | //DEBUG("BLE:Wait for Event\n\r"); //x Debug output here causes unnecessary wakes resulting in endless awakes. |
prussell | 0:0217a862b047 | 300 | ble.waitForEvent(); //PR: Wait for event - Yield control to BLE Stack and other events (Process ALL pending events before waiting again) |
prussell | 0:0217a862b047 | 301 | f_led2level+=0.25; if (f_led2level>0.5){f_led2level = 0.0;}; pwm_led2=f_led2level;//PR: Ramp Blink |
prussell | 0:0217a862b047 | 302 | u32_wakeevents++; //PR: Count events for frequency monitoring (20141207PR: nRF51822 mbed HRM = 50Hz) |
prussell | 0:0217a862b047 | 303 | } |
prussell | 0:0217a862b047 | 304 | } |
prussell | 0:0217a862b047 | 305 | } |