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#)'
main.cpp@3:f2861d705e88, 2017-03-29 (annotated)
- 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?
User | Revision | Line number | New 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 | } |