Bill Siever / Mbed OS nRF5-DK-HeartRateDemo

Fork of nRF5-DK-HeartRateDemo by Bill Siever

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include <events/mbed_events.h>
00002 #include <mbed.h>
00003 #include "ble/BLE.h"
00004 #include "ble/Gap.h"
00005 
00006 // Uses the provided Service Classes:  
00007 // (Local copies with comments are used rather than "ble/services/NAME" versions
00008 #include "DeviceInformationService.h"
00009 #include "HeartRateService.h"
00010 
00011 // If debug is "true", include code to print debugging messages to the "console"
00012 #define DEBUG 1
00013 #if DEBUG
00014 #define LOG_PRINTF(...) eventQueue.call(printf, __VA_ARGS__);
00015 #else
00016 #define LOG_PRINTF(...) ;
00017 #endif
00018 
00019 /***********************************************************************
00020 I. Global Variables: 
00021    This section declares "global variable" (variables that are used 
00022    in multiple functions in this file)
00023 ************************************************************************/
00024 
00025 // A. A way to keep track of the heart rate service object
00026 // Declare a pointer to a heart rate service object.  (This variable isn't
00027 // an actual object.  It's used like Java Reference Variables --- it can refer
00028 // to a heart rate service object, but doesn't until it is initialized)
00029 // Pointers are used because the heart rate service constructor requires a BLE 
00030 // object in its constructors, which isn't available when the program first starts
00031 // The Object won't exist until created with "new" (
00032  HeartRateService *pHrs;  
00033  
00034 // B. A way to create new "events" 
00035 /* Total size of space for eventQueue = event count * event size  */
00036 EventQueue eventQueue( 16 * 32);
00037 
00038 // C. Setup the interrupt pins for any buttons
00039 InterruptIn buttons[4] = { InterruptIn(P0_13), InterruptIn(P0_14), InterruptIn(P0_15), InterruptIn(P0_16) };
00040 
00041 // D. Variable to contain the heart rate value
00042 uint8_t heartRate = 0;
00043 
00044 
00045 /***********************************************************************
00046 II. Event "Call backs": 
00047    This section contains functions that are called to respond to events.
00048    (Each of these is "set" as a callback somewhere in the following code too)
00049 ************************************************************************/
00050 
00051 // A. Callback for things to do when a device disconnects
00052 void bleDisconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) {
00053     LOG_PRINTF(__func__);  // Print the function's name
00054     
00055     // Start advertising for a new connection
00056     BLE::Instance().gap().startAdvertising();
00057 }
00058 
00059 
00060 // B. Callback for things to do when the BLE object is ready
00061 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) {
00062     LOG_PRINTF(__func__);  // Print the function's name
00063     
00064     // Get the BLE object
00065     BLE&        ble   = BLE::Instance();
00066 
00067     // Create the HeartRateService Object with initial value of 0 and "OTHER" location 
00068     // (The object's constructor automatically adds the service)
00069     pHrs = new HeartRateService(ble, heartRate, HeartRateService::LOCATION_OTHER );
00070 
00071     // Add in a Device Information Service object too.
00072     // Argument order:                "Manufacturer", "Model No", "Serial No", "Hardware Rev", "Firmware Rev", "Software Rev"
00073     new DeviceInformationService(ble, "Acme",         "1A",        "123",      "v1.1",         "r2a",          "r3");
00074 
00075     // Setup the "onDisconnection()" callback 
00076     // Connection info is handeled by GAP (Generic ACCESS Protocol), hence the ble.gap() part
00077     ble.gap().onDisconnection(bleDisconnectionCallback);
00078 
00079 
00080     // Setup advertising: Build the "payload" 
00081     // Add in the mode (discoverable / low energy only)
00082     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
00083     // Include a list of services in the advertising packet
00084     uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE};
00085     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *) uuid16_list, sizeof(uuid16_list));
00086 
00087     // Include the device name in the advertising packet
00088     char     DEVICE_NAME[] = "HRM";
00089     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *) DEVICE_NAME, sizeof(DEVICE_NAME));
00090     // Add the fact that it's "connectable" to the advertising packet (and that its not directed to a specific device)
00091     ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
00092     // Wait 1S between advertising packets.  Shorter will lead to faster connections but more power consumption
00093     // Longer will usually lead to slower times-to-connect, but lower power consumption
00094     ble.gap().setAdvertisingInterval(1000); /* 1000ms */  
00095 
00096     // Also set the device name in the GAP level 
00097     ble.setDeviceName((uint8_t*)DEVICE_NAME);  // Set the "GAP Name" too.
00098 
00099     // Start advertising
00100     ble.gap().startAdvertising();
00101 }
00102 
00103 void buttonsPress() {
00104     LOG_PRINTF(__func__);  // Print the function's name
00105     // Display the buttons that are pressed
00106     
00107     // Do NOT use printf() in callbacks.  Put all printing on tasks handled by the event queue. 
00108     // (This uses the debug macro provided to call printf() with arguments)
00109     for(int i=0;i<sizeof(buttons)/sizeof(InterruptIn);i++) {
00110         if(buttons[i].read()==0)
00111           LOG_PRINTF("\t%d down\r\n",i+1);
00112     }
00113     if(buttons[0].read()==0) {
00114         heartRate++;
00115         pHrs->updateHeartRate(heartRate);
00116     } else 
00117     if(buttons[1].read()==0) {
00118         heartRate--;
00119         pHrs->updateHeartRate(heartRate);
00120     }
00121 }
00122 
00123 // C. Callback to respond to BLE events.  This will add a function call to the 
00124 // Event Queue to process the event. 
00125 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
00126     BLE &ble = BLE::Instance();
00127     eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
00128 }
00129 
00130 /***********************************************************************
00131 III. main() thread 
00132    This section will run initially and configure/start everything else.
00133    ************************************************************************/
00134 
00135 
00136 int main() {
00137     LOG_PRINTF(__func__);  // Print the function's name
00138     // Configure the buttons.  
00139     for(int i=0;i<sizeof(buttons)/sizeof(InterruptIn); i++) {
00140         // Pull the button voltages "up" to 3v by default
00141         buttons[i].mode(PullUp);     
00142         // Callback for when the button falls to a 0 (when the button is pressed)
00143         buttons[i].fall(&buttonsPress);  
00144     }
00145     
00146     // Get access to the BLE object
00147     BLE &ble = BLE::Instance();
00148     // Set the BLE object to use the event queue to process any BLE events
00149     // (So when a BLE event occurs, a function to respond to it will be placed in the event queue)
00150     ble.onEventsToProcess(scheduleBleEventsProcessing);
00151  
00152     // Initialize the BLE object
00153     ble.init(bleInitComplete);
00154 
00155     // Let the "event queue" take over
00156     eventQueue.dispatch_forever();
00157 
00158     return 0;
00159 }