This is an example Heart Rate Service created using a C-like approach. Rather than creating the service as a class and then using an instance of it, the service is entirely done with simple functions and variables.
Fork of nRF5-DK-HeartRateDemo by
source/main.cpp
- Committer:
- bsiever
- Date:
- 2016-11-11
- Revision:
- 2:b850666f3c8f
- Parent:
- 0:3a7b472313d7
- Child:
- 3:f593ad98fe21
File content as of revision 2:b850666f3c8f:
#include <events/mbed_events.h> #include <mbed.h> #include "ble/BLE.h" #include "ble/Gap.h" // Uses the provided Service Classes: // (Local copies with comments are used rather than "ble/services/NAME" versions #include "DeviceInformationService.h" #include "HeartRateService.h" // If debug is "true", include code to print debugging messages to the "console" #define DEBUG 1 #if DEBUG #define LOG_PRINTF(...) eventQueue.call(printf, __VA_ARGS__); #else #define LOG_PRINTF(...) ; #endif /*********************************************************************** I. Global Variables: This section declares "global variable" (variables that are used in multiple functions in this file) ************************************************************************/ // A. A way to keep track of the heart rate service object // Declare a pointer to a heart rate service object. (This variable isn't // an actual object. It's used like Java Reference Variables --- it can refer // to a heart rate service object, but doesn't until it is initialized) // Pointers are used because the heart rate service constructor requires a BLE // object in its constructors, which isn't available when the program first starts // The Object won't exist until created with "new" ( HeartRateService *pHrs; // B. A way to create new "events" /* Total size of space for eventQueue = event count * event size */ EventQueue eventQueue( 16 * 32); // C. Setup the interrupt pins for any buttons InterruptIn buttons[4] = { InterruptIn(P0_13), InterruptIn(P0_14), InterruptIn(P0_15), InterruptIn(P0_16) }; // D. Variable to contain the heart rate value uint8_t heartRate = 0; /*********************************************************************** II. Event "Call backs": This section contains functions that are called to respond to events. (Each of these is "set" as a callback somewhere in the following code too) ************************************************************************/ // A. Callback for things to do when a device disconnects void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { LOG_PRINTF(__func__); // Print the function's name // Start advertising for a new connection BLE::Instance().gap().startAdvertising(); } // B. Callback for things to do when the BLE object is ready void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) { LOG_PRINTF(__func__); // Print the function's name // Get the BLE object BLE& ble = BLE::Instance(); // Create the HeartRateService Object with initial value of 0 and "OTHER" location // (The object's constructor automatically adds the service) pHrs = new HeartRateService(ble, heartRate, HeartRateService::LOCATION_OTHER); // Add in a Device Information Service object too. // Argument order: "Manufacturer", "Model No", "Serial No", "Hardware Rev", "Firmware Rev", "Software Rev" new DeviceInformationService(ble, "Acme", "1A", "123", "v1.1", "r2a", "r3"); // Setup the "onDisconnection()" callback // Connection info is handeled by GAP (Generic ACCESS Protocol), hence the ble.gap() part ble.gap().onDisconnection(bleDisconnectionCallback); // Setup advertising: Build the "payload" // Add in the mode (discoverable / low energy only) ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); // Include a list of services in the advertising packet uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE}; ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *) uuid16_list, sizeof(uuid16_list)); // Include the device name in the advertising packet char DEVICE_NAME[] = "HRM"; ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME)); // Add the fact that it's "connectable" to the advertising packet (and that its not directed to a specific device) ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); // Wait 1S between advertising packets. Shorter will lead to faster connections but more power consumption // Longer will usually lead to slower times-to-connect, but lower power consumption ble.gap().setAdvertisingInterval(1000); /* 1000ms */ // Also set the device name in the GAP level ble.setDeviceName((uint8_t*)DEVICE_NAME); // Set the "GAP Name" too. // Start advertising ble.gap().startAdvertising(); } void buttonsPress() { LOG_PRINTF(__func__); // Print the function's name // Display the buttons that are pressed // Do NOT use printf() in callbacks. Put all printing on tasks handled by the event queue. // (This uses the debug macro provided to call printf() with arguments) for(int i=0;i<sizeof(buttons)/sizeof(InterruptIn);i++) { if(buttons[i].read()==0) LOG_PRINTF("\t%d down\r\n",i+1); } if(buttons[0].read()==0) { heartRate++; pHrs->updateHeartRate(heartRate); } else if(buttons[1].read()==0) { heartRate--; pHrs->updateHeartRate(heartRate); } } // C. Callback to respond to BLE events. This will add a function call to the // Event Queue to process the event. void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { BLE &ble = BLE::Instance(); eventQueue.call(Callback<void()>(&ble, &BLE::processEvents)); } /*********************************************************************** III. main() thread This section will run initially and configure/start everything else. ************************************************************************/ int main() { LOG_PRINTF(__func__); // Print the function's name // Configure the buttons. for(int i=0;i<sizeof(buttons)/sizeof(InterruptIn); i++) { // Pull the button voltages "up" to 3v by default buttons[i].mode(PullUp); // Callback for when the button falls to a 0 (when the button is pressed) buttons[i].fall(&buttonsPress); } // Get access to the BLE object BLE &ble = BLE::Instance(); // Set the BLE object to use the event queue to process any BLE events // (So when a BLE event occurs, a function to respond to it will be placed in the event queue) ble.onEventsToProcess(scheduleBleEventsProcessing); // Initialize the BLE object ble.init(bleInitComplete); // Let the "event queue" take over eventQueue.dispatch_forever(); return 0; }