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!!!

Committer:
prussell
Date:
Sun Jan 11 20:01:40 2015 +0000
Revision:
22:533275e76f55
Parent:
21:f92bb1c80538
Child:
23:78aad4e53ae2
Need to add: setReadAuthorizationCallback()

Who changed what in which revision?

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