Heart Rate Monitor example for Delta BLE platform

This is a very basic BLE example for DELTA DFBM-NQ620 and DELTA DFCM-NNN50 platforms. This example is doing HRM (Heart Rate Monitor) application, the service spec can be found in here Once compiled and download to DELTA platforms, the module start advertising while LED1 is blinking. User can download the APP 'nRF Connect' available in both App Store and Google Play to scan the adverting and connect to the module.

Note that printf use the baudrate 9600 8n1 as default. In Windows, user could find the ready to use com port number in Device Manager and shown as 'mbed Serial Port(COM#)'

/media/uploads/tsungta/mbed_serial_port_1.png

Committer:
silviaChen
Date:
Thu Oct 13 07:34:53 2016 +0000
Revision:
0:c7bcc0b36b5e
Child:
1:82331af3e4c9
First commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
silviaChen 0:c7bcc0b36b5e 1 /* mbed Microcontroller Library
silviaChen 0:c7bcc0b36b5e 2 * Copyright (c) 2006-2015 ARM Limited
silviaChen 0:c7bcc0b36b5e 3 *
silviaChen 0:c7bcc0b36b5e 4 * Licensed under the Apache License, Version 2.0 (the "License");
silviaChen 0:c7bcc0b36b5e 5 * you may not use this file except in compliance with the License.
silviaChen 0:c7bcc0b36b5e 6 * You may obtain a copy of the License at
silviaChen 0:c7bcc0b36b5e 7 *
silviaChen 0:c7bcc0b36b5e 8 * http://www.apache.org/licenses/LICENSE-2.0
silviaChen 0:c7bcc0b36b5e 9 *
silviaChen 0:c7bcc0b36b5e 10 * Unless required by applicable law or agreed to in writing, software
silviaChen 0:c7bcc0b36b5e 11 * distributed under the License is distributed on an "AS IS" BASIS,
silviaChen 0:c7bcc0b36b5e 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
silviaChen 0:c7bcc0b36b5e 13 * See the License for the specific language governing permissions and
silviaChen 0:c7bcc0b36b5e 14 * limitations under the License.
silviaChen 0:c7bcc0b36b5e 15 */
silviaChen 0:c7bcc0b36b5e 16
silviaChen 0:c7bcc0b36b5e 17 #include "mbed.h"
silviaChen 0:c7bcc0b36b5e 18 #include "ble/BLE.h"
silviaChen 0:c7bcc0b36b5e 19 #include "ble/services/HeartRateService.h"
silviaChen 0:c7bcc0b36b5e 20 #include "ble/services/BatteryService.h"
silviaChen 0:c7bcc0b36b5e 21 #include "ble/services/DeviceInformationService.h"
silviaChen 0:c7bcc0b36b5e 22
silviaChen 0:c7bcc0b36b5e 23 DigitalOut led1(LED1);
silviaChen 0:c7bcc0b36b5e 24
silviaChen 0:c7bcc0b36b5e 25 const static char DEVICE_NAME[] = "DELTA_HRM1";
silviaChen 0:c7bcc0b36b5e 26 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE,
silviaChen 0:c7bcc0b36b5e 27 GattService::UUID_DEVICE_INFORMATION_SERVICE};
silviaChen 0:c7bcc0b36b5e 28 static volatile bool triggerSensorPolling = false;
silviaChen 0:c7bcc0b36b5e 29
silviaChen 0:c7bcc0b36b5e 30 uint8_t hrmCounter = 100; // init HRM to 100bps
silviaChen 0:c7bcc0b36b5e 31
silviaChen 0:c7bcc0b36b5e 32 HeartRateService *hrService;
silviaChen 0:c7bcc0b36b5e 33 DeviceInformationService *deviceInfo;
silviaChen 0:c7bcc0b36b5e 34
silviaChen 0:c7bcc0b36b5e 35 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
silviaChen 0:c7bcc0b36b5e 36 {
silviaChen 0:c7bcc0b36b5e 37 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); // restart advertising
silviaChen 0:c7bcc0b36b5e 38 }
silviaChen 0:c7bcc0b36b5e 39
silviaChen 0:c7bcc0b36b5e 40 void periodicCallback(void)
silviaChen 0:c7bcc0b36b5e 41 {
silviaChen 0:c7bcc0b36b5e 42 led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
silviaChen 0:c7bcc0b36b5e 43
silviaChen 0:c7bcc0b36b5e 44 /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
silviaChen 0:c7bcc0b36b5e 45 * heavy-weight sensor polling from the main thread. */
silviaChen 0:c7bcc0b36b5e 46 triggerSensorPolling = true;
silviaChen 0:c7bcc0b36b5e 47 }
silviaChen 0:c7bcc0b36b5e 48
silviaChen 0:c7bcc0b36b5e 49 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
silviaChen 0:c7bcc0b36b5e 50 {
silviaChen 0:c7bcc0b36b5e 51 BLE &ble = params->ble;
silviaChen 0:c7bcc0b36b5e 52 ble_error_t error = params->error;
silviaChen 0:c7bcc0b36b5e 53
silviaChen 0:c7bcc0b36b5e 54 if (error != BLE_ERROR_NONE) {
silviaChen 0:c7bcc0b36b5e 55 return;
silviaChen 0:c7bcc0b36b5e 56 }
silviaChen 0:c7bcc0b36b5e 57
silviaChen 0:c7bcc0b36b5e 58 ble.gap().onDisconnection(disconnectionCallback);
silviaChen 0:c7bcc0b36b5e 59
silviaChen 0:c7bcc0b36b5e 60 /* Setup primary service. */
silviaChen 0:c7bcc0b36b5e 61 hrService = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
silviaChen 0:c7bcc0b36b5e 62
silviaChen 0:c7bcc0b36b5e 63 /* Setup auxiliary service. */
silviaChen 0:c7bcc0b36b5e 64 deviceInfo = new DeviceInformationService(ble, "DELTA", "NQ620", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
silviaChen 0:c7bcc0b36b5e 65
silviaChen 0:c7bcc0b36b5e 66 /* Setup advertising. */
silviaChen 0:c7bcc0b36b5e 67 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
silviaChen 0:c7bcc0b36b5e 68 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
silviaChen 0:c7bcc0b36b5e 69 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
silviaChen 0:c7bcc0b36b5e 70 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
silviaChen 0:c7bcc0b36b5e 71 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
silviaChen 0:c7bcc0b36b5e 72 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
silviaChen 0:c7bcc0b36b5e 73 ble.gap().startAdvertising();
silviaChen 0:c7bcc0b36b5e 74 }
silviaChen 0:c7bcc0b36b5e 75
silviaChen 0:c7bcc0b36b5e 76 int main(void)
silviaChen 0:c7bcc0b36b5e 77 {
silviaChen 0:c7bcc0b36b5e 78 led1 = 1;
silviaChen 0:c7bcc0b36b5e 79 Ticker ticker;
silviaChen 0:c7bcc0b36b5e 80 ticker.attach(periodicCallback, 1); // blink LED every second
silviaChen 0:c7bcc0b36b5e 81
silviaChen 0:c7bcc0b36b5e 82 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
silviaChen 0:c7bcc0b36b5e 83 ble.init(bleInitComplete);
silviaChen 0:c7bcc0b36b5e 84
silviaChen 0:c7bcc0b36b5e 85 /* SpinWait for initialization to complete. This is necessary because the
silviaChen 0:c7bcc0b36b5e 86 * BLE object is used in the main loop below. */
silviaChen 0:c7bcc0b36b5e 87 while (ble.hasInitialized() == false) { /* spin loop */ }
silviaChen 0:c7bcc0b36b5e 88
silviaChen 0:c7bcc0b36b5e 89 // infinite loop
silviaChen 0:c7bcc0b36b5e 90 while (1) {
silviaChen 0:c7bcc0b36b5e 91 // check for trigger from periodicCallback()
silviaChen 0:c7bcc0b36b5e 92 if (triggerSensorPolling && ble.getGapState().connected) {
silviaChen 0:c7bcc0b36b5e 93 triggerSensorPolling = false;
silviaChen 0:c7bcc0b36b5e 94
silviaChen 0:c7bcc0b36b5e 95 // Do blocking calls or whatever is necessary for sensor polling.
silviaChen 0:c7bcc0b36b5e 96 // In our case, we simply update the HRM measurement.
silviaChen 0:c7bcc0b36b5e 97 hrmCounter++;
silviaChen 0:c7bcc0b36b5e 98 if (hrmCounter == 175) { // 100 <= HRM bps <=175
silviaChen 0:c7bcc0b36b5e 99 hrmCounter = 100;
silviaChen 0:c7bcc0b36b5e 100 }
silviaChen 0:c7bcc0b36b5e 101
silviaChen 0:c7bcc0b36b5e 102 hrService->updateHeartRate(hrmCounter);
silviaChen 0:c7bcc0b36b5e 103 } else {
silviaChen 0:c7bcc0b36b5e 104 ble.waitForEvent(); // low power wait for event
silviaChen 0:c7bcc0b36b5e 105 }
silviaChen 0:c7bcc0b36b5e 106 }
silviaChen 0:c7bcc0b36b5e 107 }