Auto updating alarm watch - accepts alarm settings from a BLE device like a Raspberry Pi and buzzes at the appropriate time - also displays binary time

Dependencies:   BLE_API mbed-src nRF51822 nrf51_rtc

main.cpp

Committer:
Bobty
Date:
2015-03-10
Revision:
1:c3d7e673cdd2
Parent:
0:0d5ac2fd4620
Child:
2:9090120e2656

File content as of revision 1:c3d7e673cdd2:

// BLE Alarm Watch
// Based on BLE heart-rate-monitor from MBED team
// Rob Dobson, 2015

#include "mbed.h"
#include "BLEDevice.h"
#include "DeviceInformationService.h"

// BLE Device etc
BLEDevice  ble;
DigitalOut ledIndicator(LED1);
DigitalOut testOut(p1);

// Device name
const static char     DEVICE_NAME[] = "JOESALARM";

// UUID for CurTimeService & TimeBlockCharacteristic
const uint16_t UUID_CUR_TIME_SERVICE = 0xA000;
const uint16_t UUID_TIME_BLOCK_CHARACTERISTIC = 0xA001;

// List of supported service UUIDs
static const uint16_t uuid16_list[] = {UUID_CUR_TIME_SERVICE};

// Time is packed in an array of bytes
const int SIZE_OF_TIME_BLOCK = 7;
uint8_t timeBlockInitValue[SIZE_OF_TIME_BLOCK];
uint8_t curTimeBlock[SIZE_OF_TIME_BLOCK];

// GATT Characteristic for time block
ReadWriteGattCharacteristic<uint8_t> timeBlockCharacteristic(UUID_TIME_BLOCK_CHARACTERISTIC, timeBlockInitValue);

// Callback when connection lost
void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
    ble.startAdvertising(); // restart advertising
}

// Callback for ticker
int tickCount = 0;
bool showInfo = false;
int writeSinceLast = 0;
void periodicCallback(void)
{
    ledIndicator = !ledIndicator; /* Do blinky on LED1 while we're waiting for BLE events */
    testOut = !testOut;
    tickCount++;
    if (tickCount > 100)
    {
        showInfo = true;
        tickCount = 0;
    }
}

// Data written callback
void onDataWrittenCallback(const GattCharacteristicWriteCBParams *params) 
{
    if ((params->charHandle == timeBlockCharacteristic.getValueHandle())) 
    {
//        && (params->len == SIZE_OF_TIME_BLOCK)
        writeSinceLast = params->len;
        memcpy(curTimeBlock, params->data, SIZE_OF_TIME_BLOCK);
    }
    writeSinceLast = true;
}

// Main
int main(void)
{
    ledIndicator = 0;
    testOut = 0;

    // Ticker is interrupt driven
    Ticker ticker;
    ticker.attach_us(periodicCallback, 100000);

    // Initial value for the time block characteristic
    memset(timeBlockInitValue, 0, sizeof(timeBlockInitValue));

    // Init BLE and register callbacks
    ble.init();
    ble.onDisconnection(disconnectionCallback);
    ble.onDataWritten(onDataWrittenCallback);

    // Add the time setting service
    GattCharacteristic *charTable[] = {&timeBlockCharacteristic};
    GattService timeBlockService(UUID_CUR_TIME_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
    ble.addService(timeBlockService);
    
    // Setup advertising
    /* BREDR_NOT_SUPPORTED means classic bluetooth not supported;
    * LE_GENERAL_DISCOVERABLE means that this peripheral can be
    * discovered by any BLE scanner--i.e. any phone. */
    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    
    // Add services to payload
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
    
    /* This is where we're collecting the device name into the advertisement payload. */
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    
    /* We'd like for this BLE peripheral to be connectable. */
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    
    /* set the interval at which advertisements are sent out; this has
    * an implication power consumption--radio activity being a
    * biggest draw on average power. The other software controllable
    * parameter which influences power is the radio's TX power
    * level--there's an API to adjust that. */
    ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); /* 1000ms. */
    
    /* we're finally good to go with advertisements. */
    ble.startAdvertising();
    
    while (true) 
    {
        ble.waitForEvent();
        
        if (showInfo)
        {
            printf("Time info: ");
            for (int i = 0; i < SIZE_OF_TIME_BLOCK; i++)
            {
                printf("%02d", curTimeBlock[i]);
            }
            printf(" - writeSinceLast %d\r\n", writeSinceLast);
            showInfo = false;
            writeSinceLast = 0;
        }
    }    
//    /* Setup primary service. */
//    uint8_t hrmCounter = 100; // init HRM to 100bps
//    HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
//
//    /* Setup auxiliary service. */
//    DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
//
//    /* Setup advertising. */
//    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::GENERIC_HEART_RATE_SENSOR);
//    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
//    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
//    ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000));
//    ble.startAdvertising();
//
//    // infinite loop
//    while (1) {
//        // check for trigger from periodicCallback()
//        if (triggerSensorPolling && ble.getGapState().connected) {
//            triggerSensorPolling = false;
//
//            // Do blocking calls or whatever is necessary for sensor polling.
//            // In our case, we simply update the HRM measurement. 
//            hrmCounter++;
//            
//            //  100 <= HRM bps <=175
//            if (hrmCounter == 175) {
//                hrmCounter = 100;
//            }
//            
//            // update bps
//            hrService.updateHeartRate(hrmCounter);
//        } else {
//            ble.waitForEvent(); // low power wait for event
//        }
//    }
}