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@16:3e83f2babdfb, 2014-12-27 (annotated)
- Committer:
- prussell
- Date:
- Sat Dec 27 14:33:12 2014 +0000
- Revision:
- 16:3e83f2babdfb
- Parent:
- 15:b2c8bdef2d20
- Child:
- 17:93538044f003
Debugging Android Notify
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 | 9:2d11beda333f | 4 | // - http://developer.mbed.org/users/jksoft/code/BLE_RCBController/ (Setting up a custom Service/Characteristic) |
prussell | 0:0217a862b047 | 5 | // - http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/ |
prussell | 0:0217a862b047 | 6 | // - https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_LoopbackUART/ |
prussell | 1:4a25d917fb6a | 7 | // - https://developer.mbed.org/users/takafuminaka/code/BLE_HTM_by_InTempSensr/ |
prussell | 6:5b6fb35b4450 | 8 | // - https://developer.mbed.org/users/garimagupta002/notebook/ble-uart-lcd-demo/ (Advertise UUID16+UUID128) |
prussell | 10:ee3a359f7d3f | 9 | // - http://developer.mbed.org/teams/UCL-IoT/code/BLE_LED_Controller/ (With matching Android App, uses BLE-UART) |
prussell | 10:ee3a359f7d3f | 10 | // - https://developer.mbed.org/users/todotani/code/BLE_Health_Thermometer2-010/wiki/BLE_Health_Thermometer2-010 //Temperature handles |
prussell | 10:ee3a359f7d3f | 11 | // - |
prussell | 0:0217a862b047 | 12 | // - miscellaneous adopted from more samples... |
prussell | 0:0217a862b047 | 13 | // Reference: |
prussell | 0:0217a862b047 | 14 | // - http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/ |
prussell | 0:0217a862b047 | 15 | // - Reference: http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/docs/tip/ |
prussell | 0:0217a862b047 | 16 | // - Reference: http://developer.mbed.org/teams/Bluetooth-Low-Energy/ |
prussell | 0:0217a862b047 | 17 | // Warnings: |
prussell | 0:0217a862b047 | 18 | // - As of 20141210 it is necessary to use Android App [nRF-Master Control Panel] to ensure any previous connected |
prussell | 0:0217a862b047 | 19 | // code on mkit is properly Disconnected before trying to connect other Android nRF Apps (nRFToolbox, nRF UART 2.0, etc.). |
prussell | 0:0217a862b047 | 20 | // 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 | 21 | // Notes: |
prussell | 10:ee3a359f7d3f | 22 | // - onDataSent() maybe only occuring when confirmed receive by phone, as onDataSent() didn't happen when phone moved out of range, and no onDataSent() with App nRF-MCP. |
prussell | 0:0217a862b047 | 23 | // - onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range, OnTimeout didn't occur at all. |
prussell | 0:0217a862b047 | 24 | // ToDo: and ToCheck: |
prussell | 8:f187ba55aed2 | 25 | // - 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 | 26 | // - Re-check where voltatile needed |
prussell | 8:f187ba55aed2 | 27 | // - 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 | 11:7d02fe5ebea5 | 28 | // - invalid or untested reference code commented with "//x ", feel free to delete or experiment |
prussell | 11:7d02fe5ebea5 | 29 | // - valid alternate code commented with "//a " prefix to indicate alternnative is valid code |
prussell | 0:0217a862b047 | 30 | //==========End of PR's Header |
prussell | 0:0217a862b047 | 31 | |
prussell | 0:0217a862b047 | 32 | //==========Historic Licencing from original imported sample from mbed website [BLE_HeartRate] ========== |
prussell | 0:0217a862b047 | 33 | //From: http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/ |
prussell | 0:0217a862b047 | 34 | /* mbed Microcontroller Library |
prussell | 0:0217a862b047 | 35 | * Copyright (c) 2006-2013 ARM Limited |
prussell | 0:0217a862b047 | 36 | * |
prussell | 0:0217a862b047 | 37 | * Licensed under the Apache License, Version 2.0 (the "License"); |
prussell | 0:0217a862b047 | 38 | * you may not use this file except in compliance with the License. |
prussell | 0:0217a862b047 | 39 | * You may obtain a copy of the License at |
prussell | 0:0217a862b047 | 40 | * http://www.apache.org/licenses/LICENSE-2.0 |
prussell | 0:0217a862b047 | 41 | * Unless required by applicable law or agreed to in writing, software |
prussell | 0:0217a862b047 | 42 | * distributed under the License is distributed on an "AS IS" BASIS, |
prussell | 0:0217a862b047 | 43 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
prussell | 0:0217a862b047 | 44 | * See the License for the specific language governing permissions and |
prussell | 0:0217a862b047 | 45 | * limitations under the License. */ |
prussell | 0:0217a862b047 | 46 | //==========end of Historic Licencing ========== |
prussell | 0:0217a862b047 | 47 | |
prussell | 0:0217a862b047 | 48 | |
prussell | 0:0217a862b047 | 49 | //==========Compile Options========== |
prussell | 11:7d02fe5ebea5 | 50 | #define ENABLE_uSerial 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 | 11:7d02fe5ebea5 | 51 | //x #define ENABLE_BLE_SLOW 0 //PR: Option to slow the connection interval possibly saving power (After Connected) -- Imported feature never tested |
prussell | 0:0217a862b047 | 52 | |
prussell | 0:0217a862b047 | 53 | //==========Includes========== |
prussell | 9:2d11beda333f | 54 | #include "mbed.h" // mbed |
prussell | 1:4a25d917fb6a | 55 | #include "BLEDevice.h" // BLE |
prussell | 1:4a25d917fb6a | 56 | #include "nrf_soc.h" // nRF Internal Temperature Sensor |
prussell | 0:0217a862b047 | 57 | |
prussell | 0:0217a862b047 | 58 | //Services |
prussell | 0:0217a862b047 | 59 | #include "BatteryService.h" |
prussell | 0:0217a862b047 | 60 | #include "DeviceInformationService.h" |
prussell | 5:d36bbb315e31 | 61 | #include "HealthThermometerService.h" |
prussell | 0:0217a862b047 | 62 | #include "HeartRateService.h" |
prussell | 5:d36bbb315e31 | 63 | #include "LinkLossService.h" //TODO: How support this? |
prussell | 8:f187ba55aed2 | 64 | //#include "DFUService" //TODO: DFU and FOTA Support |
prussell | 0:0217a862b047 | 65 | //#include "UARTService.h" //TODO: Add a UART Channel for streaming data like logs? |
prussell | 0:0217a862b047 | 66 | |
prussell | 0:0217a862b047 | 67 | //==========Debug Console========== |
prussell | 11:7d02fe5ebea5 | 68 | #if ENABLE_uSerial |
prussell | 11:7d02fe5ebea5 | 69 | //Restart TeraTerm just before Pressing Reset on mbed, Default Serual=9600-8N1(No Flow Control) |
prussell | 10:ee3a359f7d3f | 70 | //Using default baud rate to avoid issues with DEBUG in a constructor being at default baud rate before main() |
prussell | 11:7d02fe5ebea5 | 71 | //TeraTerm: http://en.sourceforge.jp/projects/ttssh2/releases/ |
prussell | 11:7d02fe5ebea5 | 72 | Serial debug_userial(USBTX, USBRX); //PR: DebugSerialOverMbedUSB |
prussell | 11:7d02fe5ebea5 | 73 | #define DEBUG(...) { debug_userial.printf(__VA_ARGS__); } |
prussell | 0:0217a862b047 | 74 | #else |
prussell | 6:5b6fb35b4450 | 75 | #define DEBUG(...) //Do Nothing, DEBUG() lines are ignored |
prussell | 0:0217a862b047 | 76 | #endif |
prussell | 0:0217a862b047 | 77 | |
prussell | 2:c77c2b06d604 | 78 | //========== This Section is to Create Debug output showing variable prep before main() ========== |
prussell | 2:c77c2b06d604 | 79 | bool u8_prep_dummy(void) { |
prussell | 6:5b6fb35b4450 | 80 | 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 | 81 | return true; |
prussell | 2:c77c2b06d604 | 82 | } |
prussell | 2:c77c2b06d604 | 83 | const bool bPrep = u8_prep_dummy(); |
prussell | 2:c77c2b06d604 | 84 | |
prussell | 11:7d02fe5ebea5 | 85 | //========== IO Hardware: Buttons, LEDs, PWM ========== |
prussell | 12:8bac5f5d3a3e | 86 | // Inputs: (Simultaneous DigitalIn and InteruptIn is OK) |
prussell | 11:7d02fe5ebea5 | 87 | DigitalIn bB1in(BUTTON1); //if(bB1in){} |
prussell | 11:7d02fe5ebea5 | 88 | DigitalIn bB2in(BUTTON2); //if(bB2in){} |
prussell | 11:7d02fe5ebea5 | 89 | InterruptIn B1int(BUTTON1); //B1int.rise(&onB1rise); |
prussell | 11:7d02fe5ebea5 | 90 | InterruptIn B2int(BUTTON2); //B1int.fall(&onB1fall); |
prussell | 11:7d02fe5ebea5 | 91 | |
prussell | 11:7d02fe5ebea5 | 92 | // Outputs: |
prussell | 12:8bac5f5d3a3e | 93 | //a DigitalOut bL1out(LED1); // Direct LED1 drive |
prussell | 12:8bac5f5d3a3e | 94 | //a DigitalOut bL2out(LED2); // Direct LED2 drive |
prussell | 12:8bac5f5d3a3e | 95 | PwmOut fL1pwm(LED1); float fL1level = 0.1; // PWM LED1, brightness=float(0.0~1.0) |
prussell | 12:8bac5f5d3a3e | 96 | PwmOut fL2pwm(LED2); float fL2level = 0.1; // PWM LED2, brightness=float(0.0~1.0) |
prussell | 12:8bac5f5d3a3e | 97 | bool bAppControl = false; //Flag: Host has control of LEDs through BLE |
prussell | 11:7d02fe5ebea5 | 98 | |
prussell | 12:8bac5f5d3a3e | 99 | //a volatile uint8_t uB1rise; void onB1rise(void){ uB1rise++; };// Flag Event, Counter helps detect missed events since last cleared |
prussell | 12:8bac5f5d3a3e | 100 | //a volatile uint8_t uB1fall; void onB1fall(void){ uB1fall++; };// Flag Event, Counter helps detect missed events since last cleared |
prussell | 12:8bac5f5d3a3e | 101 | //a volatile uint8_t uB2rise; void onB2rise(void){ uB2rise++; };// Flag Event, Counter helps detect missed events since last cleared |
prussell | 12:8bac5f5d3a3e | 102 | //a volatile uint8_t uB2fall; void onB2fall(void){ uB2fall++; };// Flag Event, Counter helps detect missed events since last cleared |
prussell | 0:0217a862b047 | 103 | |
prussell | 0:0217a862b047 | 104 | //==========BLE========== |
prussell | 13:1c67c03bbf53 | 105 | //const static char pcDeviceName[] = "bleIOv04_pr"; //Too Long for advertising with a UUID128 |
prussell | 13:1c67c03bbf53 | 106 | const static char pcDeviceName[] = "bleIOv04"; //Advertised device name (Max length depends on available space with other Advertising data) |
prussell | 0:0217a862b047 | 107 | BLEDevice ble; |
prussell | 10:ee3a359f7d3f | 108 | //Pointers to services for accesses outside main() |
prussell | 8:f187ba55aed2 | 109 | HeartRateService *pServiceHRM; |
prussell | 15:b2c8bdef2d20 | 110 | HealthThermometerService *pServiceHTM; |
prussell | 15:b2c8bdef2d20 | 111 | BatteryService *pServiceBattery; |
prussell | 8:f187ba55aed2 | 112 | DeviceInformationService *pServiceDeviceInfo; |
prussell | 8:f187ba55aed2 | 113 | LinkLossService *pServiceLinkLoss; |
prussell | 10:ee3a359f7d3f | 114 | //x DFUService *pServiceDFU; |
prussell | 10:ee3a359f7d3f | 115 | //x UARTService *pServiceUART; //FromApp: pServiceUART->getTXCharacteristicHandle(); //ToApp: ble.updateCharacteristicValue(pServiceUART->getRXCharacteristicHandle(), pData, uLen); |
prussell | 10:ee3a359f7d3f | 116 | //x bleIOService *pServiceIO; |
prussell | 3:a98203f84063 | 117 | |
prussell | 6:5b6fb35b4450 | 118 | //==========UUID========== |
prussell | 6:5b6fb35b4450 | 119 | //UUID Info: |
prussell | 5:d36bbb315e31 | 120 | // 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 | 121 | /* All the custom GATT based services and characteristics must use a 128 bit UUID. |
prussell | 5:d36bbb315e31 | 122 | The Bluetooth_Base_UUID is: 00000000-0000-1000-8000 00805F9B34FB. |
prussell | 5:d36bbb315e31 | 123 | All the 16-bit Attribute UUIDs defined in the adopted specifications use the above base. |
prussell | 5:d36bbb315e31 | 124 | 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 | 125 | 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 | 126 | 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 | 127 | Latency: Refer to Core Spec V4.0, Vol 3, Part F - 3.3.1, which is "Ready by Type Request". |
prussell | 5:d36bbb315e31 | 128 | 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 | 129 | There is additional 14 extra bytes over head for the custom profiles for "Ready By Type Request Method" |
prussell | 5:d36bbb315e31 | 130 | 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 | 10:ee3a359f7d3f | 131 | 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 | 10:ee3a359f7d3f | 132 | // 16bit UUID uses: 128bit base(32 hex digits): 0000****-0000-1000-8000 00805F9B34FB (Careful to use unsigned to avoid negatives and overflows) |
prussell | 10:ee3a359f7d3f | 133 | // 32bit UUID uses: 128bit base(32 hex digits): ********-0000-1000-8000 00805F9B34FB (Careful to use unsigned to avoid negatives and overflows) |
prussell | 10:ee3a359f7d3f | 134 | |
prussell | 10:ee3a359f7d3f | 135 | //UUID128 List(Only a single UUID128 can fit in advertising) |
prussell | 10:ee3a359f7d3f | 136 | //a 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, where ****==UUID16 |
prussell | 10:ee3a359f7d3f | 137 | //a 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, where ****==0x180F |
prussell | 4:976394791d7a | 138 | |
prussell | 11:7d02fe5ebea5 | 139 | //a //UUID16 List - Advertising these required by App nRF-Toolbox:HRM&HTM // Keep list short so advertizing not over 31bytes. |
prussell | 10:ee3a359f7d3f | 140 | /*static const uint16_t uuid16_list[] = { //Service List (Pre-defined standard 16bit services) |
prussell | 10:ee3a359f7d3f | 141 | // *Order here doesn't affect order in nRF-MCP Discovery of Services |
prussell | 10:ee3a359f7d3f | 142 | //BLE_UUID_GAP UUID_GENERIC_ACCESS //0x1800 //Included by Default, DeviceName, Appearance, PreferredConnectionParam |
prussell | 10:ee3a359f7d3f | 143 | //BLE_UUID_GATT UUID_GENERIC ATTRIBUTE //0x1801 //Included by Default, ServiceChanged, |
prussell | 10:ee3a359f7d3f | 144 | GattService::UUID_HEALTH_THERMOMETER_SERVICE, //0x1809 //HTM (Might need to be first for nRF App) |
prussell | 10:ee3a359f7d3f | 145 | GattService::UUID_HEART_RATE_SERVICE, //0x180D //HRM, BodyLocation, ControlPoint |
prussell | 10:ee3a359f7d3f | 146 | GattService::UUID_DEVICE_INFORMATION_SERVICE, //0x180A //sManufacturer, sModelNumber, sSerialNumber, sHWver, sFWver, sSWver |
prussell | 10:ee3a359f7d3f | 147 | GattService::UUID_BATTERY_SERVICE, //0x180F //BatteryLevel |
prussell | 10:ee3a359f7d3f | 148 | GattService::UUID_LINK_LOSS_SERVICE, //0x1803 //LinkLoss |
prussell | 10:ee3a359f7d3f | 149 | //x GattService::UUID_DFU, //0x1530 - See UARTServiceShortUUID in BLE_API:DFUService.cpp // |
prussell | 10:ee3a359f7d3f | 150 | //x GattService::UARTService, //0x0001~0x0003 - See DFUServiceShortUUID in BLE_API:UARTService.cpp // |
prussell | 10:ee3a359f7d3f | 151 | //Possibly useful: |
prussell | 10:ee3a359f7d3f | 152 | //x GattService::UUID_ALERT_NOTIFICATION_SERVICE, //0x1811 |
prussell | 10:ee3a359f7d3f | 153 | //x GattService::UUID_CURRENT_TIME_SERVICE, //0x1805 |
prussell | 10:ee3a359f7d3f | 154 | //x GattService::UUID_HUMAN_INTERFACE_DEVICE_SERVICE, //0x1812 |
prussell | 10:ee3a359f7d3f | 155 | //x GattService::UUID_IMMEDIATE_ALERT_SERVICE, //0x1802 |
prussell | 10:ee3a359f7d3f | 156 | //x GattService::UUID_PHONE_ALERT_STATUS_SERVICE, //0x180E |
prussell | 10:ee3a359f7d3f | 157 | //x GattService::UUID_REFERENCE_TIME_UPDATE_SERVICE, //0x1806 |
prussell | 10:ee3a359f7d3f | 158 | //x GattService::UUID_SCAN_PARAMETERS_SERVICE, //0x1813 |
prussell | 10:ee3a359f7d3f | 159 | };*/ |
prussell | 2:c77c2b06d604 | 160 | |
prussell | 10:ee3a359f7d3f | 161 | //========== bleIO - A Custom Service for Handling IO with an App (GPIO,PWM,etc.)========== |
prussell | 10:ee3a359f7d3f | 162 | //UUID128 List - Note only the single Service UUID128 can fit in the advertising |
prussell | 9:2d11beda333f | 163 | |
prussell | 9:2d11beda333f | 164 | // Custom UUID128 base for this service and its characteristics (from: http://www.itu.int/ITU-T/asn1/uuid.html) |
prussell | 9:2d11beda333f | 165 | // **This is a temporary UUID for testing by anyone, should be replaced before proceeding to real product.** |
prussell | 9:2d11beda333f | 166 | // Can check that UUID is correctly entered by viewing with Android App: nRF-Master Control panel |
prussell | 9:2d11beda333f | 167 | // UUID128 can be generated using: http://www.itu.int/ITU-T/asn1/uuid.html |
prussell | 9:2d11beda333f | 168 | // 20141218PR: [4d3281c0-86d1-11e4-b084-0002a5d5c51b] == OID[2.25.102612802202735078710424021169255859483] |
prussell | 10:ee3a359f7d3f | 169 | // Base UUID128 (1 digit modified):{0x4d,0x32,0x81,0xc0,0x86,0xd1,0x11,0xe4,0xb0,0x84,0x00,0x02,0xa5,0xd5,0xc5,0x1*};// NormalOrder |
prussell | 10:ee3a359f7d3f | 170 | uint8_t puUUID128_IOService[16] = {0x4d,0x32,0x81,0xc0,0x86,0xd1,0x11,0xe4,0xb0,0x84,0x00,0x02,0xa5,0xd5,0xc5,0x10};// Service UUID |
prussell | 11:7d02fe5ebea5 | 171 | uint8_t puUUID128_IOAdvertise[16]= {0x10,0xc5,0xd5,0xa5,0x02,0x00,0x84,0xb0,0xe4,0x11,0xd1,0x86,0xc0,0x81,0x32,0x4d};// Advertising Service UUID (=ReversedOrder) |
prussell | 10:ee3a359f7d3f | 172 | // Characteristic UUID: Initially using generic blocks of IO data that may be manually dividied up into Buttons, LEDs, PWM, ADC, etc. |
prussell | 10:ee3a359f7d3f | 173 | uint8_t puUUID128_IOw8[16] = {0x4d,0x32,0x81,0xc0,0x86,0xd1,0x11,0xe4,0xb0,0x84,0x00,0x02,0xa5,0xd5,0xc5,0x11};// Write[8byte] to mbed from phone |
prussell | 10:ee3a359f7d3f | 174 | uint8_t puUUID128_IOr4[16] = {0x4d,0x32,0x81,0xc0,0x86,0xd1,0x11,0xe4,0xb0,0x84,0x00,0x02,0xa5,0xd5,0xc5,0x12};// Read[4byte] from mbed to phone |
prussell | 10:ee3a359f7d3f | 175 | uint8_t puUUID128_IOn4[16] = {0x4d,0x32,0x81,0xc0,0x86,0xd1,0x11,0xe4,0xb0,0x84,0x00,0x02,0xa5,0xd5,0xc5,0x13};// Notify[4byte] from mbed to phone |
prussell | 10:ee3a359f7d3f | 176 | // Alternately can have a characterostic for each discrete item, such as: |
prussell | 10:ee3a359f7d3f | 177 | //a uint8_t puUUID128_bleConfig32[16] = {0x1X,0xc5,0xd5,0xa5,0x02,0x00,0x84,0xb0,0xe4,0x11,0xd1,0x86,0xc0,0x81,0x32,0x4d};// Configuration 32bits |
prussell | 10:ee3a359f7d3f | 178 | //a uint8_t puUUID128_bleOut1[16] = {0x1X,0xc5,0xd5,0xa5,0x02,0x00,0x84,0xb0,0xe4,0x11,0xd1,0x86,0xc0,0x81,0x32,0x4d};// Output 1bit |
prussell | 10:ee3a359f7d3f | 179 | //a uint8_t puUUID128_bleOutPWM100[16]= {0x1X,0xc5,0xd5,0xa5,0x02,0x00,0x84,0xb0,0xe4,0x11,0xd1,0x86,0xc0,0x81,0x32,0x4d};// Output PWM (Range 0~100%) |
prussell | 10:ee3a359f7d3f | 180 | //a uint8_t puUUID128_bleOutPWM256[16]= {0x1X,0xc5,0xd5,0xa5,0x02,0x00,0x84,0xb0,0xe4,0x11,0xd1,0x86,0xc0,0x81,0x32,0x4d};// Output PWM (256 levels, 0~255) |
prussell | 10:ee3a359f7d3f | 181 | //a uint8_t puUUID128_bleIn1[16] = {0x1X,0xc5,0xd5,0xa5,0x02,0x00,0x84,0xb0,0xe4,0x11,0xd1,0x86,0xc0,0x81,0x32,0x4d};// Input 1bit |
prussell | 10:ee3a359f7d3f | 182 | //a uint8_t puUUID128_bleInADC12[16] = {0x1X,0xc5,0xd5,0xa5,0x02,0x00,0x84,0xb0,0xe4,0x11,0xd1,0x86,0xc0,0x81,0x32,0x4d};// Input ADC 12bit |
prussell | 10:ee3a359f7d3f | 183 | |
prussell | 10:ee3a359f7d3f | 184 | /* Android: |
prussell | 10:ee3a359f7d3f | 185 | //bleIO Service and Characteristics |
prussell | 10:ee3a359f7d3f | 186 | attributes.put("4d3281c0-86d1-11e4-b084-0002a5d5c51b", "bleIO base"); |
prussell | 10:ee3a359f7d3f | 187 | attributes.put("4d3281c0-86d1-11e4-b084-0002a5d5c510", "bleIO Service"); |
prussell | 10:ee3a359f7d3f | 188 | attributes.put("4d3281c0-86d1-11e4-b084-0002a5d5c511", "bleIO w8"); |
prussell | 10:ee3a359f7d3f | 189 | attributes.put("4d3281c0-86d1-11e4-b084-0002a5d5c512", "bleIO r4"); |
prussell | 10:ee3a359f7d3f | 190 | attributes.put("4d3281c0-86d1-11e4-b084-0002a5d5c513", "bleIO n4"); |
prussell | 9:2d11beda333f | 191 | |
prussell | 10:ee3a359f7d3f | 192 | attributes.put("1bc5d5a5-0200-84b0-e411-d186c081324d", "bleIO rev base"); |
prussell | 10:ee3a359f7d3f | 193 | attributes.put("10c5d5a5-0200-84b0-e411-d186c081324d", "bleIO rev Service"); |
prussell | 10:ee3a359f7d3f | 194 | attributes.put("11c5d5a5-0200-84b0-e411-d186c081324d", "bleIO rev w8"); |
prussell | 10:ee3a359f7d3f | 195 | attributes.put("12c5d5a5-0200-84b0-e411-d186c081324d", "bleIO rev r4"); |
prussell | 10:ee3a359f7d3f | 196 | attributes.put("13c5d5a5-0200-84b0-e411-d186c081324d", "bleIO rev n4"); |
prussell | 10:ee3a359f7d3f | 197 | */ |
prussell | 10:ee3a359f7d3f | 198 | |
prussell | 10:ee3a359f7d3f | 199 | // Characteristic Value Storage (with Initial values, should match actual data type transferred, doesn't have to be byte array): |
prussell | 12:8bac5f5d3a3e | 200 | //a uint8_t pIOw8[8] = {0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17}; //Value Storage for Characteristic Write8 |
prussell | 12:8bac5f5d3a3e | 201 | //a uint8_t pIOr4[4] = {0x20,0x21,0x22,0x23}; //Value Storage for Characteristic Read4 |
prussell | 12:8bac5f5d3a3e | 202 | //a uint8_t pIOn4[4] = {0x30,0x31,0x32,0x33}; //Value Storage for Characteristic Notify4 |
prussell | 12:8bac5f5d3a3e | 203 | |
prussell | 12:8bac5f5d3a3e | 204 | union { // Option: split long setup from short updates to minimize BLE power and traffic |
prussell | 12:8bac5f5d3a3e | 205 | struct {// First item in union defines the initializers |
prussell | 12:8bac5f5d3a3e | 206 | uint8_t L1pwm100; // LED1 Brightness (0%~100%) |
prussell | 12:8bac5f5d3a3e | 207 | uint8_t L2pwm255; // LED2 Brightness (0~255) |
prussell | 12:8bac5f5d3a3e | 208 | //float xxxx; //Option: If both smartphone and device use same type of float, else put converter in smartphone code (phone has larger battery and memory) |
prussell | 12:8bac5f5d3a3e | 209 | uint16_t px[3]; // Spare 3*16bit (Test: incremented by Ticker1 |
prussell | 12:8bac5f5d3a3e | 210 | } s; |
prussell | 12:8bac5f5d3a3e | 211 | uint8_t pu[]; //Direct Byte access |
prussell | 12:8bac5f5d3a3e | 212 | char pc[]; //Character Access (No Terminating Null) |
prussell | 12:8bac5f5d3a3e | 213 | } sIOw8 = {100,255,0xA00A, 0xB000, 0xC000}; // Structure/union for Characteristic IOw8 |
prussell | 12:8bac5f5d3a3e | 214 | // sIOw8.s.L1pwm100, sIOw8.s.L2pwm255, sIOw8.s.px, sIOw8.pu |
prussell | 12:8bac5f5d3a3e | 215 | |
prussell | 12:8bac5f5d3a3e | 216 | union { // Longer maybe OK since only read upon command |
prussell | 12:8bac5f5d3a3e | 217 | struct {// First item in union defines the initializers |
prussell | 12:8bac5f5d3a3e | 218 | uint8_t bB1p:1,bB2p:1; // Button status, 1/true=Pressed, bit1==Button1, bit2==Button2 |
prussell | 12:8bac5f5d3a3e | 219 | uint8_t uB1p:6; // Count Button1 Presses (6bit) |
prussell | 12:8bac5f5d3a3e | 220 | uint8_t uB1r; // Count Button1 Releases |
prussell | 12:8bac5f5d3a3e | 221 | uint8_t uB2p; // Count Button2 Presses |
prussell | 12:8bac5f5d3a3e | 222 | uint8_t uB2r; // Count Button2 Releases |
prussell | 12:8bac5f5d3a3e | 223 | // // Option: ADC or other inputs or device status |
prussell | 12:8bac5f5d3a3e | 224 | } s; |
prussell | 12:8bac5f5d3a3e | 225 | uint8_t pu[]; //Direct Byte access |
prussell | 12:8bac5f5d3a3e | 226 | char pc[]; //Character Access (No Terminating Null) |
prussell | 12:8bac5f5d3a3e | 227 | } sIOr4 = { true, false, 0x3F, 255, 255, 255}; // Structure/union for Characteristic IOr4 |
prussell | 12:8bac5f5d3a3e | 228 | // sIOr4.s.bB1p, sIOr4.s.bB1p, sIOr4.s.uB1p, sIOr4.s.bB1r, sIOr4.s.uB2p, sIOr4.s.uB2r, sIOr4.pu |
prussell | 12:8bac5f5d3a3e | 229 | |
prussell | 12:8bac5f5d3a3e | 230 | union { // Option: Shorten content to reduce BLE power and traffic |
prussell | 12:8bac5f5d3a3e | 231 | struct {// First item in union defines the initializers |
prussell | 12:8bac5f5d3a3e | 232 | uint8_t bB1p:1,bB2p:1; // Button status, 1/true=Pressed, bit1==Button1, bit2==Button2 |
prussell | 12:8bac5f5d3a3e | 233 | uint8_t uB1p:6; // Count Button2 Presses (6bit) *Notify* |
prussell | 12:8bac5f5d3a3e | 234 | uint8_t uB2r; // Count Button2 Releases *Notify* |
prussell | 12:8bac5f5d3a3e | 235 | int16_t iTempC100; // Temperature in hundreths of 'C (i.e. float = iTempC10/100) |
prussell | 12:8bac5f5d3a3e | 236 | // // Option: ADC or other inputs or device status |
prussell | 12:8bac5f5d3a3e | 237 | } s; |
prussell | 12:8bac5f5d3a3e | 238 | uint8_t pu[]; //Direct Byte access |
prussell | 12:8bac5f5d3a3e | 239 | char pc[]; //Character Access (No Terminating Null) |
prussell | 12:8bac5f5d3a3e | 240 | } sIOn4 = { false, true, 0x3F, 255, -2345/*=-23.45'C*/}; // Structure/union for Characteristic IOn4 |
prussell | 12:8bac5f5d3a3e | 241 | // sIOn4.s.bB1p, sIOn4.s.bB2p, sIOn4.s.uB1p, sIOn4.s.uB2r, sIOn4.s.iTempC100, sIOn4.pu |
prussell | 9:2d11beda333f | 242 | |
prussell | 9:2d11beda333f | 243 | //x GattCharacteristic::GattAttribute *descriptors[]; //How Set Characteristic Descriptors? Maybe in the App is easier? |
prussell | 9:2d11beda333f | 244 | |
prussell | 10:ee3a359f7d3f | 245 | //IO Characteristics: //GattCharacteristics xx(*UUID, *Payload=*Value, LenInit, LenMax, Properties) |
prussell | 10:ee3a359f7d3f | 246 | //GattCharacteristic IOw8(puUUID128_IOw8, pIOw8, sizeof(pIOw8), sizeof(pIOw8), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE); |
prussell | 12:8bac5f5d3a3e | 247 | GattCharacteristic IOw8(puUUID128_IOw8, sIOw8.pu, sizeof(sIOw8), sizeof(sIOw8), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);// Allow Host to read back last setting |
prussell | 12:8bac5f5d3a3e | 248 | GattCharacteristic IOr4(puUUID128_IOr4, sIOr4.pu, sizeof(sIOr4), sizeof(sIOr4), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); // Host can manually request |
prussell | 10:ee3a359f7d3f | 249 | //GattCharacteristic IOn4(puUUID128_IOn4, pIOn4, sizeof(pIOn4), sizeof(pIOn4), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); |
prussell | 12:8bac5f5d3a3e | 250 | GattCharacteristic IOn4(puUUID128_IOn4, sIOn4.pu, sizeof(sIOn4), sizeof(sIOn4), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); // Host is notified of changes |
prussell | 12:8bac5f5d3a3e | 251 | GattCharacteristic *pCustomCharacteristics[] = {&IOw8, &IOr4, &IOn4};//Table of Pointers to GattCharacteristics |
prussell | 10:ee3a359f7d3f | 252 | |
prussell | 10:ee3a359f7d3f | 253 | //IO Service: //GattService::GattService(*UUID, *GattCharacteristics, (numCharacteristics) ) : |
prussell | 10:ee3a359f7d3f | 254 | GattService ServiceIO(puUUID128_IOService, pCustomCharacteristics, (sizeof(pCustomCharacteristics)/sizeof(pCustomCharacteristics[0]))); |
prussell | 10:ee3a359f7d3f | 255 | GattService *pServiceIO= &ServiceIO; // Pointer to Service |
prussell | 9:2d11beda333f | 256 | |
prussell | 12:8bac5f5d3a3e | 257 | //========== Functions for IO Characteristics ======== |
prussell | 12:8bac5f5d3a3e | 258 | void vShowIO(void) |
prussell | 12:8bac5f5d3a3e | 259 | { //TODO: For Read Characteristics get data actually written to Characteristic, versus the memory expected to be in characteristic. |
prussell | 12:8bac5f5d3a3e | 260 | uint8_t puBuf8[8]; |
prussell | 12:8bac5f5d3a3e | 261 | uint16_t uLen; |
prussell | 12:8bac5f5d3a3e | 262 | |
prussell | 12:8bac5f5d3a3e | 263 | DEBUG(" ShowIO:\n"); |
prussell | 12:8bac5f5d3a3e | 264 | |
prussell | 12:8bac5f5d3a3e | 265 | // IOw8 Write |
prussell | 16:3e83f2babdfb | 266 | uLen=sizeof(puBuf8); ble.readCharacteristicValue(IOw8.getValueHandle(), puBuf8, &uLen); // Real Characteristic's Actual Value |
prussell | 12:8bac5f5d3a3e | 267 | DEBUG(" sIOw8: Handle:%d Len:%d L1:%d L2:%d %04X %04X %04X\n", IOw8.getValueHandle(), uLen, sIOw8.s.L1pwm100, sIOw8.s.L2pwm255, sIOw8.s.px[0], sIOw8.s.px[0], sIOw8.s.px[0]); |
prussell | 12:8bac5f5d3a3e | 268 | //DEBUG(" pIOw8: Handle:%d Len:%d [%02X %02X %02X %02X %02X %02X %02X %02X]\n", IOw8.getValueHandle(), sizeof(pIOw8), pIOw8[0], pIOw8[1], pIOw8[2], pIOw8[3],pIOw8[4], pIOw8[5], pIOw8[6], pIOw8[7]); |
prussell | 12:8bac5f5d3a3e | 269 | DEBUG(" sIOw8: Handle:%d Len:%d [%02X %02X %02X %02X %02X %02X %02X %02X]\n", IOw8.getValueHandle(), sizeof(sIOw8), sIOw8.pu[0],sIOw8.pu[1],sIOw8.pu[2],sIOw8.pu[3],sIOw8.pu[4],sIOw8.pu[5],sIOw8.pu[6],sIOw8.pu[7]); |
prussell | 12:8bac5f5d3a3e | 270 | DEBUG(" cIOw8: Handle:%d Len:%d [%02X %02X %02X %02X %02X %02X %02X %02X]\n", IOw8.getValueHandle(), uLen, puBuf8[0], puBuf8[1], puBuf8[2], puBuf8[3], puBuf8[4], puBuf8[5], puBuf8[6], puBuf8[7] ); |
prussell | 12:8bac5f5d3a3e | 271 | |
prussell | 12:8bac5f5d3a3e | 272 | // IOr4 Read |
prussell | 16:3e83f2babdfb | 273 | uLen=sizeof(puBuf8); ble.readCharacteristicValue(IOr4.getValueHandle(), puBuf8, &uLen); // Real Characteristic's Actual Value |
prussell | 12:8bac5f5d3a3e | 274 | DEBUG("\n sIOr4: Handle:%d Len:%d B1:%d B2:%d B1p:%d B1r:%d B2p:%d B2r:%d\n", IOr4.getValueHandle(), uLen, sIOr4.s.bB1p, sIOr4.s.bB2p, sIOr4.s.uB1p, sIOr4.s.uB1r, sIOr4.s.uB2p, sIOr4.s.uB2r); |
prussell | 12:8bac5f5d3a3e | 275 | //DEBUG(" pIOr4: Handle:%d Len:%d [%02X %02X %02X %02X]\n", IOr4.getValueHandle(), sizeof(pIOr4), pIOr4[0], pIOr4[1], pIOr4[2], pIOr4[3]); |
prussell | 12:8bac5f5d3a3e | 276 | //DEBUG(" sIOr4: Handle:%d Len:%d [%02X %02X %02X %02X][%.4s]\n", IOr4.getValueHandle(), sizeof(sIOr4), sIOr4.pu[0], sIOr4.pu[1], sIOr4.pu[2], sIOr4.pu[3], sIOr4.pc ); |
prussell | 12:8bac5f5d3a3e | 277 | DEBUG(" sIOr4: Handle:%d Len:%d [%02X %02X %02X %02X]\n", IOr4.getValueHandle(), sizeof(sIOr4), sIOr4.pu[0], sIOr4.pu[1], sIOr4.pu[2], sIOr4.pu[3]); |
prussell | 12:8bac5f5d3a3e | 278 | // Read Actual IOr4 Characteristic's data back from Service (i.e. last written to service): |
prussell | 12:8bac5f5d3a3e | 279 | DEBUG(" cIOr4: Handle:%d Len:%d [%02X %02X %02X %02X]\n", IOr4.getValueHandle(), uLen, puBuf8[0], puBuf8[1], puBuf8[2], puBuf8[3] ); |
prussell | 12:8bac5f5d3a3e | 280 | |
prussell | 12:8bac5f5d3a3e | 281 | // IOn4 Notify |
prussell | 16:3e83f2babdfb | 282 | uLen=sizeof(puBuf8); ble.readCharacteristicValue(IOn4.getValueHandle(), puBuf8, &uLen); // Real Characteristic's Actual Value |
prussell | 12:8bac5f5d3a3e | 283 | DEBUG("\n sIOn4: Handle:%d Len:%d B1:%d B2:%d B1p:%d B2r:%d %.2f\n", IOn4.getValueHandle(), uLen, sIOn4.s.bB1p, sIOn4.s.bB2p, sIOn4.s.uB1p, sIOn4.s.uB2r, ((float)sIOn4.s.iTempC100/100.0)); |
prussell | 12:8bac5f5d3a3e | 284 | //DEBUG("\n pIOn4: Handle:%d Len:%d [%02X %02X %02X %02X]\n", IOn4.getValueHandle(), sizeof(pIOn4), pIOn4[0], pIOn4[1], pIOn4[2], pIOn4[3]); |
prussell | 12:8bac5f5d3a3e | 285 | DEBUG(" sIOn4: Handle:%d Len:%d [%02X %02X %02X %02X]\n", IOn4.getValueHandle(), sizeof(sIOn4), sIOn4.pu[0], sIOn4.pu[1], sIOn4.pu[2], sIOn4.pu[3]); |
prussell | 12:8bac5f5d3a3e | 286 | DEBUG(" cIOn4: Handle:%d Len:%d [%02X %02X %02X %02X]\n", IOn4.getValueHandle(), uLen, puBuf8[0], puBuf8[1], puBuf8[2], puBuf8[3] ); |
prussell | 15:b2c8bdef2d20 | 287 | |
prussell | 15:b2c8bdef2d20 | 288 | //DEBUG("\n Handles for Standard Services' Characteristics:\n"); |
prussell | 15:b2c8bdef2d20 | 289 | //DEBUG(" HRM: Rate:%d Location:%d Control:%d", pServiceHRM->getCharacteristic(0)->getValueHandle(),pServiceHRM->getCharacteristic(1)->getValueHandle(),pServiceHRM->getCharacteristic(2)->getValueHandle()); |
prussell | 15:b2c8bdef2d20 | 290 | //DEBUG(" HTM: Temp:%d Type:%d", pServiceHTM->getCharacteristic(0)->getValueHandle(),pServiceHTM->getCharacteristic(1)->getValueHandle()); |
prussell | 15:b2c8bdef2d20 | 291 | //DEBUG(" Batt: Level:%d", pServiceBattery->getCharacteristic(0)->getHandle()); |
prussell | 15:b2c8bdef2d20 | 292 | //DEBUG(" DeviceInfo: %d~%d", pServiceDeviceInfo->getCharacteristic(0)->getHandle(), pServiceDeviceInfo->getCharacteristic(5)->getHandle()); |
prussell | 15:b2c8bdef2d20 | 293 | //DEBUG(" LinkLoss: AlertLevel:%d", pServiceLinkLoss->getCharacteristic(0)->getHandle()); |
prussell | 15:b2c8bdef2d20 | 294 | //DEBUG(" DFU:%d", pServiceDFU.getValueAttribute().getHandle()); |
prussell | 15:b2c8bdef2d20 | 295 | //DEBUG(" UART:%d\n", pServiceUART.getValueAttribute().getHandle()); |
prussell | 12:8bac5f5d3a3e | 296 | } |
prussell | 12:8bac5f5d3a3e | 297 | |
prussell | 12:8bac5f5d3a3e | 298 | //==== Soft Updates to Characteristics for initial tests: (Most replaced by real buttons/sensors/timers ) |
prussell | 10:ee3a359f7d3f | 299 | /*void vUpdate_IOw8(void) // Handle in device changes to w8 characteristic |
prussell | 12:8bac5f5d3a3e | 300 | {//a Option: Allow device to modify its settings and inform host (Some devices may be able to self-modify host written settings) |
prussell | 10:ee3a359f7d3f | 301 | static uint8_t uw8; //Level: 0..2 |
prussell | 10:ee3a359f7d3f | 302 | switch(++uw8){ |
prussell | 10:ee3a359f7d3f | 303 | case 2: memcpy(pIOw8, "w2w2w2wc", sizeof(pIOw8)); DEBUG(" w8c"); break; |
prussell | 10:ee3a359f7d3f | 304 | case 1: memcpy(pIOw8, "w1w1w1wb", sizeof(pIOw8)); DEBUG(" w8b"); break; |
prussell | 10:ee3a359f7d3f | 305 | default: uw8=0; memcpy(pIOw8, "w0w0w0wa", sizeof(pIOw8)); DEBUG(" w8a"); break; |
prussell | 9:2d11beda333f | 306 | } |
prussell | 10:ee3a359f7d3f | 307 | //ble.updateCharacteristicValue(uint16_t handle, const uint8_t *value, uint16_t size, bool localOnly) |
prussell | 10:ee3a359f7d3f | 308 | ble.updateCharacteristicValue(IOw8.getValueHandle(), pIOw8, sizeof(pIOw8)); |
prussell | 9:2d11beda333f | 309 | //pServiceHRM->updateHeartRate( u8_hrm );// Update Characteristic so sent by BLE |
prussell | 12:8bac5f5d3a3e | 310 | vShowIO(); |
prussell | 10:ee3a359f7d3f | 311 | }*/ |
prussell | 10:ee3a359f7d3f | 312 | |
prussell | 12:8bac5f5d3a3e | 313 | //==== Hard Updates to Characteristics: [onButton()] Notify: B1press or B2release |
prussell | 12:8bac5f5d3a3e | 314 | // *When direct driving hardware consider adjusting drive within the onCallback to reduce response time |
prussell | 12:8bac5f5d3a3e | 315 | //TODO: Check need of volatile for changes in interrupts affecting variables in non-interrupt code? |
prussell | 12:8bac5f5d3a3e | 316 | |
prussell | 12:8bac5f5d3a3e | 317 | volatile uint8_t uB1press; // Events since last handled in main() |
prussell | 12:8bac5f5d3a3e | 318 | volatile uint8_t uB1release;// Events since last handled in main() |
prussell | 12:8bac5f5d3a3e | 319 | volatile uint8_t uB2press; // Events since last handled in main() |
prussell | 12:8bac5f5d3a3e | 320 | volatile uint8_t uB2release;// Events since last handled in main() |
prussell | 12:8bac5f5d3a3e | 321 | |
prussell | 12:8bac5f5d3a3e | 322 | void vFillIO(void) // Fill the structures for the Characteristics, but leave any Notify to calling function |
prussell | 12:8bac5f5d3a3e | 323 | { //Structures are filled completely so available for BLE read at any time |
prussell | 12:8bac5f5d3a3e | 324 | // sIOr4.s.bB1p, sIOr4.s.bB1p, sIOr4.s.uB1p, sIOr4.s.bB1r, sIOr4.s.uB2p, sIOr4.s.uB2r, sIOr4.pu |
prussell | 12:8bac5f5d3a3e | 325 | sIOr4.s.bB1p = !bB1in; //Button1 Pressed (nRF51822 mkit: Pressed=Lo) |
prussell | 12:8bac5f5d3a3e | 326 | sIOr4.s.bB2p = !bB2in; //Button2 Pressed (nRF51822 mkit: Pressed=Lo) |
prussell | 12:8bac5f5d3a3e | 327 | sIOr4.s.uB1p = uB1press;// Button1 Presses (Truncates to size) |
prussell | 12:8bac5f5d3a3e | 328 | sIOr4.s.uB1r = uB1release; |
prussell | 12:8bac5f5d3a3e | 329 | sIOr4.s.uB2p = uB2press; |
prussell | 12:8bac5f5d3a3e | 330 | sIOr4.s.uB2r = uB2release; |
prussell | 12:8bac5f5d3a3e | 331 | |
prussell | 12:8bac5f5d3a3e | 332 | // sIOn4.s.bB1p, sIOn4.s.bB2p, sIOn4.s.uB1p, sIOn4.s.uB2r, sIOn4.s.iTempC100, sIOn4.pu |
prussell | 12:8bac5f5d3a3e | 333 | sIOn4.s.bB1p = !bB1in; //Button1 Pressed (nRF51822 mkit: Pressed=Lo) |
prussell | 12:8bac5f5d3a3e | 334 | sIOn4.s.bB2p = !bB2in; //Button2 Pressed (nRF51822 mkit: Pressed=Lo) |
prussell | 12:8bac5f5d3a3e | 335 | sIOn4.s.uB1p = uB1press;//Button1 Presses (Truncates to size) |
prussell | 12:8bac5f5d3a3e | 336 | sIOn4.s.uB2r = uB2release; |
prussell | 12:8bac5f5d3a3e | 337 | |
prussell | 12:8bac5f5d3a3e | 338 | int32_t i32_C_nRF; sd_temp_get(&i32_C_nRF); //Read the nRF Internal Temperature (Die in 0.25'C steps, offset +16'C) |
prussell | 12:8bac5f5d3a3e | 339 | sIOn4.s.iTempC100 = (i32_C_nRF*25)-(1600); //Save temperature in hundreths (0.01'C steps relative to 0'C)(.25'C * 25=.01'C steps) |
prussell | 12:8bac5f5d3a3e | 340 | //float fTemperature = (float(i32_temp)/4.0) - 16.0; // Scale&Shift (0.25'C from -16'C?) |
prussell | 9:2d11beda333f | 341 | } |
prussell | 9:2d11beda333f | 342 | |
prussell | 12:8bac5f5d3a3e | 343 | void onB1press(void) // B1 Press == *Notify* |
prussell | 12:8bac5f5d3a3e | 344 | { // Update Characteristics that include this button |
prussell | 12:8bac5f5d3a3e | 345 | uB1press++; // Flag/Count Events (allows detect any missed processing) |
prussell | 12:8bac5f5d3a3e | 346 | vFillIO(); // Prepare IO Characteristic data |
prussell | 12:8bac5f5d3a3e | 347 | ble.updateCharacteristicValue(IOn4.getValueHandle(), sIOn4.pu, sizeof(sIOn4));// Notify |
prussell | 12:8bac5f5d3a3e | 348 | DEBUG("\n B1p%d", uB1press); vShowIO(); |
prussell | 12:8bac5f5d3a3e | 349 | }; |
prussell | 12:8bac5f5d3a3e | 350 | void onB1release(void) // B1 Release |
prussell | 12:8bac5f5d3a3e | 351 | { // Update Characteristics that include this button |
prussell | 12:8bac5f5d3a3e | 352 | uB1release++; // Flag/Count Events (allows detect any missed processing) |
prussell | 12:8bac5f5d3a3e | 353 | vFillIO(); // Prepare IO Characteristic data |
prussell | 12:8bac5f5d3a3e | 354 | ble.updateCharacteristicValue(IOr4.getValueHandle(), sIOr4.pu, sizeof(sIOr4)); |
prussell | 12:8bac5f5d3a3e | 355 | DEBUG("\n B1r%d", uB1release); vShowIO(); |
prussell | 12:8bac5f5d3a3e | 356 | }; |
prussell | 12:8bac5f5d3a3e | 357 | void onB2press(void) // B2 Press |
prussell | 12:8bac5f5d3a3e | 358 | { // Update Characteristics that include this button |
prussell | 12:8bac5f5d3a3e | 359 | uB2press++; // Flag/Count Events (allows detect any missed processing) |
prussell | 12:8bac5f5d3a3e | 360 | vFillIO(); // Prepare IO Characteristic data |
prussell | 12:8bac5f5d3a3e | 361 | ble.updateCharacteristicValue(IOr4.getValueHandle(), sIOr4.pu, sizeof(sIOr4)); |
prussell | 12:8bac5f5d3a3e | 362 | DEBUG("\n B2p%d", uB2press); vShowIO(); |
prussell | 12:8bac5f5d3a3e | 363 | }; |
prussell | 12:8bac5f5d3a3e | 364 | void onB2release(void) // B2 Release |
prussell | 12:8bac5f5d3a3e | 365 | { // Update Characteristics that include this button |
prussell | 12:8bac5f5d3a3e | 366 | uB2release++; // Flag/Count Events (allows detect any missed processing) |
prussell | 12:8bac5f5d3a3e | 367 | vFillIO(); // Prepare IO Characteristic data |
prussell | 12:8bac5f5d3a3e | 368 | ble.updateCharacteristicValue(IOn4.getValueHandle(), sIOn4.pu, sizeof(sIOn4));// Notify |
prussell | 12:8bac5f5d3a3e | 369 | DEBUG("\n B2r%d", uB2release); vShowIO(); |
prussell | 12:8bac5f5d3a3e | 370 | }; |
prussell | 9:2d11beda333f | 371 | |
prussell | 0:0217a862b047 | 372 | //==========Functions:BLE========== |
prussell | 0:0217a862b047 | 373 | void Callback_BLE_onTimeout(void) |
prussell | 10:ee3a359f7d3f | 374 | { //PR: Haven't seen this, even when phone moved out of range and events occur like OnDisconnect(Reason0x08) or LinkLoss |
prussell | 12:8bac5f5d3a3e | 375 | DEBUG("\n\n\n\n**** BLEi: Callback_BLE_onTimeout() ****\n\n\n\n" ); |
prussell | 0:0217a862b047 | 376 | |
prussell | 0:0217a862b047 | 377 | //DEBUG("\nBLE:Callback_BLE_onTimeout(), Restarting Advertising\n" ); |
prussell | 0:0217a862b047 | 378 | //ble.startAdvertising(); |
prussell | 0:0217a862b047 | 379 | } |
prussell | 0:0217a862b047 | 380 | |
prussell | 0:0217a862b047 | 381 | void Callback_BLE_onDisconnect(Gap::Handle_t tHandle, Gap::DisconnectionReason_t eReason) |
prussell | 10:ee3a359f7d3f | 382 | { //PR: onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range |
prussell | 0:0217a862b047 | 383 | |
prussell | 0:0217a862b047 | 384 | // REMOTE_USER_TERMINATED_CONNECTION = 0x13 = 19, |
prussell | 0:0217a862b047 | 385 | // LOCAL_HOST_TERMINATED_CONNECTION = 0x16 = 22, |
prussell | 0:0217a862b047 | 386 | // CONN_INTERVAL_UNACCEPTABLE = 0x3B = 59, |
prussell | 0:0217a862b047 | 387 | 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 | 388 | |
prussell | 0:0217a862b047 | 389 | //DEBUG("Wait10sec...\n");wait(10.0); //PR: Optional to test effect on advertising |
prussell | 0:0217a862b047 | 390 | ble.startAdvertising(); // restart advertising |
prussell | 0:0217a862b047 | 391 | } |
prussell | 0:0217a862b047 | 392 | |
prussell | 0:0217a862b047 | 393 | 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 | 394 | { |
prussell | 0:0217a862b047 | 395 | DEBUG("\nBLEi: Callback_BLE_Connect(Handle:%d, eType:%d, Add:%u ...)\n", tHandle, ePeerAddrType, c6PeerAddr); |
prussell | 0:0217a862b047 | 396 | |
prussell | 11:7d02fe5ebea5 | 397 | //x #if ENABLE_BLE_SLOW //UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL //PR: Adopted optional code never tested |
prussell | 11:7d02fe5ebea5 | 398 | //x // Updating connection parameters can be attempted only after a connection has been |
prussell | 11:7d02fe5ebea5 | 399 | //x // established. Please note that the ble-Central is still the final arbiter for |
prussell | 11:7d02fe5ebea5 | 400 | //x // the effective parameters; the peripheral can only hope that the request is |
prussell | 11:7d02fe5ebea5 | 401 | //x // honored. Please also be mindful of the constraints that might be enforced by |
prussell | 11:7d02fe5ebea5 | 402 | //x // the BLE stack on the underlying controller. |
prussell | 11:7d02fe5ebea5 | 403 | //x #define MIN_CONN_INTERVAL 250 // Minimum connection interval (250 ms) |
prussell | 11:7d02fe5ebea5 | 404 | //x #define MAX_CONN_INTERVAL 350 // Maximum connection interval (350 ms) |
prussell | 11:7d02fe5ebea5 | 405 | //x #define CONN_SUP_TIMEOUT 6000 // Connection supervisory timeout (6 seconds) |
prussell | 11:7d02fe5ebea5 | 406 | //x #define SLAVE_LATENCY 4 |
prussell | 11:7d02fe5ebea5 | 407 | //x Gap::ConnectionParams_t tGap_conn_params; |
prussell | 11:7d02fe5ebea5 | 408 | //x tGap_conn_params.minConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MIN_CONN_INTERVAL); |
prussell | 11:7d02fe5ebea5 | 409 | //x tGap_conn_params.maxConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MAX_CONN_INTERVAL); |
prussell | 11:7d02fe5ebea5 | 410 | //x tGap_conn_params.connectionSupervisionTimeout = Gap::MSEC_TO_GAP_DURATION_UNITS(CONN_SUP_TIMEOUT); |
prussell | 11:7d02fe5ebea5 | 411 | //x tGap_conn_params.slaveLatency = SLAVE_LATENCY; |
prussell | 11:7d02fe5ebea5 | 412 | //x ble.updateConnectionParams(tHandle, &tGap_conn_params); |
prussell | 11:7d02fe5ebea5 | 413 | //x #endif // #if UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL |
prussell | 0:0217a862b047 | 414 | } |
prussell | 0:0217a862b047 | 415 | |
prussell | 12:8bac5f5d3a3e | 416 | static volatile bool bNotifySent = false; //Volatile, don't optimize, changes under interrupt control |
prussell | 12:8bac5f5d3a3e | 417 | static volatile unsigned uNotifyBLE; |
prussell | 12:8bac5f5d3a3e | 418 | void Callback_BLE_onNotifySent(unsigned uNotify) //TODO: Consider renaming to onNotifySent(uNotified) |
prussell | 12:8bac5f5d3a3e | 419 | { // Appears to get called when a Characteristic flagged for Notify is Updated/Sent (not for a characteristic being Read by the app). |
prussell | 12:8bac5f5d3a3e | 420 | uNotifyBLE=uNotify; |
prussell | 12:8bac5f5d3a3e | 421 | DEBUG(" Senti(%u)", uNotifyBLE); //TODO: PR: Why uSent always "1", expected it to match sent bytes length |
prussell | 12:8bac5f5d3a3e | 422 | bNotifySent = true; |
prussell | 0:0217a862b047 | 423 | } |
prussell | 0:0217a862b047 | 424 | |
prussell | 0:0217a862b047 | 425 | void Callback_BLE_onDataWritten(const GattCharacteristicWriteCBParams *pParams) |
prussell | 9:2d11beda333f | 426 | { // This occurs when use nRF-MCP to save a new Characteristic Value (SingleUpASrrowIcon) such as New Heart Rate Control Point (unsent if incorrect length) |
prussell | 9:2d11beda333f | 427 | GattAttribute::Handle_t tHandle=pParams->charHandle; |
prussell | 0:0217a862b047 | 428 | |
prussell | 0:0217a862b047 | 429 | //Warning: *data may not be NULL terminated |
prussell | 9:2d11beda333f | 430 | DEBUG("\nBLEi: Callback_BLE_onDataWritten(Handle:%d, eOp:%d, uOffset:%u uLen:%u Data0[0x%02x]=Data[%*s]\n", tHandle, pParams->op, pParams->offset, pParams->len, (char)(pParams->data[0]), pParams->len, pParams->data); |
prussell | 9:2d11beda333f | 431 | |
prussell | 10:ee3a359f7d3f | 432 | /* //TODO: Add check of op type with tHandle check: switch(pParams->op){ case: GATTS_CHAR_OP_WRITE_REQ:}... |
prussell | 10:ee3a359f7d3f | 433 | switch(pParams->op){ |
prussell | 10:ee3a359f7d3f | 434 | case GATTS_CHAR_OP_INVALID: |
prussell | 10:ee3a359f7d3f | 435 | case GATTS_CHAR_OP_WRITE_REQ |
prussell | 10:ee3a359f7d3f | 436 | case GATTS_CHAR_OP_WRITE_CMD |
prussell | 10:ee3a359f7d3f | 437 | case GATTS_CHAR_OP_SIGN_WRITE_CMD //< Signed Write Command |
prussell | 10:ee3a359f7d3f | 438 | case GATTS_CHAR_OP_PREP_WRITE_REQ //< Prepare Write Request |
prussell | 10:ee3a359f7d3f | 439 | case GATTS_CHAR_OP_EXEC_WRITE_REQ_CANCEL //< Execute Write Request: Cancel all prepared writes |
prussell | 10:ee3a359f7d3f | 440 | case GATTS_CHAR_OP_EXEC_WRITE_REQ_NOW //< Execute Write Request: Immediately execute all prepared writes |
prussell | 10:ee3a359f7d3f | 441 | default: Error? |
prussell | 10:ee3a359f7d3f | 442 | }*/ |
prussell | 9:2d11beda333f | 443 | |
prussell | 10:ee3a359f7d3f | 444 | //a These are equivalent ways of accessing characteristic handles: |
prussell | 10:ee3a359f7d3f | 445 | //a if (pParams->charHandle == IOw8.getValueHandle()) { DEBUG("\n\nOK tHandle %d\n\n", pParams->charHandle); } |
prussell | 10:ee3a359f7d3f | 446 | //a if (pParams->charHandle == ServiceIO.getCharacteristic(0)->getValueHandle()) { DEBUG("\n\nOK tHandle %d\n\n", pParams->charHandle); } |
prussell | 10:ee3a359f7d3f | 447 | //a if (IOw8.getValueHandle() == ServiceIO.getCharacteristic(0)->getValueHandle()) { DEBUG("\n\nOK tHandle equivalent %d\n\n", pParams->charHandle); } |
prussell | 9:2d11beda333f | 448 | |
prussell | 9:2d11beda333f | 449 | //Handle Changes to Service Characteristics: |
prussell | 10:ee3a359f7d3f | 450 | if(!ble.getGapState().connected){ //Ensure BLE still connected |
prussell | 10:ee3a359f7d3f | 451 | DEBUG("BLEi: Callback_BLE_onDataWritten() while disconnected!!"); |
prussell | 9:2d11beda333f | 452 | } else { |
prussell | 10:ee3a359f7d3f | 453 | uint16_t uLen; |
prussell | 10:ee3a359f7d3f | 454 | if (tHandle == IOw8.getValueHandle()) { // This occurs from Write by App nRF-MCP since has Write Property set |
prussell | 12:8bac5f5d3a3e | 455 | ble.readCharacteristicValue(tHandle, sIOw8.pu, &uLen); //Update Characteristic with new information (Option: Verify length or a checksum first) |
prussell | 12:8bac5f5d3a3e | 456 | vShowIO(); |
prussell | 12:8bac5f5d3a3e | 457 | |
prussell | 12:8bac5f5d3a3e | 458 | bAppControl = true; //Host has taken control of LEDs |
prussell | 12:8bac5f5d3a3e | 459 | fL1level = (((float)sIOw8.s.L1pwm100)/100.0); if(fL1level>1.0){fL1level=1.0;}; fL1pwm=fL1level; //Set LED1 Level |
prussell | 12:8bac5f5d3a3e | 460 | fL2level = (((float)sIOw8.s.L2pwm255)/255.0); if(fL2level>1.0){fL2level=1.0;}; fL2pwm=fL2level; //Set LED1 Level |
prussell | 12:8bac5f5d3a3e | 461 | DEBUG(" L1:%d==%f L2:%d==%f\n", sIOw8.s.L1pwm100, fL1level, sIOw8.s.L2pwm255, fL2level); |
prussell | 12:8bac5f5d3a3e | 462 | |
prussell | 11:7d02fe5ebea5 | 463 | //TODO: Update Outputs and settings: Direct LED Control or Output Control, Or Configuration (Includes flags for: Factory Reset, Enter Test Mode, Enter Demo Mode) |
prussell | 12:8bac5f5d3a3e | 464 | |
prussell | 11:7d02fe5ebea5 | 465 | //} else if (tHandle == IOr4.getValueHandle()) { // Readonly, shouldn't occur |
prussell | 10:ee3a359f7d3f | 466 | // ble.readCharacteristicValue(tHandle, pIOr4, &uLen); |
prussell | 10:ee3a359f7d3f | 467 | // DEBUG(" IOr4[%d]:%02X %02X %02X %02X\n", uLen, pIOr4[0], pIOr4[1], pIOr4[2], pIOr4[3]); |
prussell | 10:ee3a359f7d3f | 468 | // //TODO: Update Outputs |
prussell | 11:7d02fe5ebea5 | 469 | //} else if (tHandle == IOn4.getValueHandle()) { // Readonly, shouldn't occur |
prussell | 10:ee3a359f7d3f | 470 | // ble.readCharacteristicValue(tHandle, pIOn4, &uLen); |
prussell | 10:ee3a359f7d3f | 471 | // DEBUG(" IOn4[%d]:%02X %02X %02X %02X\n", uLen, pIOn4[0], pIOn4[1], pIOn4[2], pIOn4[3]); |
prussell | 10:ee3a359f7d3f | 472 | // //TODO: Update Outputs |
prussell | 10:ee3a359f7d3f | 473 | } else { |
prussell | 10:ee3a359f7d3f | 474 | DEBUG("\n Unknown onWrite(tHandle:%d)\n\n", tHandle); |
prussell | 10:ee3a359f7d3f | 475 | } |
prussell | 9:2d11beda333f | 476 | } |
prussell | 8:f187ba55aed2 | 477 | |
prussell | 10:ee3a359f7d3f | 478 | //LinkLoss: |
prussell | 10:ee3a359f7d3f | 479 | //x pServiceLinkLoss->setAlertLevel( AlertLevel_t newLevel ) |
prussell | 10:ee3a359f7d3f | 480 | //x Triggered by BluetoothLEGatt sample changing Linkloss setting: |
prussell | 10:ee3a359f7d3f | 481 | //x Alert=1: Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x01]=Data[]) |
prussell | 10:ee3a359f7d3f | 482 | //x Alert=2: Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x02]=Data[]) |
prussell | 8:f187ba55aed2 | 483 | |
prussell | 12:8bac5f5d3a3e | 484 | //vShowIO(); //Show IO Characteristic Status |
prussell | 0:0217a862b047 | 485 | } |
prussell | 0:0217a862b047 | 486 | |
prussell | 15:b2c8bdef2d20 | 487 | void Callback_BLE_onUpdatesEnabled(Gap::Handle_t tHandle) // Notifications |
prussell | 15:b2c8bdef2d20 | 488 | { //Triggered when click the UpdateContinuousIcon in nRF-MCP(ThreeDownArrows) |
prussell | 16:3e83f2babdfb | 489 | if (tHandle == IOn4.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Enabled - IOn4\n", tHandle); //This Occurs when selected by App nRF-MCP as has Notify property set |
prussell | 16:3e83f2babdfb | 490 | } else if (tHandle == IOr4.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Enabled - IOr4\n", tHandle); // Notify not enabled on this Characteristic |
prussell | 16:3e83f2babdfb | 491 | } else if (tHandle == IOw8.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Enabled - IOw8\n", tHandle); // Notify not enabled on this Characteristic |
prussell | 16:3e83f2babdfb | 492 | } else { DEBUG("\nBLEi: onUpdates(Handle:%d) Enabled - Characteristic?\n", tHandle); |
prussell | 15:b2c8bdef2d20 | 493 | } |
prussell | 16:3e83f2babdfb | 494 | //TODO: process Enable for Each Notify Characteriistic of each Service |
prussell | 15:b2c8bdef2d20 | 495 | } |
prussell | 15:b2c8bdef2d20 | 496 | |
prussell | 15:b2c8bdef2d20 | 497 | void Callback_BLE_onUpdatesDisabled(Gap::Handle_t tHandle) // Notifications |
prussell | 10:ee3a359f7d3f | 498 | { //Triggered when click the UpdateContinuousIcon in nRF-MCP(ThreeDownArrows) |
prussell | 16:3e83f2babdfb | 499 | if (tHandle == IOn4.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Disabled - IOn4\n", tHandle); //This Occurs when selected by App nRF-MCP as has Notify property set |
prussell | 16:3e83f2babdfb | 500 | } else if (tHandle == IOr4.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Disabled - IOr4\n", tHandle); // Notify not enabled on this Characteristic |
prussell | 16:3e83f2babdfb | 501 | } else if (tHandle == IOw8.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Disabled - IOw8\n", tHandle); // Notify not enabled on this Characteristic |
prussell | 16:3e83f2babdfb | 502 | } else { DEBUG("\nBLEi: onUpdates(Handle:%d) Disabled - Characteristic?\n", tHandle); |
prussell | 9:2d11beda333f | 503 | } |
prussell | 16:3e83f2babdfb | 504 | //TODO: process Disable for Each Notify Characteriistic of each Service |
prussell | 0:0217a862b047 | 505 | } |
prussell | 15:b2c8bdef2d20 | 506 | void Callback_BLE_onConfirmRx(Gap::Handle_t tHandle) // Confirmations?? |
prussell | 15:b2c8bdef2d20 | 507 | { |
prussell | 15:b2c8bdef2d20 | 508 | DEBUG("\nBLEi: ConfirmationRx(Handle:%d)\n", tHandle); |
prussell | 15:b2c8bdef2d20 | 509 | } |
prussell | 15:b2c8bdef2d20 | 510 | |
prussell | 0:0217a862b047 | 511 | |
prussell | 5:d36bbb315e31 | 512 | // Adopted 20141213 from http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_LinkLoss/file/440ee5e8595f/main.cpp |
prussell | 5:d36bbb315e31 | 513 | void Callback_BLE_onLinkLoss(LinkLossService::AlertLevel_t level) |
prussell | 5:d36bbb315e31 | 514 | { |
prussell | 10:ee3a359f7d3f | 515 | printf("\nBLEi: Link Loss Alert, Level:%d\n", level); |
prussell | 10:ee3a359f7d3f | 516 | //TODO: Handle Link Loss, maybe lower power mode and/or advertising mode |
prussell | 5:d36bbb315e31 | 517 | } |
prussell | 10:ee3a359f7d3f | 518 | //==========BLE:HRM========== |
prussell | 8:f187ba55aed2 | 519 | //Adopted 2014Dec from http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/ |
prussell | 8:f187ba55aed2 | 520 | uint8_t update_hrm(void)//(bool bInit) |
prussell | 8:f187ba55aed2 | 521 | { |
prussell | 8:f187ba55aed2 | 522 | static uint8_t u8_hrm = 100; |
prussell | 10:ee3a359f7d3f | 523 | if (++u8_hrm >= 175) { |
prussell | 8:f187ba55aed2 | 524 | u8_hrm = 100; |
prussell | 10:ee3a359f7d3f | 525 | DEBUG(" HRM>100"); |
prussell | 10:ee3a359f7d3f | 526 | } else { |
prussell | 10:ee3a359f7d3f | 527 | DEBUG(" HRM:%d", u8_hrm); |
prussell | 10:ee3a359f7d3f | 528 | } |
prussell | 8:f187ba55aed2 | 529 | pServiceHRM->updateHeartRate( u8_hrm );// Update Characteristic so sent by BLE |
prussell | 8:f187ba55aed2 | 530 | return(u8_hrm); |
prussell | 8:f187ba55aed2 | 531 | } |
prussell | 10:ee3a359f7d3f | 532 | //==========BLE:HTM(Using nRF Internal Temperature)========== |
prussell | 10:ee3a359f7d3f | 533 | // *If not using nRF51822 IC then change this to a simple counter like BLE:Battery section |
prussell | 10:ee3a359f7d3f | 534 | // Adopted 2014Dec from: https://developer.mbed.org/users/takafuminaka/code/BLE_HTM_by_InTempSensr/ |
prussell | 8:f187ba55aed2 | 535 | // Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml |
prussell | 8:f187ba55aed2 | 536 | // HTM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml |
prussell | 9:2d11beda333f | 537 | //****Although nRF-MCP displays float OK, the HTM Apps don't, it is likely IEEE format required like in the original project: BLE_HTM_by_InTempSensr |
prussell | 8:f187ba55aed2 | 538 | float update_htm(void) |
prussell | 8:f187ba55aed2 | 539 | { |
prussell | 8:f187ba55aed2 | 540 | //static float fTemperature = 0;//-123.456; |
prussell | 8:f187ba55aed2 | 541 | int32_t i32_temp; |
prussell | 12:8bac5f5d3a3e | 542 | sd_temp_get(&i32_temp); //Read the nRF Internal Temperature (Die in 0.25'C steps, Offset:TBD), TODO:Check Scaling |
prussell | 8:f187ba55aed2 | 543 | float fTemperature = (float(i32_temp)/4.0) - 16.0; // Scale&Shift (0.25'C from -16'C?) |
prussell | 8:f187ba55aed2 | 544 | |
prussell | 8:f187ba55aed2 | 545 | //{//Force to IEEE format to match needs of Apps like nRF-HTM and nRF-Toolbox:HTM |
prussell | 8:f187ba55aed2 | 546 | // 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 | 547 | // uint8_t exponent = 0xFE; //exponent is -2 |
prussell | 8:f187ba55aed2 | 548 | // uint32_t mantissa = (uint32_t)(fTemperature*100); |
prussell | 8:f187ba55aed2 | 549 | // uint32_t temp_ieee11073 = ((((uint32_t)exponent) << 24) | (mantissa)); //Note: Assumes Mantissa within 24bits |
prussell | 8:f187ba55aed2 | 550 | // memcpy(((uint8_t*)&fTemperature)+1, (uint8_t*)&temp_ieee11073, 4); //Overwrite with IEEE format float |
prussell | 8:f187ba55aed2 | 551 | //} |
prussell | 8:f187ba55aed2 | 552 | |
prussell | 8:f187ba55aed2 | 553 | pServiceHTM->updateTemperature( fTemperature );// Update Characteristic so sent by BLE |
prussell | 10:ee3a359f7d3f | 554 | DEBUG(" HTM%03d==%2.2f", i32_temp, fTemperature); |
prussell | 8:f187ba55aed2 | 555 | return(fTemperature); |
prussell | 8:f187ba55aed2 | 556 | } |
prussell | 10:ee3a359f7d3f | 557 | //==========BLE:Battery========== |
prussell | 8:f187ba55aed2 | 558 | uint8_t update_batt(void) |
prussell | 8:f187ba55aed2 | 559 | { |
prussell | 8:f187ba55aed2 | 560 | static uint8_t u8_BattPercent=33; //Level: 0..100% |
prussell | 8:f187ba55aed2 | 561 | u8_BattPercent <= 50 ? u8_BattPercent=100 : u8_BattPercent--; // Simulate Battery Decay |
prussell | 8:f187ba55aed2 | 562 | pServiceBattery->updateBatteryLevel( u8_BattPercent ); // Update Characteristic so sent by BLE |
prussell | 10:ee3a359f7d3f | 563 | DEBUG(" Batt%03d%%", u8_BattPercent); |
prussell | 8:f187ba55aed2 | 564 | return(u8_BattPercent); |
prussell | 8:f187ba55aed2 | 565 | } |
prussell | 9:2d11beda333f | 566 | |
prussell | 10:ee3a359f7d3f | 567 | //==========Functions:Timer========== |
prussell | 11:7d02fe5ebea5 | 568 | static volatile uint8_t uTicker1;//Volatile, don't optimize, changes under interrupt control |
prussell | 10:ee3a359f7d3f | 569 | void CallbackTicker1(void) |
prussell | 10:ee3a359f7d3f | 570 | { |
prussell | 11:7d02fe5ebea5 | 571 | static uint32_t u32_Counter; // Counter for checking Timing |
prussell | 11:7d02fe5ebea5 | 572 | DEBUG("\nBLEi: Ticker(%04u) ", ++u32_Counter); |
prussell | 12:8bac5f5d3a3e | 573 | if (!bAppControl) { fL1level+=0.1; if (fL1level>0.5){fL1level = 0.1;}; fL1pwm=fL1level;}//If host not controlling LED then ramp blink to show life |
prussell | 11:7d02fe5ebea5 | 574 | uTicker1++; // Flag event, using counter so can detect missed events |
prussell | 10:ee3a359f7d3f | 575 | } |
prussell | 11:7d02fe5ebea5 | 576 | |
prussell | 0:0217a862b047 | 577 | //==========main========== |
prussell | 0:0217a862b047 | 578 | int main(void) |
prussell | 12:8bac5f5d3a3e | 579 | { |
prussell | 14:b968df367145 | 580 | fL1level = 1.0; fL1pwm = fL1level;//Start LED1=OnMax |
prussell | 14:b968df367145 | 581 | fL2level = 0.2; fL2pwm = fL2level;//Start LED2=Dim |
prussell | 6:5b6fb35b4450 | 582 | |
prussell | 6:5b6fb35b4450 | 583 | //Restart TeraTerm just before Pressing Reset on mbed, 9600-8N1(No Flow Control) |
prussell | 6:5b6fb35b4450 | 584 | DEBUG("\nBLE: ___%s___\n", pcDeviceName); |
prussell | 14:b968df367145 | 585 | |
prussell | 14:b968df367145 | 586 | //ARM Predefines: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/BABJFEFG.html |
prussell | 14:b968df367145 | 587 | // *Some are numbers not strings so printf(%s) not always appropriate |
prussell | 14:b968df367145 | 588 | DEBUG(" ARM Compiler Predefines:\n"); |
prussell | 14:b968df367145 | 589 | DEBUG(" Built UTC:[ %s %s ]\n", __DATE__, __TIME__); |
prussell | 14:b968df367145 | 590 | DEBUG(" __arm__[%d]", __arm__); |
prussell | 14:b968df367145 | 591 | DEBUG(" __ARMCC_VERSION [%d]=[P:major V:minor bbbb:build]\n", __ARMCC_VERSION); |
prussell | 14:b968df367145 | 592 | DEBUG(" __VERSION__(gnu Compiler)[" __VERSION__ "]\n"); |
prussell | 14:b968df367145 | 593 | //DEBUG(" __STDC_VERSION__ [%d]\n", __STDC_VERSION__); |
prussell | 14:b968df367145 | 594 | //DEBUG(" __BIG_ENDIAN[%d] ", __BIG_ENDIAN); |
prussell | 14:b968df367145 | 595 | DEBUG(" __OPTIMISE_LEVEL[%d]", __OPTIMISE_LEVEL); |
prussell | 14:b968df367145 | 596 | //DEBUG(" __OPTIMISE_SPACE[%d]", __OPTIMISE_SPACE); |
prussell | 14:b968df367145 | 597 | DEBUG(" __OPTIMISE_TIME[%d]", __OPTIMISE_TIME); |
prussell | 14:b968df367145 | 598 | DEBUG("\n __MODULE__[" __MODULE__ "] __FILE__[" __FILE__ "] __BASE_FILE__[" __BASE_FILE__ "]\n"); |
prussell | 14:b968df367145 | 599 | DEBUG(" __FUNCTION__[%s] __PRETTY_FUNCTION__[%s]\n", __FUNCTION__, __PRETTY_FUNCTION__) |
prussell | 14:b968df367145 | 600 | |
prussell | 15:b2c8bdef2d20 | 601 | //vShowIO(); Show Raw initialized values before any BLE |
prussell | 0:0217a862b047 | 602 | |
prussell | 0:0217a862b047 | 603 | Ticker ticker1; //PR: Timer Object(Structure) |
prussell | 12:8bac5f5d3a3e | 604 | ticker1.attach(CallbackTicker1, 5.0); //PR: Timer Handler, Float=PeriodSeconds (Note BLE default wakes about 50Hz/20msec) |
prussell | 0:0217a862b047 | 605 | |
prussell | 3:a98203f84063 | 606 | //BLE1: Setup BLE Service (and event actions) //TODO: Check for services declared before main() - Is that OK? |
prussell | 14:b968df367145 | 607 | DEBUG("\nBLE: Connect App for Data: nRF-MCP, nRF-Toolbox:HRM/HTM, Android Sample BluetoothLeGatt, etc.\n"); |
prussell | 14:b968df367145 | 608 | DEBUG(" nRF-MCP: App->mbed: LinkLoss->AlertLevel(UpArrow)\n"); |
prussell | 14:b968df367145 | 609 | DEBUG(" nRF-MCP: App->mbed: BatteryService->BatteryLevel(DownArrow)\n"); |
prussell | 14:b968df367145 | 610 | DEBUG(" nRF-MCP: mbed->App: BatteryService->BatteryLevel->EnableNotify(ThreeDownArrows), Also App Acks the send=DEBUG('SentI')\n"); |
prussell | 14:b968df367145 | 611 | |
prussell | 3:a98203f84063 | 612 | DEBUG("BLE: Setup BLE\n"); |
prussell | 0:0217a862b047 | 613 | ble.init(); |
prussell | 12:8bac5f5d3a3e | 614 | ble.onDisconnection(Callback_BLE_onDisconnect); //PR: Host disconnects, restart advertising, clear any unnecessary functions to save power |
prussell | 12:8bac5f5d3a3e | 615 | ble.onConnection(Callback_BLE_onConnect); //PR: Host connects (Not required if no actions enabled, enabled now just for debug) |
prussell | 12:8bac5f5d3a3e | 616 | ble.onDataSent(Callback_BLE_onNotifySent); //PR: Occurs when a Notify Characteristic has been updated and sent over BLE |
prussell | 12:8bac5f5d3a3e | 617 | ble.onDataWritten(Callback_BLE_onDataWritten); //PR: Occurs when an update to a Characteristic has been received over BLE |
prussell | 12:8bac5f5d3a3e | 618 | ble.onTimeout(Callback_BLE_onTimeout); //PR: ??? Hasn't occured, TODO: Monitor and find out what causes this |
prussell | 12:8bac5f5d3a3e | 619 | ble.onUpdatesEnabled(Callback_BLE_onUpdatesEnabled);//PR: Occurs when host enables notify on a Characteristic that has Notify property set |
prussell | 15:b2c8bdef2d20 | 620 | ble.onUpdatesDisabled(Callback_BLE_onUpdatesDisabled); //TODO: |
prussell | 15:b2c8bdef2d20 | 621 | ble.onConfirmationReceived(Callback_BLE_onConfirmRx); //TODO: |
prussell | 12:8bac5f5d3a3e | 622 | //ble.onDataRead(Callback_BLE_onDataRead) //TODO: Need a callback for when reading data so can ensure characteristic is fully up to data before it is passed back (For now update periodically) |
prussell | 8:f187ba55aed2 | 623 | |
prussell | 6:5b6fb35b4450 | 624 | //BLE2: Setup Services (with their initial values and options) |
prussell | 3:a98203f84063 | 625 | DEBUG("BLE: Setup Services\n"); |
prussell | 4:976394791d7a | 626 | // *Order here affects order in nRF-MCP Discovery of Services |
prussell | 8:f187ba55aed2 | 627 | DeviceInformationService ServiceDeviceInfo(ble, "Maker", pcDeviceName, "sn1234", "hw00", "fw00", "sw00");//(BLEDevice), pcManufacturer, pcModelNumber, pcSerialNumber, pcHWver, pcFWver, pcSWver |
prussell | 9:2d11beda333f | 628 | pServiceDeviceInfo = &ServiceDeviceInfo; //DEBUG(" Handle Service DeviceInfo:%d\n", ServiceDeviceInfo.XXXgetHandle()); |
prussell | 8:f187ba55aed2 | 629 | LinkLossService ServiceLinkLoss(ble, Callback_BLE_onLinkLoss, LinkLossService::HIGH_ALERT); //New20141213, TBD |
prussell | 8:f187ba55aed2 | 630 | pServiceLinkLoss = &ServiceLinkLoss; |
prussell | 8:f187ba55aed2 | 631 | BatteryService ServiceBattery(ble, 10); |
prussell | 8:f187ba55aed2 | 632 | pServiceBattery = &ServiceBattery; |
prussell | 8:f187ba55aed2 | 633 | HeartRateService ServiceHRM(ble, (uint8_t)111, HeartRateService::LOCATION_FINGER); |
prussell | 8:f187ba55aed2 | 634 | pServiceHRM = &ServiceHRM; |
prussell | 8:f187ba55aed2 | 635 | HealthThermometerService ServiceHTM(ble, 33.3, HealthThermometerService::LOCATION_EAR); |
prussell | 8:f187ba55aed2 | 636 | pServiceHTM = &ServiceHTM; |
prussell | 8:f187ba55aed2 | 637 | //UARTService ServiceUART(ble); |
prussell | 8:f187ba55aed2 | 638 | // pServiceUART = &ServiceUART; |
prussell | 5:d36bbb315e31 | 639 | |
prussell | 12:8bac5f5d3a3e | 640 | DEBUG("BLE: Setup Custom IO Service\n"); |
prussell | 10:ee3a359f7d3f | 641 | ble.addService(ServiceIO); //Pointer: pServiceIO |
prussell | 15:b2c8bdef2d20 | 642 | vShowIO(); // Show Initialized values with bleIO initialized (includes tHandle) |
prussell | 12:8bac5f5d3a3e | 643 | //TODO: Ensure outputs in correct Initial state |
prussell | 9:2d11beda333f | 644 | |
prussell | 3:a98203f84063 | 645 | //BLE3: Setup advertising |
prussell | 10:ee3a359f7d3f | 646 | // 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 | 10:ee3a359f7d3f | 647 | // If there isn't enough space, then the accumulate payload won't add that block to the advertising, it won't add a partial block, and if name last then device shows as unnamed in App. |
prussell | 9:2d11beda333f | 648 | DEBUG("BLE: Setup Advertising - Apps like HRM/HTM/UART require matching UUID\n"); |
prussell | 6:5b6fb35b4450 | 649 | ble.clearAdvertisingPayload(); //Prep |
prussell | 6:5b6fb35b4450 | 650 | ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); //PR: Advertise 1sec (1Hz) |
prussell | 6:5b6fb35b4450 | 651 | ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); //PR: TODO: To Study |
prussell | 6:5b6fb35b4450 | 652 | ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); //PR: BLE Only (Option:LE_LIMITED_DISCOVERABLE) |
prussell | 6:5b6fb35b4450 | 653 | // Does "LE_GENERAL_DISCOVERABLE" affect whether UUID needs to be advertised to discover services? |
prussell | 10:ee3a359f7d3f | 654 | //a ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // Multiple UUID16 for Standard Services |
prussell | 11:7d02fe5ebea5 | 655 | ble.accumulateAdvertisingPayload(GapAdvertisingData::INCOMPLETE_LIST_128BIT_SERVICE_IDS, (const uint8_t *)puUUID128_IOAdvertise, sizeof(puUUID128_IOAdvertise)); //Single UUID128 for primary Service |
prussell | 11:7d02fe5ebea5 | 656 | |
prussell | 10:ee3a359f7d3f | 657 | //? PR: I'm not sure what these lines do, they were inherited from an example: |
prussell | 10:ee3a359f7d3f | 658 | //? ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); |
prussell | 10:ee3a359f7d3f | 659 | //? ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_THERMOMETER); |
prussell | 9:2d11beda333f | 660 | |
prussell | 6:5b6fb35b4450 | 661 | // Add LocalName last so if Advertising too long will easily see as Name won't be available for the device. |
prussell | 6:5b6fb35b4450 | 662 | ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)pcDeviceName, sizeof(pcDeviceName)-1);//PR: LocalName (No NULL) |
prussell | 6:5b6fb35b4450 | 663 | ble.startAdvertising(); |
prussell | 3:a98203f84063 | 664 | |
prussell | 10:ee3a359f7d3f | 665 | //Example Advertising (Max 31 bytes): 0x01020304050607080910111213141516171819202122232425262728293031 |
prussell | 6:5b6fb35b4450 | 666 | // Example Raw Advertising caught by App nRF-MCP: 0x020106070309180A180D180909626C655052763034 |
prussell | 6:5b6fb35b4450 | 667 | // = Len02 Type01 Value06 (Flags: BREDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE) |
prussell | 6:5b6fb35b4450 | 668 | // = Len07 Type03 Values: 0918 0A18 0D18 (ListUUID16: 1809 180A 180D ) |
prussell | 6:5b6fb35b4450 | 669 | // = Len09 Type09 Values: 62 6C 65 50 52 76 30 34 (LocalName = "blePRv04") |
prussell | 6:5b6fb35b4450 | 670 | // Example Raw Advertising caught by App nRF-MCP: 0x0201061106FB349B5F80000080001000000F180000070209180A180D18 |
prussell | 6:5b6fb35b4450 | 671 | // = Len02 Type01 Value06 (Flags: BREDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE) |
prussell | 6:5b6fb35b4450 | 672 | // = Len11 Type06 ValueFB349B5F8000008000100000_0F18_0000 (UUID128: BluetoothBattery=0x180F) |
prussell | 6:5b6fb35b4450 | 673 | // = Len07 Type02 Value 0918 0A18 0D18 (UUID16: 1809 180A 180D ) |
prussell | 6:5b6fb35b4450 | 674 | // = LocalName field wasn't appended as insufficient space, so Device won't be named when scanning. |
prussell | 0:0217a862b047 | 675 | |
prussell | 12:8bac5f5d3a3e | 676 | // Setup InterruptIn for Buttons (coded for nRF51822-mkit polarities on these buttons) |
prussell | 11:7d02fe5ebea5 | 677 | DEBUG("BLE: Enable Button Interrupts\n"); |
prussell | 12:8bac5f5d3a3e | 678 | B1int.fall(&onB1press); // Button1 Press/fall |
prussell | 12:8bac5f5d3a3e | 679 | B1int.rise(&onB1release); // Button1 Release/rise |
prussell | 12:8bac5f5d3a3e | 680 | B2int.fall(&onB2press); // Button2 Press/fall |
prussell | 12:8bac5f5d3a3e | 681 | B2int.rise(&onB2release); // Button2 Release/rise |
prussell | 11:7d02fe5ebea5 | 682 | |
prussell | 0:0217a862b047 | 683 | DEBUG("BLE: Main Loop\n"); |
prussell | 0:0217a862b047 | 684 | uint32_t u32_wakeevents=0, u32_wakelast=0; // Counter&Register for tracking Wake Events (to see monitor their Frequency) |
prussell | 0:0217a862b047 | 685 | while (true) { |
prussell | 11:7d02fe5ebea5 | 686 | if (uTicker1 && ble.getGapState().connected) { //If Ticker1 and Connected then Update Appropriate Data |
prussell | 11:7d02fe5ebea5 | 687 | uTicker1 = 0; // Clear flag for next Ticker1, see CallbackTicker1(), TODO: log if missed any ticks |
prussell | 3:a98203f84063 | 688 | |
prussell | 3:a98203f84063 | 689 | // Read Sensors, and update matching Service Characteristics (only if connected) |
prussell | 4:976394791d7a | 690 | // *Order here doesn't affect order in nRF-MCP Discovery of Services |
prussell | 6:5b6fb35b4450 | 691 | //TBD: Maybe save power by not Tx unless enabled by App? |
prussell | 8:f187ba55aed2 | 692 | // The Services are discovered if they were setup/started (They don't need update to be discovered) |
prussell | 8:f187ba55aed2 | 693 | update_htm(); |
prussell | 8:f187ba55aed2 | 694 | update_hrm(); |
prussell | 8:f187ba55aed2 | 695 | update_batt(); |
prussell | 8:f187ba55aed2 | 696 | |
prussell | 10:ee3a359f7d3f | 697 | //a vUpdate_IOw8(); |
prussell | 12:8bac5f5d3a3e | 698 | //a vUpdate_IOr4(); |
prussell | 12:8bac5f5d3a3e | 699 | //a vUpdate_IOn4(); |
prussell | 9:2d11beda333f | 700 | |
prussell | 12:8bac5f5d3a3e | 701 | DEBUG(" BLE:Wakes:%04u,Delta:%03u ", u32_wakeevents, u32_wakeevents-u32_wakelast); //For Evaluating Timing |
prussell | 3:a98203f84063 | 702 | u32_wakelast = u32_wakeevents; |
prussell | 11:7d02fe5ebea5 | 703 | } else if (uTicker1) { |
prussell | 11:7d02fe5ebea5 | 704 | uTicker1 = 0; // Clear flag for next Ticker1, see CallbackTicker1(), TODO: log if missed any ticks |
prussell | 12:8bac5f5d3a3e | 705 | DEBUG(" BLE: Tick while unconnected "); |
prussell | 12:8bac5f5d3a3e | 706 | } else if (bNotifySent){ |
prussell | 12:8bac5f5d3a3e | 707 | bNotifySent=false; //clear flag Notify Characteristic Transmitted |
prussell | 12:8bac5f5d3a3e | 708 | DEBUG(" BLE: Notify(%u) ", uNotifyBLE); |
prussell | 0:0217a862b047 | 709 | } else { |
prussell | 11:7d02fe5ebea5 | 710 | //DEBUG("BLE: Wait for Event\n\r"); //x Debug output here causes endless wakes from sleep() |
prussell | 12:8bac5f5d3a3e | 711 | ble.waitForEvent(); //PR: Like sleep() with ble handling. TODO: Handle Error return |
prussell | 0:0217a862b047 | 712 | u32_wakeevents++; //PR: Count events for frequency monitoring (20141207PR: nRF51822 mbed HRM = 50Hz) |
prussell | 12:8bac5f5d3a3e | 713 | if (!bAppControl) { fL2level+=0.25; if (fL2level>0.5){fL2level = 0.0;}; fL2pwm=fL2level;} //If host not controling LED then Ramp Blink to show life |
prussell | 12:8bac5f5d3a3e | 714 | } |
prussell | 0:0217a862b047 | 715 | } |
prussell | 0:0217a862b047 | 716 | } |
prussell | 10:ee3a359f7d3f | 717 | //========== end of main.cpp ========== |