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@8:f187ba55aed2, 2014-12-16 (annotated)
- Committer:
- prussell
- Date:
- Tue Dec 16 16:44:56 2014 +0000
- Revision:
- 8:f187ba55aed2
- Parent:
- 7:1097d012b01a
- Child:
- 9:2d11beda333f
Changed Services to Handles, Updated Debug, OK.
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 | 6:5b6fb35b4450 | 7 | // - https://developer.mbed.org/users/garimagupta002/notebook/ble-uart-lcd-demo/ (Advertise UUID16+UUID128) |
prussell | 0:0217a862b047 | 8 | // - miscellaneous adopted from more samples... |
prussell | 0:0217a862b047 | 9 | // Reference: |
prussell | 0:0217a862b047 | 10 | // - http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/ |
prussell | 0:0217a862b047 | 11 | // - Reference: http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/docs/tip/ |
prussell | 0:0217a862b047 | 12 | // - Reference: http://developer.mbed.org/teams/Bluetooth-Low-Energy/ |
prussell | 0:0217a862b047 | 13 | // Warnings: |
prussell | 0:0217a862b047 | 14 | // - As of 20141210 it is necessary to use Android App [nRF-Master Control Panel] to ensure any previous connected |
prussell | 0:0217a862b047 | 15 | // code on mkit is properly Disconnected before trying to connect other Android nRF Apps (nRFToolbox, nRF UART 2.0, etc.). |
prussell | 0:0217a862b047 | 16 | // 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 | 17 | // Notes: |
prussell | 0:0217a862b047 | 18 | // - onDataSent() maybe only occuring when confirmed receive by phone, as onDataSent() didn't happen when phone moved out of range. |
prussell | 0:0217a862b047 | 19 | // - onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range, OnTimeout didn't occur at all. |
prussell | 0:0217a862b047 | 20 | // ToDo: and ToCheck: |
prussell | 8:f187ba55aed2 | 21 | // - 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. |
prussell | 0:0217a862b047 | 22 | // - Re-check where voltatile needed |
prussell | 8:f187ba55aed2 | 23 | // - 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 |
prussell | 8:f187ba55aed2 | 24 | // |
prussell | 0:0217a862b047 | 25 | //==========End of PR's Header |
prussell | 0:0217a862b047 | 26 | |
prussell | 0:0217a862b047 | 27 | //==========Historic Licencing from original imported sample from mbed website [BLE_HeartRate] ========== |
prussell | 0:0217a862b047 | 28 | //From: http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/ |
prussell | 0:0217a862b047 | 29 | /* mbed Microcontroller Library |
prussell | 0:0217a862b047 | 30 | * Copyright (c) 2006-2013 ARM Limited |
prussell | 0:0217a862b047 | 31 | * |
prussell | 0:0217a862b047 | 32 | * Licensed under the Apache License, Version 2.0 (the "License"); |
prussell | 0:0217a862b047 | 33 | * you may not use this file except in compliance with the License. |
prussell | 0:0217a862b047 | 34 | * You may obtain a copy of the License at |
prussell | 0:0217a862b047 | 35 | * http://www.apache.org/licenses/LICENSE-2.0 |
prussell | 0:0217a862b047 | 36 | * Unless required by applicable law or agreed to in writing, software |
prussell | 0:0217a862b047 | 37 | * distributed under the License is distributed on an "AS IS" BASIS, |
prussell | 0:0217a862b047 | 38 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
prussell | 0:0217a862b047 | 39 | * See the License for the specific language governing permissions and |
prussell | 0:0217a862b047 | 40 | * limitations under the License. */ |
prussell | 0:0217a862b047 | 41 | //==========end of Historic Licencing ========== |
prussell | 0:0217a862b047 | 42 | |
prussell | 0:0217a862b047 | 43 | |
prussell | 0:0217a862b047 | 44 | //==========Compile Options========== |
prussell | 0:0217a862b047 | 45 | #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 | 46 | #define UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL 0 //PR: Option to slow the connection intervsal possibly saving power (After Connected) |
prussell | 0:0217a862b047 | 47 | |
prussell | 0:0217a862b047 | 48 | //==========Includes========== |
prussell | 0:0217a862b047 | 49 | #include "mbed.h" |
prussell | 1:4a25d917fb6a | 50 | #include "BLEDevice.h" // BLE |
prussell | 1:4a25d917fb6a | 51 | #include "nrf_soc.h" // nRF Internal Temperature Sensor |
prussell | 0:0217a862b047 | 52 | |
prussell | 0:0217a862b047 | 53 | //Services |
prussell | 0:0217a862b047 | 54 | #include "BatteryService.h" |
prussell | 0:0217a862b047 | 55 | #include "DeviceInformationService.h" |
prussell | 5:d36bbb315e31 | 56 | #include "HealthThermometerService.h" |
prussell | 0:0217a862b047 | 57 | #include "HeartRateService.h" |
prussell | 5:d36bbb315e31 | 58 | #include "LinkLossService.h" //TODO: How support this? |
prussell | 8:f187ba55aed2 | 59 | //#include "DFUService" //TODO: DFU and FOTA Support |
prussell | 0:0217a862b047 | 60 | //#include "UARTService.h" //TODO: Add a UART Channel for streaming data like logs? |
prussell | 0:0217a862b047 | 61 | |
prussell | 0:0217a862b047 | 62 | //==========Debug Console========== |
prussell | 0:0217a862b047 | 63 | #if ENABLE_SerialUSB_DEBUG_CONSOLE |
prussell | 6:5b6fb35b4450 | 64 | //Restart TeraTerm just before Pressing Reset on mbed, Default:9600-8N1(No Flow Control) |
prussell | 6:5b6fb35b4450 | 65 | //Using default baud rate to avoid issues with DEBUG in a constructor being at wrong baud rate before main() |
prussell | 6:5b6fb35b4450 | 66 | Serial debug_serial(USBTX, USBRX); //PR: DebugSerialOverMbedUSB |
prussell | 0:0217a862b047 | 67 | #define DEBUG(...) { debug_serial.printf(__VA_ARGS__); } |
prussell | 0:0217a862b047 | 68 | #else |
prussell | 6:5b6fb35b4450 | 69 | #define DEBUG(...) //Do Nothing, DEBUG() lines are ignored |
prussell | 0:0217a862b047 | 70 | #endif |
prussell | 0:0217a862b047 | 71 | |
prussell | 2:c77c2b06d604 | 72 | //========== This Section is to Create Debug output showing variable prep before main() ========== |
prussell | 2:c77c2b06d604 | 73 | bool u8_prep_dummy(void) { |
prussell | 6:5b6fb35b4450 | 74 | DEBUG("\n\nBLE: ____Prep Memory____\n"); //May comment this out if none of the following Objects/Classes call initiator functions with debug |
prussell | 2:c77c2b06d604 | 75 | return true; |
prussell | 2:c77c2b06d604 | 76 | } |
prussell | 2:c77c2b06d604 | 77 | const bool bPrep = u8_prep_dummy(); |
prussell | 2:c77c2b06d604 | 78 | |
prussell | 0:0217a862b047 | 79 | //==========LEDs========== |
prussell | 0:0217a862b047 | 80 | //LEDs: |
prussell | 0:0217a862b047 | 81 | //DigitalOut out_led1(LED1); //PR: Firmware heartbeat |
prussell | 0:0217a862b047 | 82 | //DigitalOut out_led2(LED2); //PR: Firmware heartbeat |
prussell | 0:0217a862b047 | 83 | PwmOut pwm_led1(LED1); //PR: Firmware Life Indicator |
prussell | 0:0217a862b047 | 84 | PwmOut pwm_led2(LED2); //TODO: Controlled by App |
prussell | 0:0217a862b047 | 85 | float f_led1level = 0.0; //Initial Brightness (Typically 0.0~0.5) |
prussell | 0:0217a862b047 | 86 | float f_led2level = 0.0; //Initial Brightness (Typically 0.0~0.5) |
prussell | 0:0217a862b047 | 87 | |
prussell | 0:0217a862b047 | 88 | //==========BLE========== |
prussell | 8:f187ba55aed2 | 89 | 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 | 90 | BLEDevice ble; |
prussell | 8:f187ba55aed2 | 91 | HealthThermometerService *pServiceHTM; |
prussell | 8:f187ba55aed2 | 92 | BatteryService *pServiceBattery; |
prussell | 8:f187ba55aed2 | 93 | HeartRateService *pServiceHRM; |
prussell | 8:f187ba55aed2 | 94 | DeviceInformationService *pServiceDeviceInfo; |
prussell | 8:f187ba55aed2 | 95 | LinkLossService *pServiceLinkLoss; |
prussell | 8:f187ba55aed2 | 96 | //UARTService *pServiceUART; |
prussell | 8:f187ba55aed2 | 97 | //pServiceUART->getTXCharacteristicHandle(); |
prussell | 8:f187ba55aed2 | 98 | //pServiceUART->getRXCharacteristicHandle(); |
prussell | 8:f187ba55aed2 | 99 | //ble.updateCharacteristicValue(pServiceUART->getRXCharacteristicHandle(), pData, uLen); // Tx to App |
prussell | 8:f187ba55aed2 | 100 | |
prussell | 3:a98203f84063 | 101 | |
prussell | 6:5b6fb35b4450 | 102 | //==========UUID========== |
prussell | 6:5b6fb35b4450 | 103 | //UUID16 List - Advertising these required by App nRF-Toolbox:HRM&HTM |
prussell | 6:5b6fb35b4450 | 104 | // Keep list short so advertizing not too long. |
prussell | 0:0217a862b047 | 105 | static const uint16_t uuid16_list[] = { //Service List (Pre-defined standard 16bit services) |
prussell | 4:976394791d7a | 106 | // *Order here doesn't affect order in nRF-MCP Discovery of Services |
prussell | 1:4a25d917fb6a | 107 | //BLE_UUID_GAP UUID_GENERIC_ACCESS //0x1800 //Included by Default, DeviceName, Appearance, PreferredConnectionParam |
prussell | 1:4a25d917fb6a | 108 | //BLE_UUID_GATT UUID_GENERIC ATTRIBUTE //0x1801 //Included by Default, ServiceChanged, |
prussell | 3:a98203f84063 | 109 | GattService::UUID_HEALTH_THERMOMETER_SERVICE, //0x1809 //HTM (Might need to be first for nRF App) |
prussell | 1:4a25d917fb6a | 110 | GattService::UUID_HEART_RATE_SERVICE, //0x180D //HRM, BodyLocation, ControlPoint |
prussell | 7:1097d012b01a | 111 | GattService::UUID_DEVICE_INFORMATION_SERVICE, //0x180A //sManufacturer, sModelNumber, sSerialNumber, sHWver, sFWver, sSWver |
prussell | 7:1097d012b01a | 112 | GattService::UUID_BATTERY_SERVICE, //0x180F //BatteryLevel |
prussell | 7:1097d012b01a | 113 | GattService::UUID_LINK_LOSS_SERVICE, //0x1803 //LinkLoss |
prussell | 6:5b6fb35b4450 | 114 | |
prussell | 1:4a25d917fb6a | 115 | //x GattService::UUID_DFU, //0x1530 - See UARTServiceShortUUID in BLE_API:DFUService.cpp // |
prussell | 5:d36bbb315e31 | 116 | //x GattService::UARTService, //0x0001~0x0003 - See DFUServiceShortUUID in BLE_API:UARTService.cpp // |
prussell | 1:4a25d917fb6a | 117 | //GattService::UUID_ALERT_NOTIFICATION_SERVICE, = 0x1811, |
prussell | 1:4a25d917fb6a | 118 | //GattService::UUID_CURRENT_TIME_SERVICE, = 0x1805, |
prussell | 1:4a25d917fb6a | 119 | //GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, = 0x1812, |
prussell | 6:5b6fb35b4450 | 120 | //GattService::UUID_IMMEDIATE_ALERT_SERVICE, = 0x1802, |
prussell | 1:4a25d917fb6a | 121 | //GattService::UUID_PHONE_ALERT_STATUS_SERVICE, = 0x180E, |
prussell | 1:4a25d917fb6a | 122 | //GattService::UUID_REFERENCE_TIME_UPDATE_SERVICE, = 0x1806, |
prussell | 1:4a25d917fb6a | 123 | //GattService::UUID_SCAN_PARAMETERS_SERVICE, = 0x1813, |
prussell | 5:d36bbb315e31 | 124 | }; |
prussell | 5:d36bbb315e31 | 125 | |
prussell | 6:5b6fb35b4450 | 126 | //UUID128 List(Only a single UUID128 can fit in advertising) |
prussell | 6:5b6fb35b4450 | 127 | uint8_t puUUID128_Bluetooth_Base_Rev[16] = {0xFB,0x34,0x9B,0x5F,0x80,0, 0,0x80, 0,0x10, 0,0, 0x00,0x00, 0,0};//0000****-0000-1000-8000 00805F9B34FB, Base for UUID16 |
prussell | 6:5b6fb35b4450 | 128 | uint8_t puUUID128_BatteryService[16] = {0xFB,0x34,0x9B,0x5F,0x80,0, 0,0x80, 0,0x10, 0,0, 0x0F,0x18, 0,0};//0000****-0000-1000-8000 00805F9B34FB, ***=0x180F |
prussell | 5:d36bbb315e31 | 129 | |
prussell | 5:d36bbb315e31 | 130 | |
prussell | 6:5b6fb35b4450 | 131 | /* //Adopted from sample code in header of BLE_API:UUID.cpp |
prussell | 6:5b6fb35b4450 | 132 | // // Create a UUID16 (0x180F) |
prussell | 6:5b6fb35b4450 | 133 | // uint8_t shortID[16] = { 0, 0, 0x0F, 0x18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
prussell | 6:5b6fb35b4450 | 134 | // UUID ble_uuid = UUID(shortID); // Will have: ble_uuid.type = UUID_TYPE_SHORT, ble_uuid.value = 0x180F |
prussell | 6:5b6fb35b4450 | 135 | // // Create a UUID128 |
prussell | 6:5b6fb35b4450 | 136 | // uint8_t longID[16] = { 0x00,0x11,0x22,0x33, 0x44,0x55,0x66,0x77, 0x88,0x99,0xAA,0xBB, 0xCC,0xDD,0xEE,0xFF }; |
prussell | 6:5b6fb35b4450 | 137 | // UUID custom_uuid = UUID(longID);// Will have: custom_uuid.type=UUID_TYPE_LONG, custom_uuid.value=0x3322, custom_uuid.base=00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF |
prussell | 6:5b6fb35b4450 | 138 | */ |
prussell | 5:d36bbb315e31 | 139 | |
prussell | 6:5b6fb35b4450 | 140 | /* // The Nordic UART Service |
prussell | 5:d36bbb315e31 | 141 | //static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E}; |
prussell | 5:d36bbb315e31 | 142 | //static const uint8_t uart_tx_uuid[] = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E}; |
prussell | 5:d36bbb315e31 | 143 | //static const uint8_t uart_rx_uuid[] = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E}; |
prussell | 6:5b6fb35b4450 | 144 | //static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};// = flip uart_base_uuid[] |
prussell | 6:5b6fb35b4450 | 145 | //const uint16_t UUID16_UART_Serv = 0x0001; |
prussell | 6:5b6fb35b4450 | 146 | //const uint16_t UUID16_UART_Tx = 0x0002; |
prussell | 6:5b6fb35b4450 | 147 | //const uint16_t UUID16_UART_Rx = 0x0003; |
prussell | 6:5b6fb35b4450 | 148 | //const uint8_t UUID128_UART_Serv[LENGTH_OF_LONG_UUID]={0x6E,0x40,(uint8_t)(UUID16_UART_Serv>>8),(uint8_t)(UUID16_UART_Serv&0xFF),0xB5,0xA3,0xF3,0x93,0xE0,0xA9,0xE5,0x0E,0x24,0xDC,0xCA,0x9E}; |
prussell | 6:5b6fb35b4450 | 149 | //const uint8_t UUID128_UART_Rev[LENGTH_OF_LONG_UUID]={0x9E,0xCA,0xDC,0x24,0x0E,0xE5,0xA9,0xE0,0x93,0xF3,0xA3,0xB5,(uint8_t)(UUID16_UART_Serv&0xFF),(uint8_t)(UUID16_UART_Serv>>8),0x40,0x6E};//Use with: INCOMPLETE_LIST_128BIT_SERVICE_IDS |
prussell | 6:5b6fb35b4450 | 150 | */ |
prussell | 1:4a25d917fb6a | 151 | |
prussell | 6:5b6fb35b4450 | 152 | //UUID Info: |
prussell | 5:d36bbb315e31 | 153 | // 20141213 From https://developer.bluetooth.org/community/lists/community%20discussion/flat.aspx?rootfolder=/community/lists/community+discussion/16+bit+uuid+vs.+128+uuid&folderctid=0x01200200e2f0e56e3d53004dba96bdf0c357551f |
prussell | 5:d36bbb315e31 | 154 | // 16bit UUID reserved 128bit base = 32 hex digits: 0000****-0000-1000-8000 00805F9B34FB (Careful to use unsigned to avoid negatives and overflows) |
prussell | 5:d36bbb315e31 | 155 | // 32bit UUID reserved 128bit base = 32 hex digits: ********-0000-1000-8000 00805F9B34FB (Careful to use unsigned to avoid negatives and overflows) |
prussell | 5:d36bbb315e31 | 156 | /* All the custom GATT based services and characteristics must use a 128 bit UUID. |
prussell | 5:d36bbb315e31 | 157 | The Bluetooth_Base_UUID is: 00000000-0000-1000-8000 00805F9B34FB. |
prussell | 5:d36bbb315e31 | 158 | All the 16-bit Attribute UUIDs defined in the adopted specifications use the above base. |
prussell | 5:d36bbb315e31 | 159 | Generating a 128 bit UUID for custom profiles: For the 128 bit UUID, please refer to The ITU-T Rec. X.667. |
prussell | 5:d36bbb315e31 | 160 | You can download a free copy of ITU-T Rec. X.667 from http://www.itu.int/ITU-T/studygroups/com17/oid/X.667-E.pdf. |
prussell | 5:d36bbb315e31 | 161 | In addition if you go to http://www.itu.int/ITU-T/asn1/uuid.html, you can generate a unique 128-bit UUID. |
prussell | 5:d36bbb315e31 | 162 | Latency: Refer to Core Spec V4.0, Vol 3, Part F - 3.3.1, which is "Ready by Type Request". |
prussell | 5:d36bbb315e31 | 163 | If you look at the PDU, you have to send 2 bytes UUID for adopted profiles and 16 bytes UUID for custom profiles. |
prussell | 5:d36bbb315e31 | 164 | There is additional 14 extra bytes over head for the custom profiles for "Ready By Type Request Method" |
prussell | 5:d36bbb315e31 | 165 | Note: All attribute types are effectively compared as 128-bit UUIDs, even if a 16-bit UUID is provided in this request or defined for an attribute. (See Section 3.2.1.) |
prussell | 5:d36bbb315e31 | 166 | A suggestive alternative will be to use a notification method, (see 3.4.7.1), where you don't need the 128 bit UUID or the indication method (see 3.4.7.2) |
prussell | 5:d36bbb315e31 | 167 | */ |
prussell | 4:976394791d7a | 168 | |
prussell | 6:5b6fb35b4450 | 169 | //========== UUID128 from readable strings based on URL (processed before main()) ========== |
prussell | 6:5b6fb35b4450 | 170 | // UUID for released product may need to be properly generated, but for testing this can be convenient |
prussell | 6:5b6fb35b4450 | 171 | // Adopted 20141214 from Nordic PUCK |
prussell | 6:5b6fb35b4450 | 172 | uint8_t* puStrToUUID128(const char* pStr) { |
prussell | 6:5b6fb35b4450 | 173 | static uint8_t pUUID[LENGTH_OF_LONG_UUID]; //Call only once before using |
prussell | 6:5b6fb35b4450 | 174 | for(int i = 0; i < LENGTH_OF_LONG_UUID; i++) { |
prussell | 6:5b6fb35b4450 | 175 | if( i < strlen(pStr) ){ pUUID[LENGTH_OF_LONG_UUID-i-1] = pStr[i];} |
prussell | 6:5b6fb35b4450 | 176 | else { pUUID[LENGTH_OF_LONG_UUID-i-1] =' '; } //Pad end with space character (Or your choice of character such as 'u' or 'x' or NULL) |
prussell | 6:5b6fb35b4450 | 177 | } |
prussell | 6:5b6fb35b4450 | 178 | // (UUID128 byte order to match that displayed by App nRF-MCP) |
prussell | 6:5b6fb35b4450 | 179 | DEBUG("UUID: Prep[%-16s] --> [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n", |
prussell | 6:5b6fb35b4450 | 180 | pStr, pUUID[15],pUUID[14],pUUID[13],pUUID[12], pUUID[11],pUUID[10],pUUID[ 9],pUUID[ 8], |
prussell | 6:5b6fb35b4450 | 181 | pUUID[ 7],pUUID[ 6],pUUID[ 5],pUUID[ 4], pUUID[ 3],pUUID[ 2],pUUID[ 1],pUUID[ 0] ); |
prussell | 6:5b6fb35b4450 | 182 | return pUUID; //Pointer to prepared UUID128 |
prussell | 2:c77c2b06d604 | 183 | } |
prussell | 6:5b6fb35b4450 | 184 | // Strings to UUID128, test url: www.none.com: "0123456789ABCDEF" (16chars=32HexDigits=32nibbles) |
prussell | 6:5b6fb35b4450 | 185 | //const char pc_com_none_servA[] = "com.none.servA";// Provide a short URL you own (in reverse to match Android naming style) |
prussell | 6:5b6fb35b4450 | 186 | //const char pc_com_none_charA1[] = "com.none.charA1"; |
prussell | 6:5b6fb35b4450 | 187 | //const char pc_com_none_charA2[] = "com.none.charA2"; |
prussell | 2:c77c2b06d604 | 188 | |
prussell | 0:0217a862b047 | 189 | //==========Functions:Timer========== |
prussell | 0:0217a862b047 | 190 | static volatile bool b_Ticker1 = false;//Volatile, don't optimize, changes under interrupt control |
prussell | 0:0217a862b047 | 191 | void CallbackTicker1(void) |
prussell | 0:0217a862b047 | 192 | { |
prussell | 0:0217a862b047 | 193 | static uint32_t u32_Counter; // Counter for Debug Output |
prussell | 0:0217a862b047 | 194 | |
prussell | 0:0217a862b047 | 195 | //pwm_led1 = !pwm_led1; /* Do blinky on LED1 while we're waiting for BLE events */ |
prussell | 0:0217a862b047 | 196 | f_led1level+=0.1; if (f_led1level>0.5){f_led1level = 0.1;}; pwm_led1=f_led1level;//PR: Ramp Blink |
prussell | 0:0217a862b047 | 197 | DEBUG("\nBLEi: Ticker1(%u) ", ++u32_Counter); |
prussell | 0:0217a862b047 | 198 | b_Ticker1 = true; //PR: Flag to handle Ticker1 Event in Main loop so interupts not blocked. |
prussell | 0:0217a862b047 | 199 | } |
prussell | 0:0217a862b047 | 200 | |
prussell | 0:0217a862b047 | 201 | //==========Functions:BLE========== |
prussell | 0:0217a862b047 | 202 | void Callback_BLE_onTimeout(void) |
prussell | 0:0217a862b047 | 203 | { |
prussell | 0:0217a862b047 | 204 | DEBUG("\nBLEi: Callback_BLE_onTimeout()\n" ); |
prussell | 0:0217a862b047 | 205 | //PR: Haven't seen this, even when phone moved out of range and OnDisconnect(Reason0x08) occurs |
prussell | 0:0217a862b047 | 206 | |
prussell | 0:0217a862b047 | 207 | //DEBUG("\nBLE:Callback_BLE_onTimeout(), Restarting Advertising\n" ); |
prussell | 0:0217a862b047 | 208 | //ble.startAdvertising(); |
prussell | 0:0217a862b047 | 209 | } |
prussell | 0:0217a862b047 | 210 | |
prussell | 0:0217a862b047 | 211 | //void onDisconnection (Gap::DisconnectionEventCallback_t disconnectionCallback) |
prussell | 0:0217a862b047 | 212 | void Callback_BLE_onDisconnect(Gap::Handle_t tHandle, Gap::DisconnectionReason_t eReason) |
prussell | 0:0217a862b047 | 213 | { |
prussell | 0:0217a862b047 | 214 | //PR: onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range |
prussell | 0:0217a862b047 | 215 | |
prussell | 0:0217a862b047 | 216 | // REMOTE_USER_TERMINATED_CONNECTION = 0x13 = 19, |
prussell | 0:0217a862b047 | 217 | // LOCAL_HOST_TERMINATED_CONNECTION = 0x16 = 22, |
prussell | 0:0217a862b047 | 218 | // CONN_INTERVAL_UNACCEPTABLE = 0x3B = 59, |
prussell | 0:0217a862b047 | 219 | 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 | 220 | |
prussell | 0:0217a862b047 | 221 | //DEBUG("Wait10sec...\n");wait(10.0); //PR: Optional to test effect on advertising |
prussell | 0:0217a862b047 | 222 | ble.startAdvertising(); // restart advertising |
prussell | 0:0217a862b047 | 223 | } |
prussell | 0:0217a862b047 | 224 | |
prussell | 0:0217a862b047 | 225 | //inline void BLEDevice::onConnection(Gap::ConnectionEventCallback_t connectionCallback){ transport->getGap().setOnConnection(connectionCallback);} |
prussell | 0:0217a862b047 | 226 | 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 | 227 | { |
prussell | 0:0217a862b047 | 228 | DEBUG("\nBLEi: Callback_BLE_Connect(Handle:%d, eType:%d, Add:%u ...)\n", tHandle, ePeerAddrType, c6PeerAddr); |
prussell | 0:0217a862b047 | 229 | |
prussell | 0:0217a862b047 | 230 | #if UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL |
prussell | 0:0217a862b047 | 231 | /* Updating connection parameters can be attempted only after a connection has been |
prussell | 0:0217a862b047 | 232 | * established. Please note that the ble-Central is still the final arbiter for |
prussell | 0:0217a862b047 | 233 | * the effective parameters; the peripheral can only hope that the request is |
prussell | 0:0217a862b047 | 234 | * honored. Please also be mindful of the constraints that might be enforced by |
prussell | 0:0217a862b047 | 235 | * the BLE stack on the underlying controller.*/ |
prussell | 0:0217a862b047 | 236 | #define MIN_CONN_INTERVAL 250 /**< Minimum connection interval (250 ms) */ |
prussell | 0:0217a862b047 | 237 | #define MAX_CONN_INTERVAL 350 /**< Maximum connection interval (350 ms). */ |
prussell | 0:0217a862b047 | 238 | #define CONN_SUP_TIMEOUT 6000 /**< Connection supervisory timeout (6 seconds). */ |
prussell | 0:0217a862b047 | 239 | #define SLAVE_LATENCY 4 |
prussell | 0:0217a862b047 | 240 | |
prussell | 0:0217a862b047 | 241 | Gap::ConnectionParams_t tGap_conn_params; |
prussell | 0:0217a862b047 | 242 | tGap_conn_params.minConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MIN_CONN_INTERVAL); |
prussell | 0:0217a862b047 | 243 | tGap_conn_params.maxConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MAX_CONN_INTERVAL); |
prussell | 0:0217a862b047 | 244 | tGap_conn_params.connectionSupervisionTimeout = Gap::MSEC_TO_GAP_DURATION_UNITS(CONN_SUP_TIMEOUT); |
prussell | 0:0217a862b047 | 245 | tGap_conn_params.slaveLatency = SLAVE_LATENCY; |
prussell | 0:0217a862b047 | 246 | ble.updateConnectionParams(tHandle, &tGap_conn_params); |
prussell | 0:0217a862b047 | 247 | #endif /* #if UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL */ |
prussell | 0:0217a862b047 | 248 | } |
prussell | 0:0217a862b047 | 249 | |
prussell | 0:0217a862b047 | 250 | static volatile bool bSent = false; //Volatile, don't optimize, changes under interrupt control |
prussell | 0:0217a862b047 | 251 | static volatile unsigned uSentBLE; |
prussell | 0:0217a862b047 | 252 | void Callback_BLE_onDataSent(unsigned uSent){ |
prussell | 0:0217a862b047 | 253 | uSentBLE=uSent; |
prussell | 1:4a25d917fb6a | 254 | DEBUG("BLEi: SentI(%u)", uSent); //TODO: PR: Why uSent always "1", expected it to match sent bytes length |
prussell | 0:0217a862b047 | 255 | bSent = true; |
prussell | 5:d36bbb315e31 | 256 | //PR: App nRF-MCP doesn't cause onDataSent(), while App nRF-ToolBox:HRM does cause onDataSent() |
prussell | 0:0217a862b047 | 257 | //PR: onDataSent() maybe only occuring when confirmed receive by phone, as onDataSent() didn't happen when phone moved out of range. |
prussell | 0:0217a862b047 | 258 | } |
prussell | 0:0217a862b047 | 259 | |
prussell | 0:0217a862b047 | 260 | void Callback_BLE_onDataWritten(const GattCharacteristicWriteCBParams *pParams) |
prussell | 0:0217a862b047 | 261 | { |
prussell | 0:0217a862b047 | 262 | // Callback_BLE_onDataWritten == This does occur when use nRF-MCP to save New Heart Rate Control Point (Ignored if incorrect length) |
prussell | 0:0217a862b047 | 263 | |
prussell | 0:0217a862b047 | 264 | //Warning: *data may not be NULL terminated |
prussell | 0:0217a862b047 | 265 | 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 | 8:f187ba55aed2 | 266 | |
prussell | 8:f187ba55aed2 | 267 | //Triggered by BluetoothLEGatt sample changing Linkloss setting: |
prussell | 8:f187ba55aed2 | 268 | //Alert=1: Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x01]=Data[] |
prussell | 8:f187ba55aed2 | 269 | //Alert=2: Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x02]=Data[] |
prussell | 8:f187ba55aed2 | 270 | |
prussell | 8:f187ba55aed2 | 271 | /* From mbed project BLE_LoopbackUART: |
prussell | 8:f187ba55aed2 | 272 | if ((uartServicePtr != NULL) && (params->charHandle == uartServicePtr->getTXCharacteristicHandle())) { |
prussell | 8:f187ba55aed2 | 273 | uint16_t bytesRead = params->len; |
prussell | 8:f187ba55aed2 | 274 | DEBUG("received %u bytes\n\r", bytesRead); |
prussell | 8:f187ba55aed2 | 275 | ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(), params->data, bytesRead); |
prussell | 8:f187ba55aed2 | 276 | } |
prussell | 8:f187ba55aed2 | 277 | */ |
prussell | 8:f187ba55aed2 | 278 | //if(ble.getGapState().connected){ //Ensure BLE still connected |
prussell | 8:f187ba55aed2 | 279 | // if(params->charHandle == ble.getTXCharacteristicHandle()) |
prussell | 8:f187ba55aed2 | 280 | // htmService.updateTemperature( update_htm() ); |
prussell | 8:f187ba55aed2 | 281 | // hrmService.updateHeartRate( update_hrm() ); |
prussell | 8:f187ba55aed2 | 282 | // battService.updateBatteryLevel( update_batt() ); |
prussell | 8:f187ba55aed2 | 283 | |
prussell | 8:f187ba55aed2 | 284 | |
prussell | 8:f187ba55aed2 | 285 | /* switch(pParams->op){ |
prussell | 8:f187ba55aed2 | 286 | case GATTS_CHAR_OP_INVALID: |
prussell | 8:f187ba55aed2 | 287 | GATTS_CHAR_OP_WRITE_REQ |
prussell | 8:f187ba55aed2 | 288 | GATTS_CHAR_OP_WRITE_CMD |
prussell | 8:f187ba55aed2 | 289 | GATTS_CHAR_OP_SIGN_WRITE_CMD //< Signed Write Command |
prussell | 8:f187ba55aed2 | 290 | GATTS_CHAR_OP_PREP_WRITE_REQ //< Prepare Write Request |
prussell | 8:f187ba55aed2 | 291 | GATTS_CHAR_OP_EXEC_WRITE_REQ_CANCEL //< Execute Write Request: Cancel all prepared writes |
prussell | 8:f187ba55aed2 | 292 | GATTS_CHAR_OP_EXEC_WRITE_REQ_NOW //< Execute Write Request: Immediately execute all prepared writes |
prussell | 8:f187ba55aed2 | 293 | } |
prussell | 8:f187ba55aed2 | 294 | */ |
prussell | 8:f187ba55aed2 | 295 | |
prussell | 8:f187ba55aed2 | 296 | |
prussell | 8:f187ba55aed2 | 297 | |
prussell | 0:0217a862b047 | 298 | } |
prussell | 0:0217a862b047 | 299 | |
prussell | 0:0217a862b047 | 300 | void Callback_BLE_onUpdatesEnabled(Gap::Handle_t tHandle) |
prussell | 0:0217a862b047 | 301 | { |
prussell | 0:0217a862b047 | 302 | DEBUG("\nBLEi: Callback_BLE_onUpdates(Handle:%d)\r\n", tHandle); |
prussell | 0:0217a862b047 | 303 | } |
prussell | 0:0217a862b047 | 304 | |
prussell | 5:d36bbb315e31 | 305 | // Adopted 20141213 from http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_LinkLoss/file/440ee5e8595f/main.cpp |
prussell | 5:d36bbb315e31 | 306 | void Callback_BLE_onLinkLoss(LinkLossService::AlertLevel_t level) |
prussell | 5:d36bbb315e31 | 307 | { |
prussell | 5:d36bbb315e31 | 308 | printf("\nBLEi: Link loss alert[%d]\n", level); |
prussell | 5:d36bbb315e31 | 309 | } |
prussell | 8:f187ba55aed2 | 310 | //==========HRM========== |
prussell | 8:f187ba55aed2 | 311 | //Adopted 2014Dec from http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/ |
prussell | 8:f187ba55aed2 | 312 | uint8_t update_hrm(void)//(bool bInit) |
prussell | 8:f187ba55aed2 | 313 | { |
prussell | 8:f187ba55aed2 | 314 | static uint8_t u8_hrm = 100; |
prussell | 8:f187ba55aed2 | 315 | u8_hrm++; |
prussell | 8:f187ba55aed2 | 316 | if (u8_hrm >= 175) { |
prussell | 8:f187ba55aed2 | 317 | u8_hrm = 100; |
prussell | 8:f187ba55aed2 | 318 | DEBUG("BLE: HRM Rollover175->100 "); |
prussell | 8:f187ba55aed2 | 319 | } |
prussell | 8:f187ba55aed2 | 320 | DEBUG("[HRM:%d]", u8_hrm); |
prussell | 8:f187ba55aed2 | 321 | pServiceHRM->updateHeartRate( u8_hrm );// Update Characteristic so sent by BLE |
prussell | 8:f187ba55aed2 | 322 | return(u8_hrm); |
prussell | 8:f187ba55aed2 | 323 | } |
prussell | 8:f187ba55aed2 | 324 | //==========HTM:Internal Temperature========== |
prussell | 8:f187ba55aed2 | 325 | //Adopted 2014Dec from: https://developer.mbed.org/users/takafuminaka/code/BLE_HTM_by_InTempSensr/ |
prussell | 8:f187ba55aed2 | 326 | // Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml |
prussell | 8:f187ba55aed2 | 327 | // HTM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml |
prussell | 5:d36bbb315e31 | 328 | |
prussell | 8:f187ba55aed2 | 329 | //****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 |
prussell | 8:f187ba55aed2 | 330 | float update_htm(void) |
prussell | 8:f187ba55aed2 | 331 | { |
prussell | 8:f187ba55aed2 | 332 | //static float fTemperature = 0;//-123.456; |
prussell | 8:f187ba55aed2 | 333 | int32_t i32_temp; |
prussell | 8:f187ba55aed2 | 334 | sd_temp_get(&i32_temp); //Read the nRF Internal Temperature (Die in 0.25'C steps, Counting From TBD), TODO:Check Scaling |
prussell | 8:f187ba55aed2 | 335 | float fTemperature = (float(i32_temp)/4.0) - 16.0; // Scale&Shift (0.25'C from -16'C?) |
prussell | 8:f187ba55aed2 | 336 | |
prussell | 8:f187ba55aed2 | 337 | //{//Force to IEEE format to match needs of Apps like nRF-HTM and nRF-Toolbox:HTM |
prussell | 8:f187ba55aed2 | 338 | // 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. |
prussell | 8:f187ba55aed2 | 339 | // uint8_t exponent = 0xFE; //exponent is -2 |
prussell | 8:f187ba55aed2 | 340 | // uint32_t mantissa = (uint32_t)(fTemperature*100); |
prussell | 8:f187ba55aed2 | 341 | // uint32_t temp_ieee11073 = ((((uint32_t)exponent) << 24) | (mantissa)); //Note: Assumes Mantissa within 24bits |
prussell | 8:f187ba55aed2 | 342 | // memcpy(((uint8_t*)&fTemperature)+1, (uint8_t*)&temp_ieee11073, 4); //Overwrite with IEEE format float |
prussell | 8:f187ba55aed2 | 343 | //} |
prussell | 8:f187ba55aed2 | 344 | |
prussell | 8:f187ba55aed2 | 345 | pServiceHTM->updateTemperature( fTemperature );// Update Characteristic so sent by BLE |
prussell | 8:f187ba55aed2 | 346 | DEBUG("[HTMi:%d HTMf:%f]", i32_temp, fTemperature); |
prussell | 8:f187ba55aed2 | 347 | return(fTemperature); |
prussell | 8:f187ba55aed2 | 348 | } |
prussell | 8:f187ba55aed2 | 349 | //==========Battery========== |
prussell | 8:f187ba55aed2 | 350 | uint8_t update_batt(void) |
prussell | 8:f187ba55aed2 | 351 | { |
prussell | 8:f187ba55aed2 | 352 | static uint8_t u8_BattPercent=33; //Level: 0..100% |
prussell | 8:f187ba55aed2 | 353 | u8_BattPercent <= 50 ? u8_BattPercent=100 : u8_BattPercent--; // Simulate Battery Decay |
prussell | 8:f187ba55aed2 | 354 | pServiceBattery->updateBatteryLevel( u8_BattPercent ); // Update Characteristic so sent by BLE |
prussell | 8:f187ba55aed2 | 355 | DEBUG("[BATT:%d%%]", u8_BattPercent); |
prussell | 8:f187ba55aed2 | 356 | return(u8_BattPercent); |
prussell | 8:f187ba55aed2 | 357 | } |
prussell | 0:0217a862b047 | 358 | //==========main========== |
prussell | 0:0217a862b047 | 359 | int main(void) |
prussell | 0:0217a862b047 | 360 | { |
prussell | 0:0217a862b047 | 361 | f_led1level = 1; pwm_led1 = f_led1level;//Start LED1=OnMax |
prussell | 0:0217a862b047 | 362 | f_led2level = 1; pwm_led2 = f_led2level;//Start LED2=OnMax |
prussell | 6:5b6fb35b4450 | 363 | |
prussell | 6:5b6fb35b4450 | 364 | //Restart TeraTerm just before Pressing Reset on mbed, 9600-8N1(No Flow Control) |
prussell | 6:5b6fb35b4450 | 365 | DEBUG("\nBLE: ___%s___\n", pcDeviceName); |
prussell | 8:f187ba55aed2 | 366 | DEBUG("BLE: Connect App for Data: nRF-MCP, nRF-Toolbox:HRM/HTM, Android Sample BluetoothLeGatt, etc.\n"); |
prussell | 8:f187ba55aed2 | 367 | DEBUG("BLE: BluetoothLeGatt: App->mbed: LinkLoss->AlertLevel(UpArrow)\n"); |
prussell | 8:f187ba55aed2 | 368 | DEBUG("BLE: BluetoothLeGatt: App->mbed: BatteryService->BatteryLevel(DownArrow)\n"); |
prussell | 8:f187ba55aed2 | 369 | DEBUG("BLE: BluetoothLeGatt: mbed->App: BatteryService->BatteryLevel->EnableNotify(ThreeDownArrows), Also App Acks the send=DEBUG('SentI')\n"); |
prussell | 0:0217a862b047 | 370 | |
prussell | 0:0217a862b047 | 371 | Ticker ticker1; //PR: Timer Object(Structure) |
prussell | 0:0217a862b047 | 372 | ticker1.attach(CallbackTicker1, 2.0); //PR: Timer Handler, Float=PeriodSeconds |
prussell | 0:0217a862b047 | 373 | |
prussell | 3:a98203f84063 | 374 | //BLE1: Setup BLE Service (and event actions) //TODO: Check for services declared before main() - Is that OK? |
prussell | 3:a98203f84063 | 375 | DEBUG("BLE: Setup BLE\n"); |
prussell | 0:0217a862b047 | 376 | ble.init(); |
prussell | 0:0217a862b047 | 377 | ble.onDisconnection(Callback_BLE_onDisconnect); |
prussell | 0:0217a862b047 | 378 | ble.onConnection(Callback_BLE_onConnect); //PR: Not required if no actions enabled, enabled now just for debug printf() |
prussell | 0:0217a862b047 | 379 | ble.onDataSent(Callback_BLE_onDataSent); |
prussell | 0:0217a862b047 | 380 | ble.onDataWritten(Callback_BLE_onDataWritten); |
prussell | 0:0217a862b047 | 381 | ble.onTimeout(Callback_BLE_onTimeout); |
prussell | 0:0217a862b047 | 382 | ble.onUpdatesEnabled(Callback_BLE_onUpdatesEnabled); |
prussell | 8:f187ba55aed2 | 383 | |
prussell | 8:f187ba55aed2 | 384 | DEBUG("BLE: Handles:\n"); |
prussell | 8:f187ba55aed2 | 385 | //DEBUG(" Service: BLE: %d\n", ble.getHandle()); |
prussell | 8:f187ba55aed2 | 386 | //DEBUG(" Characteristic:BattLevel: %d\n", batteryLevelCharacteristic.getValueAttribute().getHandle()); |
prussell | 8:f187ba55aed2 | 387 | //DFUService |
prussell | 8:f187ba55aed2 | 388 | |
prussell | 8:f187ba55aed2 | 389 | |
prussell | 8:f187ba55aed2 | 390 | |
prussell | 0:0217a862b047 | 391 | |
prussell | 0:0217a862b047 | 392 | //ble_error_t readCharacteristicValue ( uint16_t handle, uint8_t *const buffer, uint16_t *const lengthP ) |
prussell | 0:0217a862b047 | 393 | //ble_error_t updateCharacteristicValue (uint16_t handle, const uint8_t *value, uint16_t size, bool localOnly=false) |
prussell | 0:0217a862b047 | 394 | |
prussell | 4:976394791d7a | 395 | //UUID List by Services that are setup |
prussell | 6:5b6fb35b4450 | 396 | //BLE2: Setup Services (with their initial values and options) |
prussell | 3:a98203f84063 | 397 | DEBUG("BLE: Setup Services\n"); |
prussell | 4:976394791d7a | 398 | // *Order here affects order in nRF-MCP Discovery of Services |
prussell | 8:f187ba55aed2 | 399 | DeviceInformationService ServiceDeviceInfo(ble, "Maker", pcDeviceName, "sn1234", "hw00", "fw00", "sw00");//(BLEDevice), pcManufacturer, pcModelNumber, pcSerialNumber, pcHWver, pcFWver, pcSWver |
prussell | 8:f187ba55aed2 | 400 | pServiceDeviceInfo = &ServiceDeviceInfo; DEBUG(" Handle Service DeviceInfo:%d\n", ServiceDeviceInfo); |
prussell | 8:f187ba55aed2 | 401 | LinkLossService ServiceLinkLoss(ble, Callback_BLE_onLinkLoss, LinkLossService::HIGH_ALERT); //New20141213, TBD |
prussell | 8:f187ba55aed2 | 402 | pServiceLinkLoss = &ServiceLinkLoss; |
prussell | 8:f187ba55aed2 | 403 | BatteryService ServiceBattery(ble, 10); |
prussell | 8:f187ba55aed2 | 404 | pServiceBattery = &ServiceBattery; |
prussell | 8:f187ba55aed2 | 405 | HeartRateService ServiceHRM(ble, (uint8_t)111, HeartRateService::LOCATION_FINGER); |
prussell | 8:f187ba55aed2 | 406 | pServiceHRM = &ServiceHRM; |
prussell | 8:f187ba55aed2 | 407 | HealthThermometerService ServiceHTM(ble, 33.3, HealthThermometerService::LOCATION_EAR); |
prussell | 8:f187ba55aed2 | 408 | pServiceHTM = &ServiceHTM; |
prussell | 8:f187ba55aed2 | 409 | //UARTService ServiceUART(ble); |
prussell | 8:f187ba55aed2 | 410 | // pServiceUART = &ServiceUART; |
prussell | 5:d36bbb315e31 | 411 | |
prussell | 3:a98203f84063 | 412 | //BLE3: Setup advertising |
prussell | 6:5b6fb35b4450 | 413 | // 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. |
prussell | 6:5b6fb35b4450 | 414 | // If there isn't enough space, then the accumulatepayload won't add that block to the advertising, it won't add a partial block. |
prussell | 3:a98203f84063 | 415 | DEBUG("BLE: Setup Advertising\n"); |
prussell | 6:5b6fb35b4450 | 416 | ble.clearAdvertisingPayload(); //Prep |
prussell | 6:5b6fb35b4450 | 417 | ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); //PR: Advertise 1sec (1Hz) |
prussell | 6:5b6fb35b4450 | 418 | ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); //PR: TODO: To Study |
prussell | 6:5b6fb35b4450 | 419 | ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); //PR: BLE Only (Option:LE_LIMITED_DISCOVERABLE) |
prussell | 6:5b6fb35b4450 | 420 | // Does "LE_GENERAL_DISCOVERABLE" affect whether UUID needs to be advertised to discover services? |
prussell | 6:5b6fb35b4450 | 421 | //ble.accumulateAdvertisingPayload(GapAdvertisingData::INCOMPLETE_LIST_128BIT_SERVICE_IDS, (const uint8_t *)UUID128_UART_Rev, sizeof(UUID128_UART_Rev)); //Single UUID128 |
prussell | 6:5b6fb35b4450 | 422 | //ble.accumulateAdvertisingPayload(GapAdvertisingData::INCOMPLETE_LIST_128BIT_SERVICE_IDS, (const uint8_t *)puUUID128_BatteryService, sizeof(puUUID128_BatteryService)); //Single UUID128 |
prussell | 6:5b6fb35b4450 | 423 | //ble.accumulateAdvertisingPayload(GapAdvertisingData::INCOMPLETE_LIST_128BIT_SERVICE_IDS, puStrToUUID128( pc_com_none_servA), LENGTH_OF_LONG_UUID); //Single UUID128 |
prussell | 6:5b6fb35b4450 | 424 | //ble.accumulateAdvertisingPayload(GapAdvertisingData::INCOMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // Multiple UUID16 |
prussell | 6:5b6fb35b4450 | 425 | ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // Multiple UUID16 |
prussell | 6:5b6fb35b4450 | 426 | //ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);//PR: Add Appearance::HeartRate (HRM Connects without this) |
prussell | 6:5b6fb35b4450 | 427 | //ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_THERMOMETER); //PR: Add Appearance::Thermometer (HTM Connects without this, though float format still needs change) |
prussell | 6:5b6fb35b4450 | 428 | // Add LocalName last so if Advertising too long will easily see as Name won't be available for the device. |
prussell | 6:5b6fb35b4450 | 429 | ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)pcDeviceName, sizeof(pcDeviceName)-1);//PR: LocalName (No NULL) |
prussell | 6:5b6fb35b4450 | 430 | ble.startAdvertising(); |
prussell | 3:a98203f84063 | 431 | |
prussell | 6:5b6fb35b4450 | 432 | // Raw Advertizing max length 31bytes: 0x01020304050607080910111213141516171819202122232425262728293031 |
prussell | 6:5b6fb35b4450 | 433 | // Example Raw Advertising caught by App nRF-MCP: 0x020106070309180A180D180909626C655052763034 |
prussell | 6:5b6fb35b4450 | 434 | // = Len02 Type01 Value06 (Flags: BREDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE) |
prussell | 6:5b6fb35b4450 | 435 | // = Len07 Type03 Values: 0918 0A18 0D18 (ListUUID16: 1809 180A 180D ) |
prussell | 6:5b6fb35b4450 | 436 | // = Len09 Type09 Values: 62 6C 65 50 52 76 30 34 (LocalName = "blePRv04") |
prussell | 5:d36bbb315e31 | 437 | |
prussell | 6:5b6fb35b4450 | 438 | // Example Raw Advertising caught by App nRF-MCP: 0x02010611069ECADC240EE5A9E093F3A3B50100406E090209180A180D180F18 (==Max Length) |
prussell | 6:5b6fb35b4450 | 439 | // = Len02 Type01 Value06 (Flags: BREDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE) |
prussell | 6:5b6fb35b4450 | 440 | // = Len11 Type06 Value9ECADC240EE5A9E093F3A3B5_0100_406E (UUID128: NordicUART=0x0001) |
prussell | 6:5b6fb35b4450 | 441 | // = Len09 Type02 Values:0918 0A18 0D18 0F18 (UUID16: 1809 180A 180D 180F) |
prussell | 6:5b6fb35b4450 | 442 | // = LocalName field wasn't appended as insufficient space, so Device won't be named when scanning. |
prussell | 6:5b6fb35b4450 | 443 | |
prussell | 6:5b6fb35b4450 | 444 | // Example Raw Advertising caught by App nRF-MCP: 0x0201061106FB349B5F80000080001000000F180000070209180A180D18 |
prussell | 6:5b6fb35b4450 | 445 | // = Len02 Type01 Value06 (Flags: BREDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE) |
prussell | 6:5b6fb35b4450 | 446 | // = Len11 Type06 ValueFB349B5F8000008000100000_0F18_0000 (UUID128: BluetoothBattery=0x180F) |
prussell | 6:5b6fb35b4450 | 447 | // = Len07 Type02 Value 0918 0A18 0D18 (UUID16: 1809 180A 180D ) |
prussell | 6:5b6fb35b4450 | 448 | // = LocalName field wasn't appended as insufficient space, so Device won't be named when scanning. |
prussell | 0:0217a862b047 | 449 | |
prussell | 0:0217a862b047 | 450 | DEBUG("BLE: Main Loop\n"); |
prussell | 0:0217a862b047 | 451 | uint32_t u32_wakeevents=0, u32_wakelast=0; // Counter&Register for tracking Wake Events (to see monitor their Frequency) |
prussell | 0:0217a862b047 | 452 | while (true) { |
prussell | 0:0217a862b047 | 453 | if (b_Ticker1 && ble.getGapState().connected) { //If Ticker1 and Connected Update Data |
prussell | 0:0217a862b047 | 454 | b_Ticker1 = false; // Clear flag for next Ticker1, see CallbackTicker1() |
prussell | 3:a98203f84063 | 455 | |
prussell | 3:a98203f84063 | 456 | // Read Sensors, and update matching Service Characteristics (only if connected) |
prussell | 4:976394791d7a | 457 | // *Order here doesn't affect order in nRF-MCP Discovery of Services |
prussell | 6:5b6fb35b4450 | 458 | //TBD: Maybe save power by not Tx unless enabled by App? |
prussell | 8:f187ba55aed2 | 459 | // The Services are discovered if they were setup/started (They don't need update to be discovered) |
prussell | 8:f187ba55aed2 | 460 | update_htm(); |
prussell | 8:f187ba55aed2 | 461 | update_hrm(); |
prussell | 8:f187ba55aed2 | 462 | update_batt(); |
prussell | 8:f187ba55aed2 | 463 | |
prussell | 3:a98203f84063 | 464 | DEBUG("BLE: Wakes:%u Delta:%d ", u32_wakeevents, u32_wakeevents-u32_wakelast); //For Evaluating Timing |
prussell | 3:a98203f84063 | 465 | u32_wakelast = u32_wakeevents; |
prussell | 0:0217a862b047 | 466 | } else if (b_Ticker1) { |
prussell | 0:0217a862b047 | 467 | b_Ticker1 = false; // Clear flag for next Ticker1, see CallbackTicker1() |
prussell | 3:a98203f84063 | 468 | DEBUG("BLE: Tick while unconnected "); |
prussell | 0:0217a862b047 | 469 | } else if (bSent){ |
prussell | 0:0217a862b047 | 470 | bSent=false; //clear flag |
prussell | 3:a98203f84063 | 471 | //DEBUG("BLE: Sent %ubytes ", uSentBLE); |
prussell | 0:0217a862b047 | 472 | } else { |
prussell | 3:a98203f84063 | 473 | //DEBUG("BLE: Wait for Event\n\r"); //x Debug output here causes unnecessary wakes resulting in endless awakes. |
prussell | 0:0217a862b047 | 474 | ble.waitForEvent(); //PR: Wait for event - Yield control to BLE Stack and other events (Process ALL pending events before waiting again) |
prussell | 0:0217a862b047 | 475 | f_led2level+=0.25; if (f_led2level>0.5){f_led2level = 0.0;}; pwm_led2=f_led2level;//PR: Ramp Blink |
prussell | 0:0217a862b047 | 476 | u32_wakeevents++; //PR: Count events for frequency monitoring (20141207PR: nRF51822 mbed HRM = 50Hz) |
prussell | 0:0217a862b047 | 477 | } |
prussell | 0:0217a862b047 | 478 | } |
prussell | 0:0217a862b047 | 479 | } |
prussell | 6:5b6fb35b4450 | 480 | //========== end ========== |