Techcon 2014 BLE sample Police HRM (button-based) for Nordic

Dependencies:   BLE_API mbed nRF51822 BufferedSerial

main.cpp

Committer:
ansond
Date:
2014-09-26
Revision:
1:e8d3536c7f99
Parent:
0:45e5a1daf7c0

File content as of revision 1:e8d3536c7f99:

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed.h"
#include "BLEDevice.h"
#include "HeartRateService.h"

// ********************* BEGIN Tunables for TechCon 2014

// !!!!IMPORTANT!!!!  CHANGE DEVICE_NAME so that you can find *YOUR* Nordic board in the workshop on your phone!!
const static char     DEVICE_NAME[]     = "Policeman #1234";                 // what we want to appear as in mBED device server

#define HRM_INCREMENT                     10                                 // increment of HRM per button press (+/-)
#define HRM_DEFAULT_INIT                  70                                 // default HRM (button only... earbud defaults to offline status)
#define ENABLE_CONSOLE                    1                                  // 0 - no serial output, 1 - serial output

#define HRM_MIN                           10                                 // min heartrate
#define HRM_MAX                           250                                // max heartrate
#define HRM_DEFAULT_INIT                  70                                 // initial heartrate (buttons only, earbud will default differently)


// ********************* END Tunables for Techcon 2014

volatile uint16_t     hrmCounter        = HRM_DEFAULT_INIT;                  // initial heartrate 
int                   oldhrmCounter     = HRM_MAX+1;                         // tracker so that we only send when things change appropriately

// Support for the Grove Ear-Clip Earbud 
#define USE_EARBUD                        false                              // true - enable (pin P0_0),  false - disable (default) 

// Globals
BLEDevice  ble;
DigitalOut led1(LED1);
volatile bool connected = false;

// Console allocation
#if ENABLE_CONSOLE
    #include "BufferedSerial.h"
    BufferedSerial  pc(USBTX, USBRX);
    #define LOG_CONSOLE(...) { pc.printf(__VA_ARGS__); }
#else
    #define LOG_CONSOLE(...)
#endif 

// Earbud allocation (or button usage)
#if USE_EARBUD
    #include "GroveEarbudSensor.h"
    InterruptIn sensor(P0_0);
    GroveEarbudSensor earbud(&sensor,&pc);
#else
    DigitalIn up(BUTTON1);
    DigitalIn down(BUTTON2);
#endif

// BLE Globals
static const uint16_t uuid16_list[]        = {GattService::UUID_HEART_RATE_SERVICE};
static volatile bool  triggerSensorPolling = false;

// Disconnection callback
void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) {
    LOG_CONSOLE("Disconnected handle %u!\r\n", handle);
    LOG_CONSOLE("Restarting the advertising process\r\n");
    ble.startAdvertising();
    connected = false;
    oldhrmCounter = HRM_MAX+1;
#if USE_EARBUD
    hrmCounter = HEARTRATE_OFF;
#else
    hrmCounter = HRM_DEFAULT_INIT;
#endif
}

// Connection callback
void connectionCallback(Gap::Handle_t handle, const Gap::ConnectionParams_t *parms) {
    LOG_CONSOLE("Endpoint is connected!\r\n");
    connected = true;
}

// Periodic callback
void periodicCallback(void) {
    led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */

    /* Note that the periodicCallback() executes in interrupt context, so it is safer to do
     * heavy-weight sensor polling from the main thread. */
    triggerSensorPolling = true;
}

#if USE_EARBUD
// Heartrate callback (Earbud)
void heartrateCallback(float heartrate,void *data) {
    hrmCounter = (int)heartrate;
}
#endif

// main entry point
int main(void) {
    bool do_loop = true;
    led1 = 1;
    Ticker ticker;
    ticker.attach(periodicCallback, 1);

#if USE_EARBUD
    LOG_CONSOLE("\r\nmbed PoliceHRM (EARBUD) v1.0 (ARM Techcon 2014)\r\n");
#else
    LOG_CONSOLE("\r\nmbed PoliceHRM (BUTTON) v1.0 (ARM Techcon 2014)\r\n");
#endif
    ble.init();
    ble.onDisconnection(disconnectionCallback);
    ble.onConnection(connectionCallback);

    /* setup advertising */
    LOG_CONSOLE("Starting BLE Advertising...\r\n");
    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
    ble.accumulateAdvertisingPayload(GapAdvertisingData::HEART_RATE_SENSOR_HEART_RATE_BELT);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.setAdvertisingInterval(1600); /* 1000ms; in multiples of 0.625ms. */
    ble.startAdvertising();

#if USE_EARBUD
    // initialize the earbud
    LOG_CONSOLE("Initializing Earbud...\r\n");
    hrmCounter = HEARTRATE_OFF;
    earbud.registerCallback(heartrateCallback);
#endif

    // Start the HRM Service
    LOG_CONSOLE("Starting HRM Service...\r\n");
#if !USE_EARBUD
    HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_WRIST);
#else
    HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_EAR_LOBE);
#endif
     
    // Loop
    LOG_CONSOLE("Entering main loop...\r\n");
    while (do_loop) {
        if (triggerSensorPolling) {
            triggerSensorPolling = false;

#if !USE_EARBUD
            // see if either button was pressed and adjust the heartrate accordingly
            //LOG_CONSOLE("Updating HRM via button...\r\n");
            if (up) hrmCounter += HRM_INCREMENT;
            if (down) hrmCounter -= HRM_INCREMENT;
            
            // boundary checking
            if (hrmCounter <  0) hrmCounter = 0;
            else if (hrmCounter < HRM_MIN) hrmCounter = HRM_MIN;
            else if (hrmCounter > HRM_MAX) hrmCounter = HRM_MAX;
#endif

            // update the heartrate service if it has changed
            if (hrmCounter != oldhrmCounter) {
                LOG_CONSOLE("Updating HRM values...%d bpm\r\n",hrmCounter);
                hrService.updateHeartRate(hrmCounter);
                if (connected == true) oldhrmCounter = hrmCounter;
            }
        } else {
            ble.waitForEvent();
        }
    }
    
    // we have exited
    LOG_CONSOLE("Application exiting...\r\n");
}