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:
Mon Dec 29 20:02:23 2014 +0000
Revision:
21:f92bb1c80538
Parent:
20:fb286f736dc4
Child:
22:533275e76f55
Fix: vShowIO(w8 for spare 16bit from Central)

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 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 18:c676e79d5d3e 246 //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 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 18:c676e79d5d3e 248 GattCharacteristic IOr4(puUUID128_IOr4, sIOr4.pu, sizeof(sIOr4), sizeof(sIOr4), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); // Host can manually request
prussell 19:ebe7b59d9c76 249 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 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 (Same as HTM & BattLevel), Buggy until can queue BLE Operations
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 21:f92bb1c80538 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[1], sIOw8.s.px[2]);
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 20:fb286f736dc4 341
prussell 20:fb286f736dc4 342 ble.updateCharacteristicValue(IOr4.getValueHandle(), sIOr4.pu, sizeof(sIOr4)); // Update r4 data so ready for read (Doesn't Trigger Notify)
prussell 9:2d11beda333f 343 }
prussell 9:2d11beda333f 344
prussell 20:fb286f736dc4 345 //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 346
prussell 12:8bac5f5d3a3e 347 void onB1press(void) // B1 Press == *Notify*
prussell 12:8bac5f5d3a3e 348 { // Update Characteristics that include this button
prussell 12:8bac5f5d3a3e 349 uB1press++; // Flag/Count Events (allows detect any missed processing)
prussell 12:8bac5f5d3a3e 350 vFillIO(); // Prepare IO Characteristic data
prussell 20:fb286f736dc4 351 ble.updateCharacteristicValue(IOn4.getValueHandle(), sIOn4.pu, sizeof(sIOn4));// Triggers Notify (Reading n4 at other times may have old data)
prussell 12:8bac5f5d3a3e 352 DEBUG("\n B1p%d", uB1press); vShowIO();
prussell 12:8bac5f5d3a3e 353 };
prussell 12:8bac5f5d3a3e 354 void onB1release(void) // B1 Release
prussell 12:8bac5f5d3a3e 355 { // Update Characteristics that include this button
prussell 12:8bac5f5d3a3e 356 uB1release++; // Flag/Count Events (allows detect any missed processing)
prussell 12:8bac5f5d3a3e 357 vFillIO(); // Prepare IO Characteristic data
prussell 20:fb286f736dc4 358 ble.updateCharacteristicValue(IOn4.getValueHandle(), sIOn4.pu, sizeof(sIOn4));// Triggers Notify (Reading n4 at other times may have old data)
prussell 12:8bac5f5d3a3e 359 DEBUG("\n B1r%d", uB1release); vShowIO();
prussell 12:8bac5f5d3a3e 360 };
prussell 12:8bac5f5d3a3e 361 void onB2press(void) // B2 Press
prussell 12:8bac5f5d3a3e 362 { // Update Characteristics that include this button
prussell 12:8bac5f5d3a3e 363 uB2press++; // Flag/Count Events (allows detect any missed processing)
prussell 12:8bac5f5d3a3e 364 vFillIO(); // Prepare IO Characteristic data
prussell 20:fb286f736dc4 365 ble.updateCharacteristicValue(IOn4.getValueHandle(), sIOn4.pu, sizeof(sIOn4));// Triggers Notify (Reading n4 at other times may have old data)
prussell 12:8bac5f5d3a3e 366 DEBUG("\n B2p%d", uB2press); vShowIO();
prussell 12:8bac5f5d3a3e 367 };
prussell 12:8bac5f5d3a3e 368 void onB2release(void) // B2 Release
prussell 12:8bac5f5d3a3e 369 { // Update Characteristics that include this button
prussell 12:8bac5f5d3a3e 370 uB2release++; // Flag/Count Events (allows detect any missed processing)
prussell 12:8bac5f5d3a3e 371 vFillIO(); // Prepare IO Characteristic data
prussell 20:fb286f736dc4 372 ble.updateCharacteristicValue(IOn4.getValueHandle(), sIOn4.pu, sizeof(sIOn4));// Triggers Notify (Reading n4 at other times may have old data)
prussell 12:8bac5f5d3a3e 373 DEBUG("\n B2r%d", uB2release); vShowIO();
prussell 12:8bac5f5d3a3e 374 };
prussell 9:2d11beda333f 375
prussell 0:0217a862b047 376 //==========Functions:BLE==========
prussell 0:0217a862b047 377 void Callback_BLE_onTimeout(void)
prussell 10:ee3a359f7d3f 378 { //PR: Haven't seen this, even when phone moved out of range and events occur like OnDisconnect(Reason0x08) or LinkLoss
prussell 12:8bac5f5d3a3e 379 DEBUG("\n\n\n\n**** BLEi: Callback_BLE_onTimeout() ****\n\n\n\n" );
prussell 0:0217a862b047 380
prussell 0:0217a862b047 381 //DEBUG("\nBLE:Callback_BLE_onTimeout(), Restarting Advertising\n" );
prussell 0:0217a862b047 382 //ble.startAdvertising();
prussell 0:0217a862b047 383 }
prussell 0:0217a862b047 384
prussell 0:0217a862b047 385 void Callback_BLE_onDisconnect(Gap::Handle_t tHandle, Gap::DisconnectionReason_t eReason)
prussell 10:ee3a359f7d3f 386 { //PR: onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range
prussell 0:0217a862b047 387
prussell 0:0217a862b047 388 // REMOTE_USER_TERMINATED_CONNECTION = 0x13 = 19,
prussell 0:0217a862b047 389 // LOCAL_HOST_TERMINATED_CONNECTION = 0x16 = 22,
prussell 0:0217a862b047 390 // CONN_INTERVAL_UNACCEPTABLE = 0x3B = 59,
prussell 0:0217a862b047 391 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 392
prussell 0:0217a862b047 393 //DEBUG("Wait10sec...\n");wait(10.0); //PR: Optional to test effect on advertising
prussell 0:0217a862b047 394 ble.startAdvertising(); // restart advertising
prussell 0:0217a862b047 395 }
prussell 0:0217a862b047 396
prussell 0:0217a862b047 397 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 398 {
prussell 0:0217a862b047 399 DEBUG("\nBLEi: Callback_BLE_Connect(Handle:%d, eType:%d, Add:%u ...)\n", tHandle, ePeerAddrType, c6PeerAddr);
prussell 0:0217a862b047 400
prussell 11:7d02fe5ebea5 401 //x #if ENABLE_BLE_SLOW //UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL //PR: Adopted optional code never tested
prussell 11:7d02fe5ebea5 402 //x // Updating connection parameters can be attempted only after a connection has been
prussell 11:7d02fe5ebea5 403 //x // established. Please note that the ble-Central is still the final arbiter for
prussell 11:7d02fe5ebea5 404 //x // the effective parameters; the peripheral can only hope that the request is
prussell 11:7d02fe5ebea5 405 //x // honored. Please also be mindful of the constraints that might be enforced by
prussell 11:7d02fe5ebea5 406 //x // the BLE stack on the underlying controller.
prussell 11:7d02fe5ebea5 407 //x #define MIN_CONN_INTERVAL 250 // Minimum connection interval (250 ms)
prussell 11:7d02fe5ebea5 408 //x #define MAX_CONN_INTERVAL 350 // Maximum connection interval (350 ms)
prussell 11:7d02fe5ebea5 409 //x #define CONN_SUP_TIMEOUT 6000 // Connection supervisory timeout (6 seconds)
prussell 11:7d02fe5ebea5 410 //x #define SLAVE_LATENCY 4
prussell 11:7d02fe5ebea5 411 //x Gap::ConnectionParams_t tGap_conn_params;
prussell 11:7d02fe5ebea5 412 //x tGap_conn_params.minConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MIN_CONN_INTERVAL);
prussell 11:7d02fe5ebea5 413 //x tGap_conn_params.maxConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MAX_CONN_INTERVAL);
prussell 11:7d02fe5ebea5 414 //x tGap_conn_params.connectionSupervisionTimeout = Gap::MSEC_TO_GAP_DURATION_UNITS(CONN_SUP_TIMEOUT);
prussell 11:7d02fe5ebea5 415 //x tGap_conn_params.slaveLatency = SLAVE_LATENCY;
prussell 11:7d02fe5ebea5 416 //x ble.updateConnectionParams(tHandle, &tGap_conn_params);
prussell 11:7d02fe5ebea5 417 //x #endif // #if UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL
prussell 0:0217a862b047 418 }
prussell 0:0217a862b047 419
prussell 12:8bac5f5d3a3e 420 static volatile bool bNotifySent = false; //Volatile, don't optimize, changes under interrupt control
prussell 12:8bac5f5d3a3e 421 static volatile unsigned uNotifyBLE;
prussell 12:8bac5f5d3a3e 422 void Callback_BLE_onNotifySent(unsigned uNotify) //TODO: Consider renaming to onNotifySent(uNotified)
prussell 12:8bac5f5d3a3e 423 { // 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 424 uNotifyBLE=uNotify;
prussell 12:8bac5f5d3a3e 425 DEBUG(" Senti(%u)", uNotifyBLE); //TODO: PR: Why uSent always "1", expected it to match sent bytes length
prussell 12:8bac5f5d3a3e 426 bNotifySent = true;
prussell 0:0217a862b047 427 }
prussell 0:0217a862b047 428
prussell 0:0217a862b047 429 void Callback_BLE_onDataWritten(const GattCharacteristicWriteCBParams *pParams)
prussell 9:2d11beda333f 430 { // 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 431 GattAttribute::Handle_t tHandle=pParams->charHandle;
prussell 0:0217a862b047 432
prussell 0:0217a862b047 433 //Warning: *data may not be NULL terminated
prussell 9:2d11beda333f 434 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 435
prussell 10:ee3a359f7d3f 436 /* //TODO: Add check of op type with tHandle check: switch(pParams->op){ case: GATTS_CHAR_OP_WRITE_REQ:}...
prussell 10:ee3a359f7d3f 437 switch(pParams->op){
prussell 10:ee3a359f7d3f 438 case GATTS_CHAR_OP_INVALID:
prussell 10:ee3a359f7d3f 439 case GATTS_CHAR_OP_WRITE_REQ
prussell 10:ee3a359f7d3f 440 case GATTS_CHAR_OP_WRITE_CMD
prussell 10:ee3a359f7d3f 441 case GATTS_CHAR_OP_SIGN_WRITE_CMD //< Signed Write Command
prussell 10:ee3a359f7d3f 442 case GATTS_CHAR_OP_PREP_WRITE_REQ //< Prepare Write Request
prussell 10:ee3a359f7d3f 443 case GATTS_CHAR_OP_EXEC_WRITE_REQ_CANCEL //< Execute Write Request: Cancel all prepared writes
prussell 10:ee3a359f7d3f 444 case GATTS_CHAR_OP_EXEC_WRITE_REQ_NOW //< Execute Write Request: Immediately execute all prepared writes
prussell 10:ee3a359f7d3f 445 default: Error?
prussell 10:ee3a359f7d3f 446 }*/
prussell 9:2d11beda333f 447
prussell 10:ee3a359f7d3f 448 //a These are equivalent ways of accessing characteristic handles:
prussell 10:ee3a359f7d3f 449 //a if (pParams->charHandle == IOw8.getValueHandle()) { DEBUG("\n\nOK tHandle %d\n\n", pParams->charHandle); }
prussell 10:ee3a359f7d3f 450 //a if (pParams->charHandle == ServiceIO.getCharacteristic(0)->getValueHandle()) { DEBUG("\n\nOK tHandle %d\n\n", pParams->charHandle); }
prussell 10:ee3a359f7d3f 451 //a if (IOw8.getValueHandle() == ServiceIO.getCharacteristic(0)->getValueHandle()) { DEBUG("\n\nOK tHandle equivalent %d\n\n", pParams->charHandle); }
prussell 9:2d11beda333f 452
prussell 9:2d11beda333f 453 //Handle Changes to Service Characteristics:
prussell 10:ee3a359f7d3f 454 if(!ble.getGapState().connected){ //Ensure BLE still connected
prussell 10:ee3a359f7d3f 455 DEBUG("BLEi: Callback_BLE_onDataWritten() while disconnected!!");
prussell 9:2d11beda333f 456 } else {
prussell 10:ee3a359f7d3f 457 uint16_t uLen;
prussell 10:ee3a359f7d3f 458 if (tHandle == IOw8.getValueHandle()) { // This occurs from Write by App nRF-MCP since has Write Property set
prussell 12:8bac5f5d3a3e 459 ble.readCharacteristicValue(tHandle, sIOw8.pu, &uLen); //Update Characteristic with new information (Option: Verify length or a checksum first)
prussell 12:8bac5f5d3a3e 460 vShowIO();
prussell 12:8bac5f5d3a3e 461
prussell 12:8bac5f5d3a3e 462 bAppControl = true; //Host has taken control of LEDs
prussell 12:8bac5f5d3a3e 463 fL1level = (((float)sIOw8.s.L1pwm100)/100.0); if(fL1level>1.0){fL1level=1.0;}; fL1pwm=fL1level; //Set LED1 Level
prussell 12:8bac5f5d3a3e 464 fL2level = (((float)sIOw8.s.L2pwm255)/255.0); if(fL2level>1.0){fL2level=1.0;}; fL2pwm=fL2level; //Set LED1 Level
prussell 12:8bac5f5d3a3e 465 DEBUG(" L1:%d==%f L2:%d==%f\n", sIOw8.s.L1pwm100, fL1level, sIOw8.s.L2pwm255, fL2level);
prussell 12:8bac5f5d3a3e 466
prussell 11:7d02fe5ebea5 467 //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 468
prussell 11:7d02fe5ebea5 469 //} else if (tHandle == IOr4.getValueHandle()) { // Readonly, shouldn't occur
prussell 10:ee3a359f7d3f 470 // ble.readCharacteristicValue(tHandle, pIOr4, &uLen);
prussell 10:ee3a359f7d3f 471 // DEBUG(" IOr4[%d]:%02X %02X %02X %02X\n", uLen, pIOr4[0], pIOr4[1], pIOr4[2], pIOr4[3]);
prussell 10:ee3a359f7d3f 472 // //TODO: Update Outputs
prussell 11:7d02fe5ebea5 473 //} else if (tHandle == IOn4.getValueHandle()) { // Readonly, shouldn't occur
prussell 10:ee3a359f7d3f 474 // ble.readCharacteristicValue(tHandle, pIOn4, &uLen);
prussell 10:ee3a359f7d3f 475 // DEBUG(" IOn4[%d]:%02X %02X %02X %02X\n", uLen, pIOn4[0], pIOn4[1], pIOn4[2], pIOn4[3]);
prussell 10:ee3a359f7d3f 476 // //TODO: Update Outputs
prussell 10:ee3a359f7d3f 477 } else {
prussell 10:ee3a359f7d3f 478 DEBUG("\n Unknown onWrite(tHandle:%d)\n\n", tHandle);
prussell 10:ee3a359f7d3f 479 }
prussell 9:2d11beda333f 480 }
prussell 8:f187ba55aed2 481
prussell 10:ee3a359f7d3f 482 //LinkLoss:
prussell 10:ee3a359f7d3f 483 //x pServiceLinkLoss->setAlertLevel( AlertLevel_t newLevel )
prussell 10:ee3a359f7d3f 484 //x Triggered by BluetoothLEGatt sample changing Linkloss setting:
prussell 10:ee3a359f7d3f 485 //x Alert=1: Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x01]=Data[])
prussell 10:ee3a359f7d3f 486 //x Alert=2: Debug=BLEi: Callback_BLE_onDataWritten(Handle:12, eOp:1, uOffset:0 uLen:1 Data0[0x02]=Data[])
prussell 8:f187ba55aed2 487
prussell 12:8bac5f5d3a3e 488 //vShowIO(); //Show IO Characteristic Status
prussell 0:0217a862b047 489 }
prussell 0:0217a862b047 490
prussell 15:b2c8bdef2d20 491 void Callback_BLE_onUpdatesEnabled(Gap::Handle_t tHandle) // Notifications
prussell 15:b2c8bdef2d20 492 { //Triggered when click the UpdateContinuousIcon in nRF-MCP(ThreeDownArrows)
prussell 17:93538044f003 493 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 494 } else if (tHandle == IOr4.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Enabled - IOr4\n", tHandle); // Notify not enabled on this Characteristic
prussell 16:3e83f2babdfb 495 } else if (tHandle == IOw8.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Enabled - IOw8\n", tHandle); // Notify not enabled on this Characteristic
prussell 16:3e83f2babdfb 496 } else { DEBUG("\nBLEi: onUpdates(Handle:%d) Enabled - Characteristic?\n", tHandle);
prussell 15:b2c8bdef2d20 497 }
prussell 16:3e83f2babdfb 498 //TODO: process Enable for Each Notify Characteriistic of each Service
prussell 15:b2c8bdef2d20 499 }
prussell 15:b2c8bdef2d20 500
prussell 15:b2c8bdef2d20 501 void Callback_BLE_onUpdatesDisabled(Gap::Handle_t tHandle) // Notifications
prussell 10:ee3a359f7d3f 502 { //Triggered when click the UpdateContinuousIcon in nRF-MCP(ThreeDownArrows)
prussell 16:3e83f2babdfb 503 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 504 } else if (tHandle == IOr4.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Disabled - IOr4\n", tHandle); // Notify not enabled on this Characteristic
prussell 16:3e83f2babdfb 505 } else if (tHandle == IOw8.getValueHandle()) { DEBUG("\nBLEi: onUpdates(Handle:%d) Disabled - IOw8\n", tHandle); // Notify not enabled on this Characteristic
prussell 16:3e83f2babdfb 506 } else { DEBUG("\nBLEi: onUpdates(Handle:%d) Disabled - Characteristic?\n", tHandle);
prussell 9:2d11beda333f 507 }
prussell 16:3e83f2babdfb 508 //TODO: process Disable for Each Notify Characteriistic of each Service
prussell 0:0217a862b047 509 }
prussell 15:b2c8bdef2d20 510 void Callback_BLE_onConfirmRx(Gap::Handle_t tHandle) // Confirmations??
prussell 15:b2c8bdef2d20 511 {
prussell 15:b2c8bdef2d20 512 DEBUG("\nBLEi: ConfirmationRx(Handle:%d)\n", tHandle);
prussell 15:b2c8bdef2d20 513 }
prussell 15:b2c8bdef2d20 514
prussell 0:0217a862b047 515
prussell 5:d36bbb315e31 516 // Adopted 20141213 from http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_LinkLoss/file/440ee5e8595f/main.cpp
prussell 5:d36bbb315e31 517 void Callback_BLE_onLinkLoss(LinkLossService::AlertLevel_t level)
prussell 5:d36bbb315e31 518 {
prussell 10:ee3a359f7d3f 519 printf("\nBLEi: Link Loss Alert, Level:%d\n", level);
prussell 10:ee3a359f7d3f 520 //TODO: Handle Link Loss, maybe lower power mode and/or advertising mode
prussell 5:d36bbb315e31 521 }
prussell 10:ee3a359f7d3f 522 //==========BLE:HRM==========
prussell 8:f187ba55aed2 523 //Adopted 2014Dec from http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/
prussell 8:f187ba55aed2 524 uint8_t update_hrm(void)//(bool bInit)
prussell 8:f187ba55aed2 525 {
prussell 8:f187ba55aed2 526 static uint8_t u8_hrm = 100;
prussell 10:ee3a359f7d3f 527 if (++u8_hrm >= 175) {
prussell 8:f187ba55aed2 528 u8_hrm = 100;
prussell 10:ee3a359f7d3f 529 DEBUG(" HRM>100");
prussell 10:ee3a359f7d3f 530 } else {
prussell 10:ee3a359f7d3f 531 DEBUG(" HRM:%d", u8_hrm);
prussell 10:ee3a359f7d3f 532 }
prussell 8:f187ba55aed2 533 pServiceHRM->updateHeartRate( u8_hrm );// Update Characteristic so sent by BLE
prussell 8:f187ba55aed2 534 return(u8_hrm);
prussell 8:f187ba55aed2 535 }
prussell 10:ee3a359f7d3f 536 //==========BLE:HTM(Using nRF Internal Temperature)==========
prussell 10:ee3a359f7d3f 537 // *If not using nRF51822 IC then change this to a simple counter like BLE:Battery section
prussell 10:ee3a359f7d3f 538 // Adopted 2014Dec from: https://developer.mbed.org/users/takafuminaka/code/BLE_HTM_by_InTempSensr/
prussell 8:f187ba55aed2 539 // Service: https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml
prussell 8:f187ba55aed2 540 // HTM Char: https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml
prussell 9:2d11beda333f 541 //****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 542 float update_htm(void)
prussell 8:f187ba55aed2 543 {
prussell 8:f187ba55aed2 544 //static float fTemperature = 0;//-123.456;
prussell 8:f187ba55aed2 545 int32_t i32_temp;
prussell 12:8bac5f5d3a3e 546 sd_temp_get(&i32_temp); //Read the nRF Internal Temperature (Die in 0.25'C steps, Offset:TBD), TODO:Check Scaling
prussell 8:f187ba55aed2 547 float fTemperature = (float(i32_temp)/4.0) - 16.0; // Scale&Shift (0.25'C from -16'C?)
prussell 8:f187ba55aed2 548
prussell 8:f187ba55aed2 549 //{//Force to IEEE format to match needs of Apps like nRF-HTM and nRF-Toolbox:HTM
prussell 8:f187ba55aed2 550 // 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 551 // uint8_t exponent = 0xFE; //exponent is -2
prussell 8:f187ba55aed2 552 // uint32_t mantissa = (uint32_t)(fTemperature*100);
prussell 8:f187ba55aed2 553 // uint32_t temp_ieee11073 = ((((uint32_t)exponent) << 24) | (mantissa)); //Note: Assumes Mantissa within 24bits
prussell 8:f187ba55aed2 554 // memcpy(((uint8_t*)&fTemperature)+1, (uint8_t*)&temp_ieee11073, 4); //Overwrite with IEEE format float
prussell 8:f187ba55aed2 555 //}
prussell 8:f187ba55aed2 556
prussell 8:f187ba55aed2 557 pServiceHTM->updateTemperature( fTemperature );// Update Characteristic so sent by BLE
prussell 10:ee3a359f7d3f 558 DEBUG(" HTM%03d==%2.2f", i32_temp, fTemperature);
prussell 8:f187ba55aed2 559 return(fTemperature);
prussell 8:f187ba55aed2 560 }
prussell 10:ee3a359f7d3f 561 //==========BLE:Battery==========
prussell 8:f187ba55aed2 562 uint8_t update_batt(void)
prussell 8:f187ba55aed2 563 {
prussell 8:f187ba55aed2 564 static uint8_t u8_BattPercent=33; //Level: 0..100%
prussell 8:f187ba55aed2 565 u8_BattPercent <= 50 ? u8_BattPercent=100 : u8_BattPercent--; // Simulate Battery Decay
prussell 8:f187ba55aed2 566 pServiceBattery->updateBatteryLevel( u8_BattPercent ); // Update Characteristic so sent by BLE
prussell 10:ee3a359f7d3f 567 DEBUG(" Batt%03d%%", u8_BattPercent);
prussell 8:f187ba55aed2 568 return(u8_BattPercent);
prussell 8:f187ba55aed2 569 }
prussell 9:2d11beda333f 570
prussell 10:ee3a359f7d3f 571 //==========Functions:Timer==========
prussell 11:7d02fe5ebea5 572 static volatile uint8_t uTicker1;//Volatile, don't optimize, changes under interrupt control
prussell 10:ee3a359f7d3f 573 void CallbackTicker1(void)
prussell 10:ee3a359f7d3f 574 {
prussell 11:7d02fe5ebea5 575 static uint32_t u32_Counter; // Counter for checking Timing
prussell 11:7d02fe5ebea5 576 DEBUG("\nBLEi: Ticker(%04u) ", ++u32_Counter);
prussell 12:8bac5f5d3a3e 577 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 578 uTicker1++; // Flag event, using counter so can detect missed events
prussell 10:ee3a359f7d3f 579 }
prussell 11:7d02fe5ebea5 580
prussell 0:0217a862b047 581 //==========main==========
prussell 0:0217a862b047 582 int main(void)
prussell 12:8bac5f5d3a3e 583 {
prussell 14:b968df367145 584 fL1level = 1.0; fL1pwm = fL1level;//Start LED1=OnMax
prussell 14:b968df367145 585 fL2level = 0.2; fL2pwm = fL2level;//Start LED2=Dim
prussell 6:5b6fb35b4450 586
prussell 6:5b6fb35b4450 587 //Restart TeraTerm just before Pressing Reset on mbed, 9600-8N1(No Flow Control)
prussell 6:5b6fb35b4450 588 DEBUG("\nBLE: ___%s___\n", pcDeviceName);
prussell 14:b968df367145 589
prussell 14:b968df367145 590 //ARM Predefines: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/BABJFEFG.html
prussell 14:b968df367145 591 // *Some are numbers not strings so printf(%s) not always appropriate
prussell 14:b968df367145 592 DEBUG(" ARM Compiler Predefines:\n");
prussell 14:b968df367145 593 DEBUG(" Built UTC:[ %s %s ]\n", __DATE__, __TIME__);
prussell 14:b968df367145 594 DEBUG(" __arm__[%d]", __arm__);
prussell 14:b968df367145 595 DEBUG(" __ARMCC_VERSION [%d]=[P:major V:minor bbbb:build]\n", __ARMCC_VERSION);
prussell 14:b968df367145 596 DEBUG(" __VERSION__(gnu Compiler)[" __VERSION__ "]\n");
prussell 14:b968df367145 597 //DEBUG(" __STDC_VERSION__ [%d]\n", __STDC_VERSION__);
prussell 14:b968df367145 598 //DEBUG(" __BIG_ENDIAN[%d] ", __BIG_ENDIAN);
prussell 14:b968df367145 599 DEBUG(" __OPTIMISE_LEVEL[%d]", __OPTIMISE_LEVEL);
prussell 14:b968df367145 600 //DEBUG(" __OPTIMISE_SPACE[%d]", __OPTIMISE_SPACE);
prussell 14:b968df367145 601 DEBUG(" __OPTIMISE_TIME[%d]", __OPTIMISE_TIME);
prussell 14:b968df367145 602 DEBUG("\n __MODULE__[" __MODULE__ "] __FILE__[" __FILE__ "] __BASE_FILE__[" __BASE_FILE__ "]\n");
prussell 14:b968df367145 603 DEBUG(" __FUNCTION__[%s] __PRETTY_FUNCTION__[%s]\n", __FUNCTION__, __PRETTY_FUNCTION__)
prussell 14:b968df367145 604
prussell 15:b2c8bdef2d20 605 //vShowIO(); Show Raw initialized values before any BLE
prussell 0:0217a862b047 606
prussell 0:0217a862b047 607 Ticker ticker1; //PR: Timer Object(Structure)
prussell 12:8bac5f5d3a3e 608 ticker1.attach(CallbackTicker1, 5.0); //PR: Timer Handler, Float=PeriodSeconds (Note BLE default wakes about 50Hz/20msec)
prussell 0:0217a862b047 609
prussell 3:a98203f84063 610 //BLE1: Setup BLE Service (and event actions) //TODO: Check for services declared before main() - Is that OK?
prussell 14:b968df367145 611 DEBUG("\nBLE: Connect App for Data: nRF-MCP, nRF-Toolbox:HRM/HTM, Android Sample BluetoothLeGatt, etc.\n");
prussell 14:b968df367145 612 DEBUG(" nRF-MCP: App->mbed: LinkLoss->AlertLevel(UpArrow)\n");
prussell 14:b968df367145 613 DEBUG(" nRF-MCP: App->mbed: BatteryService->BatteryLevel(DownArrow)\n");
prussell 14:b968df367145 614 DEBUG(" nRF-MCP: mbed->App: BatteryService->BatteryLevel->EnableNotify(ThreeDownArrows), Also App Acks the send=DEBUG('SentI')\n");
prussell 14:b968df367145 615
prussell 3:a98203f84063 616 DEBUG("BLE: Setup BLE\n");
prussell 0:0217a862b047 617 ble.init();
prussell 12:8bac5f5d3a3e 618 ble.onDisconnection(Callback_BLE_onDisconnect); //PR: Host disconnects, restart advertising, clear any unnecessary functions to save power
prussell 12:8bac5f5d3a3e 619 ble.onConnection(Callback_BLE_onConnect); //PR: Host connects (Not required if no actions enabled, enabled now just for debug)
prussell 12:8bac5f5d3a3e 620 ble.onDataSent(Callback_BLE_onNotifySent); //PR: Occurs when a Notify Characteristic has been updated and sent over BLE
prussell 12:8bac5f5d3a3e 621 ble.onDataWritten(Callback_BLE_onDataWritten); //PR: Occurs when an update to a Characteristic has been received over BLE
prussell 12:8bac5f5d3a3e 622 ble.onTimeout(Callback_BLE_onTimeout); //PR: ??? Hasn't occured, TODO: Monitor and find out what causes this
prussell 12:8bac5f5d3a3e 623 ble.onUpdatesEnabled(Callback_BLE_onUpdatesEnabled);//PR: Occurs when host enables notify on a Characteristic that has Notify property set
prussell 15:b2c8bdef2d20 624 ble.onUpdatesDisabled(Callback_BLE_onUpdatesDisabled); //TODO:
prussell 15:b2c8bdef2d20 625 ble.onConfirmationReceived(Callback_BLE_onConfirmRx); //TODO:
prussell 12:8bac5f5d3a3e 626 //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 627
prussell 6:5b6fb35b4450 628 //BLE2: Setup Services (with their initial values and options)
prussell 3:a98203f84063 629 DEBUG("BLE: Setup Services\n");
prussell 4:976394791d7a 630 // *Order here affects order in nRF-MCP Discovery of Services
prussell 8:f187ba55aed2 631 DeviceInformationService ServiceDeviceInfo(ble, "Maker", pcDeviceName, "sn1234", "hw00", "fw00", "sw00");//(BLEDevice), pcManufacturer, pcModelNumber, pcSerialNumber, pcHWver, pcFWver, pcSWver
prussell 9:2d11beda333f 632 pServiceDeviceInfo = &ServiceDeviceInfo; //DEBUG(" Handle Service DeviceInfo:%d\n", ServiceDeviceInfo.XXXgetHandle());
prussell 8:f187ba55aed2 633 LinkLossService ServiceLinkLoss(ble, Callback_BLE_onLinkLoss, LinkLossService::HIGH_ALERT); //New20141213, TBD
prussell 8:f187ba55aed2 634 pServiceLinkLoss = &ServiceLinkLoss;
prussell 8:f187ba55aed2 635 BatteryService ServiceBattery(ble, 10);
prussell 8:f187ba55aed2 636 pServiceBattery = &ServiceBattery;
prussell 8:f187ba55aed2 637 HeartRateService ServiceHRM(ble, (uint8_t)111, HeartRateService::LOCATION_FINGER);
prussell 8:f187ba55aed2 638 pServiceHRM = &ServiceHRM;
prussell 8:f187ba55aed2 639 HealthThermometerService ServiceHTM(ble, 33.3, HealthThermometerService::LOCATION_EAR);
prussell 8:f187ba55aed2 640 pServiceHTM = &ServiceHTM;
prussell 8:f187ba55aed2 641 //UARTService ServiceUART(ble);
prussell 8:f187ba55aed2 642 // pServiceUART = &ServiceUART;
prussell 5:d36bbb315e31 643
prussell 12:8bac5f5d3a3e 644 DEBUG("BLE: Setup Custom IO Service\n");
prussell 10:ee3a359f7d3f 645 ble.addService(ServiceIO); //Pointer: pServiceIO
prussell 15:b2c8bdef2d20 646 vShowIO(); // Show Initialized values with bleIO initialized (includes tHandle)
prussell 12:8bac5f5d3a3e 647 //TODO: Ensure outputs in correct Initial state
prussell 9:2d11beda333f 648
prussell 3:a98203f84063 649 //BLE3: Setup advertising
prussell 10:ee3a359f7d3f 650 // 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 651 // 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 652 DEBUG("BLE: Setup Advertising - Apps like HRM/HTM/UART require matching UUID\n");
prussell 6:5b6fb35b4450 653 ble.clearAdvertisingPayload(); //Prep
prussell 6:5b6fb35b4450 654 ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); //PR: Advertise 1sec (1Hz)
prussell 6:5b6fb35b4450 655 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); //PR: TODO: To Study
prussell 6:5b6fb35b4450 656 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); //PR: BLE Only (Option:LE_LIMITED_DISCOVERABLE)
prussell 6:5b6fb35b4450 657 // Does "LE_GENERAL_DISCOVERABLE" affect whether UUID needs to be advertised to discover services?
prussell 10:ee3a359f7d3f 658 //a ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // Multiple UUID16 for Standard Services
prussell 11:7d02fe5ebea5 659 ble.accumulateAdvertisingPayload(GapAdvertisingData::INCOMPLETE_LIST_128BIT_SERVICE_IDS, (const uint8_t *)puUUID128_IOAdvertise, sizeof(puUUID128_IOAdvertise)); //Single UUID128 for primary Service
prussell 11:7d02fe5ebea5 660
prussell 10:ee3a359f7d3f 661 //? PR: I'm not sure what these lines do, they were inherited from an example:
prussell 10:ee3a359f7d3f 662 //? ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
prussell 10:ee3a359f7d3f 663 //? ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_THERMOMETER);
prussell 9:2d11beda333f 664
prussell 6:5b6fb35b4450 665 // Add LocalName last so if Advertising too long will easily see as Name won't be available for the device.
prussell 6:5b6fb35b4450 666 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)pcDeviceName, sizeof(pcDeviceName)-1);//PR: LocalName (No NULL)
prussell 6:5b6fb35b4450 667 ble.startAdvertising();
prussell 3:a98203f84063 668
prussell 10:ee3a359f7d3f 669 //Example Advertising (Max 31 bytes): 0x01020304050607080910111213141516171819202122232425262728293031
prussell 6:5b6fb35b4450 670 // Example Raw Advertising caught by App nRF-MCP: 0x020106070309180A180D180909626C655052763034
prussell 6:5b6fb35b4450 671 // = Len02 Type01 Value06 (Flags: BREDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE)
prussell 6:5b6fb35b4450 672 // = Len07 Type03 Values: 0918 0A18 0D18 (ListUUID16: 1809 180A 180D )
prussell 6:5b6fb35b4450 673 // = Len09 Type09 Values: 62 6C 65 50 52 76 30 34 (LocalName = "blePRv04")
prussell 6:5b6fb35b4450 674 // Example Raw Advertising caught by App nRF-MCP: 0x0201061106FB349B5F80000080001000000F180000070209180A180D18
prussell 6:5b6fb35b4450 675 // = Len02 Type01 Value06 (Flags: BREDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE)
prussell 6:5b6fb35b4450 676 // = Len11 Type06 ValueFB349B5F8000008000100000_0F18_0000 (UUID128: BluetoothBattery=0x180F)
prussell 6:5b6fb35b4450 677 // = Len07 Type02 Value 0918 0A18 0D18 (UUID16: 1809 180A 180D )
prussell 6:5b6fb35b4450 678 // = LocalName field wasn't appended as insufficient space, so Device won't be named when scanning.
prussell 0:0217a862b047 679
prussell 12:8bac5f5d3a3e 680 // Setup InterruptIn for Buttons (coded for nRF51822-mkit polarities on these buttons)
prussell 11:7d02fe5ebea5 681 DEBUG("BLE: Enable Button Interrupts\n");
prussell 12:8bac5f5d3a3e 682 B1int.fall(&onB1press); // Button1 Press/fall
prussell 12:8bac5f5d3a3e 683 B1int.rise(&onB1release); // Button1 Release/rise
prussell 12:8bac5f5d3a3e 684 B2int.fall(&onB2press); // Button2 Press/fall
prussell 12:8bac5f5d3a3e 685 B2int.rise(&onB2release); // Button2 Release/rise
prussell 11:7d02fe5ebea5 686
prussell 0:0217a862b047 687 DEBUG("BLE: Main Loop\n");
prussell 0:0217a862b047 688 uint32_t u32_wakeevents=0, u32_wakelast=0; // Counter&Register for tracking Wake Events (to see monitor their Frequency)
prussell 0:0217a862b047 689 while (true) {
prussell 11:7d02fe5ebea5 690 if (uTicker1 && ble.getGapState().connected) { //If Ticker1 and Connected then Update Appropriate Data
prussell 11:7d02fe5ebea5 691 uTicker1 = 0; // Clear flag for next Ticker1, see CallbackTicker1(), TODO: log if missed any ticks
prussell 3:a98203f84063 692
prussell 3:a98203f84063 693 // Read Sensors, and update matching Service Characteristics (only if connected)
prussell 4:976394791d7a 694 // *Order here doesn't affect order in nRF-MCP Discovery of Services
prussell 6:5b6fb35b4450 695 //TBD: Maybe save power by not Tx unless enabled by App?
prussell 8:f187ba55aed2 696 // The Services are discovered if they were setup/started (They don't need update to be discovered)
prussell 8:f187ba55aed2 697 update_htm();
prussell 8:f187ba55aed2 698 update_hrm();
prussell 8:f187ba55aed2 699 update_batt();
prussell 8:f187ba55aed2 700
prussell 10:ee3a359f7d3f 701 //a vUpdate_IOw8();
prussell 12:8bac5f5d3a3e 702 //a vUpdate_IOr4();
prussell 12:8bac5f5d3a3e 703 //a vUpdate_IOn4();
prussell 9:2d11beda333f 704
prussell 12:8bac5f5d3a3e 705 DEBUG(" BLE:Wakes:%04u,Delta:%03u ", u32_wakeevents, u32_wakeevents-u32_wakelast); //For Evaluating Timing
prussell 3:a98203f84063 706 u32_wakelast = u32_wakeevents;
prussell 11:7d02fe5ebea5 707 } else if (uTicker1) {
prussell 11:7d02fe5ebea5 708 uTicker1 = 0; // Clear flag for next Ticker1, see CallbackTicker1(), TODO: log if missed any ticks
prussell 12:8bac5f5d3a3e 709 DEBUG(" BLE: Tick while unconnected ");
prussell 12:8bac5f5d3a3e 710 } else if (bNotifySent){
prussell 12:8bac5f5d3a3e 711 bNotifySent=false; //clear flag Notify Characteristic Transmitted
prussell 12:8bac5f5d3a3e 712 DEBUG(" BLE: Notify(%u) ", uNotifyBLE);
prussell 0:0217a862b047 713 } else {
prussell 11:7d02fe5ebea5 714 //DEBUG("BLE: Wait for Event\n\r"); //x Debug output here causes endless wakes from sleep()
prussell 12:8bac5f5d3a3e 715 ble.waitForEvent(); //PR: Like sleep() with ble handling. TODO: Handle Error return
prussell 0:0217a862b047 716 u32_wakeevents++; //PR: Count events for frequency monitoring (20141207PR: nRF51822 mbed HRM = 50Hz)
prussell 12:8bac5f5d3a3e 717 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 718 }
prussell 0:0217a862b047 719 }
prussell 0:0217a862b047 720 }
prussell 10:ee3a359f7d3f 721 //========== end of main.cpp ==========