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 Dec 28 01:51:03 2014 +0000
Revision:
18:c676e79d5d3e
Parent:
17:93538044f003
Child:
19:ebe7b59d9c76
Debugging Notify

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