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:
tsungta
Date:
Wed Mar 29 14:34:47 2017 +0000
Revision:
3:f2861d705e88
Parent:
2:d4b007ee15dc
Add Serial to use for printf

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
tsungta 3:f2861d705e88 23 Serial uart(USBTX, USBRX);//9600 8n1 is set as default
silviaChen 0:c7bcc0b36b5e 24 DigitalOut led1(LED1);
silviaChen 0:c7bcc0b36b5e 25
tsungta 3:f2861d705e88 26 const static char DEVICE_NAME[] = "DELTA_HRM";
silviaChen 0:c7bcc0b36b5e 27 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE,
silviaChen 0:c7bcc0b36b5e 28 GattService::UUID_DEVICE_INFORMATION_SERVICE};
silviaChen 0:c7bcc0b36b5e 29 static volatile bool triggerSensorPolling = false;
silviaChen 0:c7bcc0b36b5e 30
silviaChen 0:c7bcc0b36b5e 31 uint8_t hrmCounter = 100; // init HRM to 100bps
silviaChen 0:c7bcc0b36b5e 32
silviaChen 0:c7bcc0b36b5e 33 HeartRateService *hrService;
silviaChen 0:c7bcc0b36b5e 34 DeviceInformationService *deviceInfo;
silviaChen 0:c7bcc0b36b5e 35
silviaChen 0:c7bcc0b36b5e 36 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
silviaChen 0:c7bcc0b36b5e 37 {
silviaChen 0:c7bcc0b36b5e 38 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); // restart advertising
tsungta 3:f2861d705e88 39 uart.printf("BLE Disconnected, restart advertising!!\r\n");
silviaChen 0:c7bcc0b36b5e 40 }
silviaChen 0:c7bcc0b36b5e 41
silviaChen 0:c7bcc0b36b5e 42 void periodicCallback(void)
silviaChen 0:c7bcc0b36b5e 43 {
silviaChen 0:c7bcc0b36b5e 44 led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
silviaChen 0:c7bcc0b36b5e 45
silviaChen 0:c7bcc0b36b5e 46 /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
silviaChen 0:c7bcc0b36b5e 47 * heavy-weight sensor polling from the main thread. */
silviaChen 0:c7bcc0b36b5e 48 triggerSensorPolling = true;
silviaChen 0:c7bcc0b36b5e 49 }
silviaChen 0:c7bcc0b36b5e 50
silviaChen 0:c7bcc0b36b5e 51 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
silviaChen 0:c7bcc0b36b5e 52 {
silviaChen 0:c7bcc0b36b5e 53 BLE &ble = params->ble;
silviaChen 0:c7bcc0b36b5e 54 ble_error_t error = params->error;
silviaChen 0:c7bcc0b36b5e 55
silviaChen 0:c7bcc0b36b5e 56 if (error != BLE_ERROR_NONE) {
silviaChen 0:c7bcc0b36b5e 57 return;
silviaChen 0:c7bcc0b36b5e 58 }
silviaChen 0:c7bcc0b36b5e 59
silviaChen 0:c7bcc0b36b5e 60 ble.gap().onDisconnection(disconnectionCallback);
silviaChen 0:c7bcc0b36b5e 61
silviaChen 0:c7bcc0b36b5e 62 /* Setup primary service. */
silviaChen 0:c7bcc0b36b5e 63 hrService = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
silviaChen 0:c7bcc0b36b5e 64
silviaChen 0:c7bcc0b36b5e 65 /* Setup auxiliary service. */
silviaChen 0:c7bcc0b36b5e 66 deviceInfo = new DeviceInformationService(ble, "DELTA", "NQ620", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
silviaChen 0:c7bcc0b36b5e 67
silviaChen 0:c7bcc0b36b5e 68 /* Setup advertising. */
silviaChen 0:c7bcc0b36b5e 69 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
silviaChen 0:c7bcc0b36b5e 70 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
silviaChen 0:c7bcc0b36b5e 71 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
silviaChen 0:c7bcc0b36b5e 72 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
silviaChen 0:c7bcc0b36b5e 73 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
silviaChen 0:c7bcc0b36b5e 74 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
silviaChen 0:c7bcc0b36b5e 75 ble.gap().startAdvertising();
tsungta 3:f2861d705e88 76 uart.printf("BLE start Advertising!!\r\n");
silviaChen 0:c7bcc0b36b5e 77 }
silviaChen 0:c7bcc0b36b5e 78
silviaChen 0:c7bcc0b36b5e 79 int main(void)
silviaChen 0:c7bcc0b36b5e 80 {
tsungta 3:f2861d705e88 81 uart.printf("APPLICATION START!!\r\n");
silviaChen 0:c7bcc0b36b5e 82 led1 = 1;
silviaChen 0:c7bcc0b36b5e 83 Ticker ticker;
silviaChen 0:c7bcc0b36b5e 84 ticker.attach(periodicCallback, 1); // blink LED every second
silviaChen 0:c7bcc0b36b5e 85
silviaChen 0:c7bcc0b36b5e 86 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
silviaChen 0:c7bcc0b36b5e 87 ble.init(bleInitComplete);
silviaChen 0:c7bcc0b36b5e 88
silviaChen 0:c7bcc0b36b5e 89 /* SpinWait for initialization to complete. This is necessary because the
silviaChen 0:c7bcc0b36b5e 90 * BLE object is used in the main loop below. */
silviaChen 0:c7bcc0b36b5e 91 while (ble.hasInitialized() == false) { /* spin loop */ }
silviaChen 0:c7bcc0b36b5e 92
tsungta 1:82331af3e4c9 93 ble.setTxPower(0);
tsungta 1:82331af3e4c9 94
silviaChen 0:c7bcc0b36b5e 95 // infinite loop
silviaChen 0:c7bcc0b36b5e 96 while (1) {
silviaChen 0:c7bcc0b36b5e 97 // check for trigger from periodicCallback()
silviaChen 0:c7bcc0b36b5e 98 if (triggerSensorPolling && ble.getGapState().connected) {
silviaChen 0:c7bcc0b36b5e 99 triggerSensorPolling = false;
silviaChen 0:c7bcc0b36b5e 100
silviaChen 0:c7bcc0b36b5e 101 // Do blocking calls or whatever is necessary for sensor polling.
silviaChen 0:c7bcc0b36b5e 102 // In our case, we simply update the HRM measurement.
silviaChen 0:c7bcc0b36b5e 103 hrmCounter++;
silviaChen 0:c7bcc0b36b5e 104 if (hrmCounter == 175) { // 100 <= HRM bps <=175
silviaChen 0:c7bcc0b36b5e 105 hrmCounter = 100;
silviaChen 0:c7bcc0b36b5e 106 }
silviaChen 0:c7bcc0b36b5e 107
silviaChen 0:c7bcc0b36b5e 108 hrService->updateHeartRate(hrmCounter);
tsungta 3:f2861d705e88 109 uart.printf("notify hrmCounter: %i\r\n", hrmCounter);
silviaChen 0:c7bcc0b36b5e 110 } else {
silviaChen 0:c7bcc0b36b5e 111 ble.waitForEvent(); // low power wait for event
silviaChen 0:c7bcc0b36b5e 112 }
silviaChen 0:c7bcc0b36b5e 113 }
silviaChen 0:c7bcc0b36b5e 114 }