Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API mbed nRF51822
Revision 0:0217a862b047, committed 2014-12-10
- Comitter:
- prussell
- Date:
- Wed Dec 10 16:54:58 2014 +0000
- Child:
- 1:4a25d917fb6a
- Commit message:
- Initial, Imported from PR's bleHRMv02
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BLE_API.lib Wed Dec 10 16:54:58 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#98f930d14515
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Wed Dec 10 16:54:58 2014 +0000
@@ -0,0 +1,235 @@
+//=========Header (PR)
+// blePRv04, Initial: 20141210 Paul Russell (mbed user: prussell = PR)
+// This sample includes code from several projects found on http://developer.mbed.org, including but not limited to:
+// - http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/
+// - https://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_LoopbackUART/
+// - miscellaneous adopted from more samples...
+// Reference:
+// - http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/
+// - Reference: http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/docs/tip/
+// - Reference: http://developer.mbed.org/teams/Bluetooth-Low-Energy/
+// Warnings:
+// - As of 20141210 it is necessary to use Android App [nRF-Master Control Panel] to ensure any previous connected
+// code on mkit is properly Disconnected before trying to connect other Android nRF Apps (nRFToolbox, nRF UART 2.0, etc.).
+// As UART device doesn't offer disconnect you may need to load a 3rf sample, then connect, then discoonect, to clear the link.
+// Notes:
+// - onDataSent() maybe only occuring when confirmed receive by phone, as onDataSent() didn't happen when phone moved out of range.
+// - onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range, OnTimeout didn't occur at all.
+// ToDo: and ToCheck:
+// - Re-check where voltatile needed
+//==========End of PR's Header
+
+//==========Historic Licencing from original imported sample from mbed website [BLE_HeartRate] ==========
+//From: http://developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_HeartRate/
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License. */
+//==========end of Historic Licencing ==========
+
+
+//==========Compile Options==========
+#define ENABLE_SerialUSB_DEBUG_CONSOLE 1 //PR: Enable Debug on mbed's USB Serial Debug, Setup: Serial 9600,8,N,1,NoFlowControl (TeraTerm: http://en.sourceforge.jp/projects/ttssh2/releases/)
+#define UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL 0 //PR: Option to slow the connection intervsal possibly saving power (After Connected)
+
+//==========Includes==========
+#include "mbed.h"
+#include "BLEDevice.h"
+
+//Services
+#include "BatteryService.h"
+#include "DeviceInformationService.h"
+//#include "DFUService" //TODO: DFU and FOTA Support
+//#include "HealthThermometerService.h" //TODO: Temperature, #include "ble_hts.h"
+#include "HeartRateService.h"
+//#include "UARTService.h" //TODO: Add a UART Channel for streaming data like logs?
+
+//==========Debug Console==========
+#if ENABLE_SerialUSB_DEBUG_CONSOLE
+ Serial debug_serial(USBTX, USBRX); //PR: DebugSerialOverMbedUSB 9600-8N1N
+ #define DEBUG(...) { debug_serial.printf(__VA_ARGS__); }
+#else
+ #define DEBUG(...) //Do Nothing
+#endif
+
+//==========LEDs==========
+//LEDs:
+//DigitalOut out_led1(LED1); //PR: Firmware heartbeat
+//DigitalOut out_led2(LED2); //PR: Firmware heartbeat
+PwmOut pwm_led1(LED1); //PR: Firmware Life Indicator
+PwmOut pwm_led2(LED2); //TODO: Controlled by App
+float f_led1level = 0.0; //Initial Brightness (Typically 0.0~0.5)
+float f_led2level = 0.0; //Initial Brightness (Typically 0.0~0.5)
+
+//==========BLE==========
+BLEDevice ble;
+const static char pcDeviceName[] = "blePRv04"; //PR: Why can App nRF-MCP modify this even though flagged as Const, maybe only temporary mod till App restarts?
+static const uint16_t uuid16_list[] = { //Service List (Pre-defined standard 16bit services)
+ //BLE_UUID_GAP UUID_GENERIC_ACCESS //0x1800 //Included by Default, DeviceName, Appearance, PreferredConnectionParam
+ //BLE_UUID_GATT UUID_GENERIC ATTRIBUTE //0x1801 //Included by Default, ServiceChanged,
+ GattService::UUID_HEART_RATE_SERVICE, //0x180D //HRM, BosyLocation,ControlPoint
+ GattService::UUID_BATTERY_SERVICE, //0x180F //BatteryLevel
+ GattService::UUID_DEVICE_INFORMATION_SERVICE}; //0x180A //sManufacturer, sModelNumber, sSerialNumber, sHWver, sFWver, sSWver
+
+//==========Functions:Timer==========
+static volatile bool b_Ticker1 = false;//Volatile, don't optimize, changes under interrupt control
+void CallbackTicker1(void)
+{
+ static uint32_t u32_Counter; // Counter for Debug Output
+
+ //pwm_led1 = !pwm_led1; /* Do blinky on LED1 while we're waiting for BLE events */
+ f_led1level+=0.1; if (f_led1level>0.5){f_led1level = 0.1;}; pwm_led1=f_led1level;//PR: Ramp Blink
+ DEBUG("\nBLEi: Ticker1(%u) ", ++u32_Counter);
+ b_Ticker1 = true; //PR: Flag to handle Ticker1 Event in Main loop so interupts not blocked.
+}
+
+//==========Functions:BLE==========
+void Callback_BLE_onTimeout(void)
+{
+ DEBUG("\nBLEi: Callback_BLE_onTimeout()\n" );
+ //PR: Haven't seen this, even when phone moved out of range and OnDisconnect(Reason0x08) occurs
+
+ //DEBUG("\nBLE:Callback_BLE_onTimeout(), Restarting Advertising\n" );
+ //ble.startAdvertising();
+}
+
+//void onDisconnection (Gap::DisconnectionEventCallback_t disconnectionCallback)
+void Callback_BLE_onDisconnect(Gap::Handle_t tHandle, Gap::DisconnectionReason_t eReason)
+{
+ //PR: onDisconnect(Reason:8) occured after ~20Tx with no onDataSent() after phone moved out of range
+
+ // REMOTE_USER_TERMINATED_CONNECTION = 0x13 = 19,
+ // LOCAL_HOST_TERMINATED_CONNECTION = 0x16 = 22,
+ // CONN_INTERVAL_UNACCEPTABLE = 0x3B = 59,
+ 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
+
+ //DEBUG("Wait10sec...\n");wait(10.0); //PR: Optional to test effect on advertising
+ ble.startAdvertising(); // restart advertising
+}
+
+//inline void BLEDevice::onConnection(Gap::ConnectionEventCallback_t connectionCallback){ transport->getGap().setOnConnection(connectionCallback);}
+void Callback_BLE_onConnect(Gap::Handle_t tHandle, Gap::addr_type_t ePeerAddrType, const Gap::address_t c6PeerAddr, const Gap::ConnectionParams_t *params)
+{
+ DEBUG("\nBLEi: Callback_BLE_Connect(Handle:%d, eType:%d, Add:%u ...)\n", tHandle, ePeerAddrType, c6PeerAddr);
+
+ #if UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL
+ /* Updating connection parameters can be attempted only after a connection has been
+ * established. Please note that the ble-Central is still the final arbiter for
+ * the effective parameters; the peripheral can only hope that the request is
+ * honored. Please also be mindful of the constraints that might be enforced by
+ * the BLE stack on the underlying controller.*/
+ #define MIN_CONN_INTERVAL 250 /**< Minimum connection interval (250 ms) */
+ #define MAX_CONN_INTERVAL 350 /**< Maximum connection interval (350 ms). */
+ #define CONN_SUP_TIMEOUT 6000 /**< Connection supervisory timeout (6 seconds). */
+ #define SLAVE_LATENCY 4
+
+ Gap::ConnectionParams_t tGap_conn_params;
+ tGap_conn_params.minConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MIN_CONN_INTERVAL);
+ tGap_conn_params.maxConnectionInterval = Gap::MSEC_TO_GAP_DURATION_UNITS(MAX_CONN_INTERVAL);
+ tGap_conn_params.connectionSupervisionTimeout = Gap::MSEC_TO_GAP_DURATION_UNITS(CONN_SUP_TIMEOUT);
+ tGap_conn_params.slaveLatency = SLAVE_LATENCY;
+ ble.updateConnectionParams(tHandle, &tGap_conn_params);
+ #endif /* #if UPDATE_PARAMS_FOR_LONGER_CONNECTION_INTERVAL */
+}
+
+static volatile bool bSent = false; //Volatile, don't optimize, changes under interrupt control
+static volatile unsigned uSentBLE;
+void Callback_BLE_onDataSent(unsigned uSent){
+ uSentBLE=uSent;
+ DEBUG("BLEi: SentI %ubytes", uSent); //TODO: PR: Why uSent always "1", expected it to match sent bytes length
+ bSent = true;
+ //PR: onDataSent() maybe only occuring when confirmed receive by phone, as onDataSent() didn't happen when phone moved out of range.
+}
+
+void Callback_BLE_onDataWritten(const GattCharacteristicWriteCBParams *pParams)
+{
+ // Callback_BLE_onDataWritten == This does occur when use nRF-MCP to save New Heart Rate Control Point (Ignored if incorrect length)
+
+ //Warning: *data may not be NULL terminated
+ DEBUG("\nBLEi: Callback_BLE_onDataWritten(Handle:%d, eOp:%d, uOffset:%u uLen:%u Data0[0x%02x]=Data[%*s]\n", pParams->charHandle, pParams->op, pParams->offset, pParams->len, (char)(pParams->data[0]), pParams->len, pParams->data);
+}
+
+void Callback_BLE_onUpdatesEnabled(Gap::Handle_t tHandle)
+{
+ DEBUG("\nBLEi: Callback_BLE_onUpdates(Handle:%d)\r\n", tHandle);
+}
+
+//==========main==========
+int main(void)
+{
+ f_led1level = 1; pwm_led1 = f_led1level;//Start LED1=OnMax
+ f_led2level = 1; pwm_led2 = f_led2level;//Start LED2=OnMax
+ DEBUG("\nBLE:___%s___\nConnect App for Data: nRF-MCP, nRF-Toolbox:HRM, etc.\n", pcDeviceName); //Restart TeraTerm just before Pressing Reset on mbed
+
+ Ticker ticker1; //PR: Timer Object(Structure)
+ //ticker1.attach(CallbackTicker1, 1.0); //PR: Timer Handler, Float=PeriodSeconds
+ ticker1.attach(CallbackTicker1, 2.0); //PR: Timer Handler, Float=PeriodSeconds
+ //ticker1.attach(CallbackTicker1, 5.0); //PR: Timer Handler, Float=PeriodSeconds
+
+ //Initialize BLE Service (and event actions)
+ ble.init();
+ ble.onDisconnection(Callback_BLE_onDisconnect);
+ ble.onConnection(Callback_BLE_onConnect); //PR: Not required if no actions enabled, enabled now just for debug printf()
+ ble.onDataSent(Callback_BLE_onDataSent);
+ ble.onDataWritten(Callback_BLE_onDataWritten);
+ ble.onTimeout(Callback_BLE_onTimeout);
+ ble.onUpdatesEnabled(Callback_BLE_onUpdatesEnabled);
+
+//ble_error_t readCharacteristicValue ( uint16_t handle, uint8_t *const buffer, uint16_t *const lengthP )
+//ble_error_t updateCharacteristicValue (uint16_t handle, const uint8_t *value, uint16_t size, bool localOnly=false)
+
+ /* Setup primary service. */
+ uint8_t u8LoopCounter = 100;
+ HeartRateService hrService(ble, u8LoopCounter, HeartRateService::LOCATION_FINGER); //Start the service for BLE:HRM
+
+ /* Setup auxiliary services. */
+ BatteryService battery(ble); //Start the service for BLE:Battery
+ DeviceInformationService deviceInfo(ble, "Maker", pcDeviceName, "sn1234", "hw00", "fw00", "sw00");//Start the service for BLE:DeviceInfo
+ // (BLEDevice), pcManufacturer, pcModelNumber, pcSerialNumber, pcHWver, pcFWver, pcSWver
+
+ /* Setup advertising. */
+ ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); //PR: Advertise 1sec (1Hz)
+ ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); //PR: TODO
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); //PR: BLE Only, Options(LE_GENERAL_DISCOVERABLE/LE_LIMITED_DISCOVERABLE)
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); //PR: Might need to change for Custom Services/Characteristics
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);//PR: TODO: Change to: UNKNOWN or custom
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)pcDeviceName, sizeof(pcDeviceName));//PR: Product?
+ ble.startAdvertising();
+
+ DEBUG("BLE: Main Loop\n");
+
+ uint32_t u32_wakeevents=0, u32_wakelast=0; // Counter&Register for tracking Wake Events (to see monitor their Frequency)
+ while (true) {
+ if (b_Ticker1 && ble.getGapState().connected) { //If Ticker1 and Connected Update Data
+ b_Ticker1 = false; // Clear flag for next Ticker1, see CallbackTicker1()
+
+ /* Handle sensor polling == Simulate Data */
+ u8LoopCounter++;
+ if (u8LoopCounter >= 175) {
+ u8LoopCounter = 100;
+ DEBUG("BLE: HRM Rollover175->100 ", u8LoopCounter);
+ }
+ DEBUG("BLE: HRM:%u, Wakes:%u Delta:%d ", u8LoopCounter, u32_wakeevents, u32_wakeevents-u32_wakelast); u32_wakelast=u32_wakeevents;
+ hrService.updateHeartRate(u8LoopCounter);
+ } else if (b_Ticker1) {
+ b_Ticker1 = false; // Clear flag for next Ticker1, see CallbackTicker1()
+ DEBUG("BLE: Tick while unconnected ", u8LoopCounter);
+ } else if (bSent){
+ bSent=false; //clear flag
+ //DEBUG("BLE:Sent %ubytes ", uSentBLE);
+ } else {
+ //DEBUG("BLE:Wait for Event\n\r"); //x Debug output here causes unnecessary wakes resulting in endless awakes.
+ ble.waitForEvent(); //PR: Wait for event - Yield control to BLE Stack and other events (Process ALL pending events before waiting again)
+ f_led2level+=0.25; if (f_led2level>0.5){f_led2level = 0.0;}; pwm_led2=f_led2level;//PR: Ramp Blink
+ u32_wakeevents++; //PR: Count events for frequency monitoring (20141207PR: nRF51822 mbed HRM = 50Hz)
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Dec 10 16:54:58 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/4fc01daae5a5 \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nRF51822.lib Wed Dec 10 16:54:58 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#cdcc094ab166