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

Files at this revision

API Documentation at this revision

Comitter:
Bobty
Date:
Tue Mar 01 13:03:32 2016 +0000
Parent:
5:2682353a8c32
Commit message:
Completed work on display and alarm

Changed in this revision

LedDisplay.h Show annotated file Show diff for this revision Revisions of this file
WatchTimeService.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
nRF51822.lib Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LedDisplay.h	Tue Mar 01 13:03:32 2016 +0000
@@ -0,0 +1,184 @@
+#ifndef __LED_DISPLAY_H__
+#define __LED_DISPLAY_H__
+
+#include "nrf51_rtc.h"
+
+// Hour LEDs
+const int numHourPins = 5;
+DigitalOut hourPins[numHourPins] = { p0, p1, p2, p3, p4 };
+
+// Minute LEDs
+const int numMinPins = 6;
+DigitalOut minPins[numMinPins] = { p23, p24, p25, p28, p29, p30 };
+
+// Status LEDs
+const int numStatusPins = 3;
+DigitalOut statusPins[numStatusPins] = { p6, p10, p11 };
+
+// Status bit numbers
+const int STATUS_BITS_EXTRA_BIT = 0;
+const int STATUS_BITS_SECS_BIT = 1;
+const int STATUS_BITS_ALARM_BIT = 2;
+
+void callbackForLEDMuxing();
+
+class LedDisplay
+{
+public:
+    enum DispType {
+        DispType_None = 0,
+        DispType_CurTime = 1,
+        DispType_AlarmTime = 2,
+        };
+    
+    LedDisplay()
+    {
+        _dispType = DispType_None;
+        _timeDisplayStartTime = 0;
+        _secsToDisplayFor = 0;
+        _timeToShow_Hour = 0;
+        _timeToShow_Min = 0;
+        _statusBits = 0;
+        _curTimeLEDBitPos = 0;
+        clear();
+    }
+
+    void clear()
+    {
+        // Clear all LEDs
+        for (int i = 0; i < numHourPins; i++)
+            hourPins[i] = 0;
+        for (int i = 0; i < numMinPins; i++)
+            minPins[i] = 0;
+        for (int i = 0; i < numStatusPins; i++)
+            statusPins[i] = 0;
+    }
+    
+    void start(time_t timeToShow, DispType dispType, int secsToDisplayFor, bool extraInfoBit)
+    {
+        // Save time to show
+        _timeToShow_time_t = timeToShow;
+        _dispType = dispType;
+        _secsToDisplayFor = secsToDisplayFor;
+        if (dispType == DispType_None)
+            return;
+
+        // Convert time to binary displayable info (localtime)
+        if (((int)_timeToShow_time_t != -1) && ((int)_timeToShow_time_t != 0))
+        {
+            struct tm * timeinfo;
+            timeinfo = localtime (&_timeToShow_time_t);           
+            _timeToShow_Hour = timeinfo->tm_hour;
+            _timeToShow_Min = timeinfo->tm_min;
+        }
+        else
+        {
+            _timeToShow_Hour = 0;
+            _timeToShow_Min = 0;
+        }
+        
+        // Status - extra bit
+        _statusBits = 0;
+        if (extraInfoBit)
+            _statusBits |= (1 << STATUS_BITS_EXTRA_BIT);
+            
+        // Status - alarm bit
+        if (dispType == DispType_AlarmTime)
+            _statusBits |= (1 << STATUS_BITS_ALARM_BIT);
+        else
+            _statusBits &= (~(1 << STATUS_BITS_ALARM_BIT));
+        
+        // Record time we started displaying
+        time_t curTime = rtc.time();
+        _timeDisplayStartTime = curTime;
+
+        // Ready to display on next callback
+        _curTimeLEDBitPos = 0;
+        _timerForLEDMuxing.attach(callbackForLEDMuxing, 0.001);
+
+    }
+    
+    void stop()
+    {
+        _dispType = DispType_None;
+    }
+    
+    void showNext()
+    {
+        // Clear LEDs
+        clear();
+
+        // Check display type
+        if (_dispType == DispType_None)
+            return;
+
+        // Get current time
+        time_t curTime = rtc.time();
+        
+        // Stop displaying time after a certain number of seconds
+        if (curTime - _timeDisplayStartTime >= _secsToDisplayFor)
+        {
+            stop();
+            return;
+        }
+    
+        // Flash status seconds
+        if (_dispType == DispType_CurTime)
+        {
+            if ((curTime % 2) == 0)
+                _statusBits |= (1 << STATUS_BITS_SECS_BIT);
+            else
+                _statusBits &= (~(1 << STATUS_BITS_SECS_BIT));
+        }
+        
+        // Display binary time
+        int mask = 1 << _curTimeLEDBitPos;
+        if ((_curTimeLEDBitPos < numHourPins) && ((_timeToShow_Hour & mask) != 0))
+            hourPins[_curTimeLEDBitPos] = 1;
+        if ((_curTimeLEDBitPos < numMinPins) && ((_timeToShow_Min & mask) != 0))
+            minPins[_curTimeLEDBitPos] = 1;
+        if ((_curTimeLEDBitPos < numStatusPins) && ((_statusBits & mask) != 0))
+            statusPins[_curTimeLEDBitPos] = 1;
+        
+        // Next bit pos
+        _curTimeLEDBitPos++;
+        if (_curTimeLEDBitPos > numMinPins)
+            _curTimeLEDBitPos = 0;
+    
+        // Set for another callback
+        _timerForLEDMuxing.attach(callbackForLEDMuxing, 0.001);
+    }
+    
+private:
+
+    // Display type
+    DispType _dispType;
+
+    // Time to show
+    time_t _timeToShow_time_t;
+    int _timeToShow_Hour;
+    int _timeToShow_Min;
+    
+    // Time displaying started and time to show for
+    time_t _timeDisplayStartTime;
+    int _secsToDisplayFor;
+    
+    // Status bit
+    int _statusBits;
+    
+    // Timeout used to display LEDs
+    Timeout _timerForLEDMuxing;
+    
+    // Cur time disp info
+    int _curTimeLEDBitPos;
+};
+
+static LedDisplay ledDisplay;
+
+void callbackForLEDMuxing()
+{
+    ledDisplay.showNext();
+}
+
+
+#endif /* #ifndef __BLE_BUTTON_SERVICE_H__ */
\ No newline at end of file
--- a/WatchTimeService.h	Mon Dec 14 22:58:31 2015 +0000
+++ b/WatchTimeService.h	Tue Mar 01 13:03:32 2016 +0000
@@ -4,38 +4,73 @@
 #ifndef __BLE_WATCHTIME_SERVICE_H__
 #define __BLE_WATCHTIME_SERVICE_H__
 
-//typedef void (*GetCurTimeCallbackFn)(uint8_t* curWatchTime)
-
 class WatchTimeService {
 public:
 
     static const int WatchTime_BlockSize = 7;
     const static uint16_t WATCHTIME_SERVICE_UUID              = 0xFE32;
     const static uint16_t WATCHTIME_STATE_CHARACTERISTIC_UUID = 0xFE33;
+    const static uint16_t ALARMTIME_STATE_CHARACTERISTIC_UUID = 0xFE34;
 
-    WatchTimeService(BLE &ble, uint8_t* pInitialWatchTime) :
+    WatchTimeService(BLE &ble, uint8_t* pInitialWatchTime, uint8_t* pInitialAlarmTime) :
         _ble(ble), 
-        _watchTimeVal(WATCHTIME_STATE_CHARACTERISTIC_UUID, pInitialWatchTime, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)
+        _watchTimeVal(WATCHTIME_STATE_CHARACTERISTIC_UUID, pInitialWatchTime, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY),
+        _alarmTimeVal(ALARMTIME_STATE_CHARACTERISTIC_UUID, pInitialAlarmTime, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)        
     {
-        GattCharacteristic *charTable[] = {&_watchTimeVal};
+        GattCharacteristic *charTable[] = {&_watchTimeVal, &_alarmTimeVal};
         GattService watchTimeService(WatchTimeService::WATCHTIME_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
         _ble.gattServer().addService(watchTimeService);
     }
 
-    void writeWatchTime(uint8_t* pWatchTime)
+    void writeWatchTime(time_t timeToWrite)
     {
-        _ble.gattServer().write(_watchTimeVal.getValueHandle(), pWatchTime, WatchTime_BlockSize);
+        uint8_t watchTime[WatchTimeService::WatchTime_BlockSize];
+        unixTimeToWatchTime(timeToWrite, watchTime);
+        _ble.gattServer().write(_watchTimeVal.getValueHandle(), watchTime, WatchTime_BlockSize);
     }
 
-    GattAttribute::Handle_t getValueHandle()
+    GattAttribute::Handle_t getWatchTimeValueHandle()
     {
         return _watchTimeVal.getValueHandle();
     }
+    
+    GattAttribute::Handle_t getAlarmTimeValueHandle()
+    {
+        return _alarmTimeVal.getValueHandle();
+    }
+    
+    static time_t watchTimeToUnixTime(const uint8_t* pWatchTime)
+    {
+        struct tm tminfo;
+        tminfo.tm_year = int(pWatchTime[0])*256 + pWatchTime[1] - 1900;
+        tminfo.tm_mon = pWatchTime[2] - 1;
+        tminfo.tm_mday = pWatchTime[3];
+        tminfo.tm_hour = pWatchTime[4];
+        tminfo.tm_min = pWatchTime[5];
+        tminfo.tm_sec = pWatchTime[6];
+        tminfo.tm_isdst = -1;
+        time_t timest = mktime(&tminfo);
+        return timest;
+    }
+    
+    static void unixTimeToWatchTime(time_t unixTime, uint8_t* pWatchTime)
+    {
+        // Convert to localtime
+        struct tm * timeinfo;     
+        timeinfo = localtime (&unixTime);
+        pWatchTime[0] = (timeinfo->tm_year + 1900) / 256;
+        pWatchTime[1] = (timeinfo->tm_year + 1900) % 256;
+        pWatchTime[2] = timeinfo->tm_mon + 1;
+        pWatchTime[3] = timeinfo->tm_mday;
+        pWatchTime[4] = timeinfo->tm_hour;
+        pWatchTime[5] = timeinfo->tm_min;
+        pWatchTime[6] = timeinfo->tm_sec;
+    }
 
 private:
     BLE &_ble;
     ReadWriteArrayGattCharacteristic<uint8_t, WatchTime_BlockSize> _watchTimeVal;
-//    GetCurTimeCallbackFn _pGetCurTimeCallback;
+    ReadWriteArrayGattCharacteristic<uint8_t, WatchTime_BlockSize> _alarmTimeVal;
 };
 
 #endif /* #ifndef __BLE_WATCHTIME_SERVICE_H__ */
--- a/main.cpp	Mon Dec 14 22:58:31 2015 +0000
+++ b/main.cpp	Tue Mar 01 13:03:32 2016 +0000
@@ -4,188 +4,136 @@
 
 #include "mbed.h"
 #include "BLE.h"
-#include "ButtonService.h"
+#include "LedDisplay.h"
 #include "WatchTimeService.h"
 #include "nrf51_rtc.h"
+#include "DFUService.h"
 
 // BLE platform
 BLE ble;
 
-// Hour LEDs
-DigitalOut hourPins[5] = { p0, p1, p2, p3, p4 };
-
-// Minute LEDs
-DigitalOut minPins[6] = { p23, p24, p25, p28, p29, p30 };
-
 // Button press to show time
 InterruptIn button(p5);
 
+// Vibration motor
+DigitalOut vibrationMotor(p9);
+
 // Device name - this is the visible name of device on BLE
 const static char DEVICE_NAME[] = "JoesAlarm";
 
 // UUIDs of services offered
-static const uint16_t uuid16_list[] = {ButtonService::BUTTON_SERVICE_UUID, WatchTimeService::WATCHTIME_SERVICE_UUID};
+static const uint16_t uuid16_list[] = {WatchTimeService::WATCHTIME_SERVICE_UUID};
 
 // Service offering to read and set the time on the watch
 WatchTimeService *pWatchTimeService;
 
-// Time display state variables
-const int timeDisplayState_None = 0;
-const int timeDisplayState_ShowTime = 1;
-const int timeDisplayState_ShowAlarm = 2;
-int timeDisplayState = timeDisplayState_None;
-uint8_t curBinaryLedDisplayVal[WatchTimeService::WatchTime_BlockSize];
-int timeDisplayLastButtonTime = 0;
-const int timeDisplayShowTimeSecs = 10;
-const int timeDisplayMoveToShowAlarmSecs = 5;
+// Time watch button last pressed
+time_t watchButtonLastPressed = 0;
 
-// Cur time disp info
-int curTimeLEDBitPos = 0;
+// Time between periodic callbacks used to keep RTC functioning
+const int PERIODIC_CALLBACK_SECS = 2;
+
+// Time for double press detection (2 presses within this number of secs == double press)
+const int DOUBLE_PRESS_SECS = 2;
 
-// TEST CODE
-int callbackCount = 0;
-uint8_t testbuf[WatchTimeService::WatchTime_BlockSize];
-time_t retval = 0;
-int servcode = 0;
-int buflen = 0;
-int mycode = 0;
-int offs = 0;
-int butcode = 0;
-ButtonService *buttonServicePtr;
-Ticker periodicCallbackToKeepTimerGoing;
-Timeout timerForLEDMuxing;
+// Time to display LEDs
+const int DISPLAY_ON_TIME = 5;
+
+// Alarm on time
+const int ALARM_ON_TIME = 120;
+
+// Control whether time characteristic is updated when BLE is connected
+// This is currently set false because it is probably not needed - really just a debug function
+// and, since the code runs in an interrupt, it may be brittle although it seems to work ok
+int UPDATE_BLE_TIME_WHEN_CONNECTED = false;
+
+// Time alarm set to
+time_t alarmSetTime = 0;
 
-time_t watchTimeToUnix(const uint8_t* pWatchTime)
+// Ticker needed to keep the RTC from losing time on counter rollover
+Ticker periodicCallbackToKeepTimerGoing;
+
+// Timeout to avoid bounce on button
+Timeout buttonDebounceTimeout;
+bool buttonAlreadyPressed = false;
+
+// Alarm state
+enum AlarmState
 {
-    struct tm tminfo;
-    tminfo.tm_year = int(pWatchTime[0])*256 + pWatchTime[1] - 1900;
-    tminfo.tm_mon = pWatchTime[2] - 1;
-    tminfo.tm_mday = pWatchTime[3];
-    tminfo.tm_hour = pWatchTime[4];
-    tminfo.tm_min = pWatchTime[5];
-    tminfo.tm_sec = pWatchTime[6];
-    tminfo.tm_isdst = -1;
-    time_t timest = mktime(&tminfo);
-    return timest;
-}
+    AlarmState_off,
+    AlarmState_on_sounding,
+    AlarmState_on_resting
+};
+AlarmState alarmState = AlarmState_off;
 
-void unixTimeToWatchTime(time_t unixTime, uint8_t* pWatchTime)
+// Time alarm was activated
+time_t alarmInitiatedTime = 0;
+
+// Set alarm on
+void AlarmOn()
 {
-    // Convert to localtime
-    struct tm * timeinfo;     
-    timeinfo = localtime (&unixTime);
-    pWatchTime[0] = (timeinfo->tm_year + 1900) / 256;
-    pWatchTime[1] = (timeinfo->tm_year + 1900) % 256;
-    pWatchTime[2] = timeinfo->tm_mon + 1;
-    pWatchTime[3] = timeinfo->tm_mday;
-    pWatchTime[4] = timeinfo->tm_hour;
-    pWatchTime[5] = timeinfo->tm_min;
-    pWatchTime[6] = timeinfo->tm_sec;
+    alarmState = AlarmState_on_sounding;
+    vibrationMotor = 1;
+    alarmInitiatedTime = rtc.time();
 }
 
-int watchTimeToBCD(const uint8_t* pWatchTime)
+// Set alarm on
+void AlarmOff()
 {
-    // Simply combine the hour and minute values in a 4 digit BCD number
-    int bcdHourMin = pWatchTime[4] / 10;
-    bcdHourMin = (bcdHourMin << 4) + pWatchTime[4] % 10;
-    bcdHourMin = (bcdHourMin << 4) + pWatchTime[5] / 10;
-    bcdHourMin = (bcdHourMin << 4) + pWatchTime[5] % 10;
-    return bcdHourMin;
-}
-
-void callbackForLEDMuxing();
-
-void clearTimeLEDs()
-{
-    for (int i = 0; i < 5; i++)
-        hourPins[i] = 0;
-    for (int i = 0; i < 6; i++)
-        minPins[i] = 0;
+    alarmState = AlarmState_off;
+    vibrationMotor = 0;
 }
 
-//uint8_t* GetCurTimeAsWatchTime()
-//{
-//    // Get current time and convert to displayable time
-//    time_t rawtime=rtc.time();
-//    unixTimeToWatchTime(rawtime, curBinaryLedDisplayVal);
-//}
-    
-void nextShowingTimeLEDs()
+// Button debounce callback
+void buttonDebounceCallback()
 {
-    // Get current time and convert to displayable time
-    time_t rawtime=rtc.time();
-    unixTimeToWatchTime(rawtime, curBinaryLedDisplayVal);
-    
-    // Clear LEDs
-    clearTimeLEDs();
-    
-    // Stop displaying time after a certain number of seconds
-    if (rawtime - timeDisplayLastButtonTime >= timeDisplayShowTimeSecs)
-        return;
-
-    // Display binary time
-    int hours = curBinaryLedDisplayVal[4];
-    int mins = curBinaryLedDisplayVal[5];
-    int mask = 1 << curTimeLEDBitPos;
-    if ((curTimeLEDBitPos < 5) && ((hours & mask) != 0))
-        hourPins[curTimeLEDBitPos] = 1;
-    if ((mins & mask) != 0)
-        minPins[curTimeLEDBitPos] = 1;
-    curTimeLEDBitPos++;
-    if (curTimeLEDBitPos > 5)
-        curTimeLEDBitPos = 0;
-
-    // Set for another callback
-    timerForLEDMuxing.attach(callbackForLEDMuxing, 0.001);
-}
-
-void callbackForLEDMuxing()
-{
-    nextShowingTimeLEDs();
+    buttonAlreadyPressed = false;
 }
     
-void startShowingTimeLEDs()
+bool datesAreTheSame(time_t dateTime1, time_t dateTime2)
 {
-    curTimeLEDBitPos = 0;
-    timerForLEDMuxing.attach(callbackForLEDMuxing, 0.001);
-}
-
-void stopShowingTimeLEDs()
-{
-    clearTimeLEDs();
+    struct tm * timeinfo;
+    timeinfo = localtime (&dateTime1);
+    int alarmMDay = timeinfo->tm_mday;
+    int alarmMonth = timeinfo->tm_mon;
+    int alarmYear = timeinfo->tm_year;
+    timeinfo = localtime (&dateTime2);
+    return (alarmMDay == timeinfo->tm_mday) && (alarmMonth == timeinfo->tm_mon) && (alarmYear == timeinfo->tm_year);
 }
 
 // Handle button press to read watch
 void buttonPressedCallback(void)
 {
+    // Handle debounce
+    if (buttonAlreadyPressed)
+        return;
+    buttonAlreadyPressed = true;
+    buttonDebounceTimeout.attach(buttonDebounceCallback, 0.2);
+    
+    // Stop alarm
+    AlarmOff();
+    
     // Get the time to display
-    time_t rawtime=rtc.time();
+    time_t curTime = rtc.time();
     
     // Check if we should display current time or alarm time
-    if (rawtime - timeDisplayLastButtonTime > timeDisplayMoveToShowAlarmSecs)
+    if (curTime - watchButtonLastPressed > DOUBLE_PRESS_SECS)
     {
-        timeDisplayState = timeDisplayState_ShowTime;
+        ledDisplay.start(rtc.time(), LedDisplay::DispType_CurTime, DISPLAY_ON_TIME, false);
     }
     else
     {
-        // TO BE DONE 
-        // - move alarm time value to the curBinaryLedDisplayVal
-        timeDisplayState = timeDisplayState_ShowAlarm;
+        bool alarmIsLaterToday = (alarmSetTime > curTime) && datesAreTheSame(alarmSetTime, curTime);
+        ledDisplay.start(alarmSetTime, LedDisplay::DispType_AlarmTime, DISPLAY_ON_TIME, alarmIsLaterToday);
     }
-    startShowingTimeLEDs();
     
     // Remember when button last pressed
-    timeDisplayLastButtonTime = rawtime;
-
-    // Update the button-state service
-    buttonServicePtr->updateButtonState(true);
+    watchButtonLastPressed = curTime;
 }
 
-// TEST CODE
+// Button released
 void buttonReleasedCallback(void)
 {
-    // Update the button-state service
-    buttonServicePtr->updateButtonState(false);
 }
 
 // Handle BLE disconnection - restart advertising
@@ -194,47 +142,107 @@
     ble.gap().startAdvertising();
 }
 
-// TEST CODE
+// Callback required for RTC operation
 void periodicCallback(void)
 {
     // Update the rtc library time (it says in the notes on the rtc lib that this needs to happen
     // more than once every few hundred seconds to avoid a rollover
-    rtc.time();
+    time_t curTime = rtc.time();
+    
+    // Update the time characteristic if we are connected
+    if (UPDATE_BLE_TIME_WHEN_CONNECTED)
+    {
+        Gap::GapState_t gapState = ble.gap().getState();
+        if (gapState.connected)
+        {
+            time_t curTime = rtc.time();
+            pWatchTimeService->writeWatchTime(curTime);
+        }
+    }
+    
+    // Check if alarm went off recently
+    if (alarmInitiatedTime + PERIODIC_CALLBACK_SECS*2 + ALARM_ON_TIME > curTime)
+    {
+        // Stop the alarm after it has been on for the allotted time
+        if (alarmInitiatedTime + ALARM_ON_TIME < curTime)
+            AlarmOff();
+    }
+    else
+    {
+        // Check if time for alarm
+        if (alarmSetTime > 0)
+        {
+            if ((curTime >= alarmSetTime) && (curTime < alarmSetTime + PERIODIC_CALLBACK_SECS*2))
+            {
+                AlarmOn();
+            }
+        }
+    }
+    
+    // Pulse the alarm
+    if (alarmState == AlarmState_on_sounding)
+    {
+        alarmState = AlarmState_on_resting;
+        vibrationMotor = 0;
+    }
+    else if (alarmState == AlarmState_on_resting)
+    {
+        alarmState = AlarmState_on_sounding;
+        vibrationMotor = 1;
+    }
+    
+//    // TEST TEST TEST
+//    int testMin = 0;
+//    int testHr = 0;
+//    if (testNum < 6)
+//        testMin = 1 << testNum;
+//    else
+//        testHr = 1 << (testNum - 6);
+//    testNum++;
+//    if (testNum >= 11)
+//        testNum = 0;
+//    
+//    uint8_t testTime[] = { uint8_t(2015/256), uint8_t(2015%256), 12, 18, testHr, testMin, 0 };
+//    time_t testTimeT = WatchTimeService::watchTimeToUnixTime(testTime);
+//
+//    ledDisplay.start(testTimeT, LedDisplay::DispType_CurTime, DISPLAY_ON_TIME);
+
 }
 
+// Helper
 void setRTCfromWatchTime(const uint8_t* pWatchTime)
 {
-    time_t timest = watchTimeToUnix(pWatchTime);
-    retval = timest;
+    time_t timest = WatchTimeService::watchTimeToUnixTime(pWatchTime);
     if ((int)timest != -1)
     {
         rtc.set_time(timest);
-        minPins[5] = !minPins[5];
     }
 }
 
 void onDataWrittenCallback(const GattWriteCallbackParams *params) 
 {
-    // TEST code
-    callbackCount++;
-    memcpy(testbuf, params->data, WatchTimeService::WatchTime_BlockSize);
-    servcode = params->handle;
-    buflen = params->len;
-    mycode = pWatchTimeService->getValueHandle();
-    butcode = buttonServicePtr->getValueHandle();
-    offs = params->offset;
-
     // Check if this is time setting
-    if (pWatchTimeService->getValueHandle() == params->handle) 
+    if (pWatchTimeService->getWatchTimeValueHandle() == params->handle) 
     {
         if (params->len == WatchTimeService::WatchTime_BlockSize)
         {
             setRTCfromWatchTime(params->data);
         }
     }
+    else if (pWatchTimeService->getAlarmTimeValueHandle() == params->handle) 
+    {
+        if (params->len == WatchTimeService::WatchTime_BlockSize)
+        {
+            time_t timest = WatchTimeService::watchTimeToUnixTime(params->data);
+            if (((int)timest != -1) && ((int)timest != 0))
+                alarmSetTime = timest;
+            else
+                alarmSetTime = 0;
+        }
+    }
 }
     
-// TEST CODE
+// DEBUG CODE
 void print_time() 
 {    
     time_t rawtime=rtc.time();
@@ -251,31 +259,35 @@
 {
     printf("AlarmWatch\r\n");
     
-    // TEST CODE
-    memset(testbuf, 0, WatchTimeService::WatchTime_BlockSize);
-    int loopCount = 0;
-    periodicCallbackToKeepTimerGoing.attach(periodicCallback, 1);
+    // This is necessary to keep the clock ticking - doesn't have to be so frequent
+    // According to this https://developer.mbed.org/users/fxschumacher/code/nRF51_rtc_example/file/c1f06d0a5e11/main.cpp
+    // any time less than 512 seconds is ok
+    periodicCallbackToKeepTimerGoing.attach(periodicCallback, PERIODIC_CALLBACK_SECS);
+    
+    // Handlers for the button press
     button.fall(buttonPressedCallback);
     button.rise(buttonReleasedCallback);
 
     // Clear display
-    clearTimeLEDs();
+    ledDisplay.clear();
     
     // BLE init
     ble.init();
     ble.gap().onDisconnection(disconnectionCallback);
     ble.onDataWritten(onDataWrittenCallback);
     
-    // TEST CODE
-    ButtonService buttonService(ble, false /* initial value for button pressed */);
-    buttonServicePtr = &buttonService;
-    
     // Watch Time Service
-    uint8_t initialTime[] = { uint8_t(2015/256), uint8_t(2015%256), 7, 26, 12, 8, 0 };    
-    WatchTimeService watchTimeService(ble, initialTime);
+    uint8_t initialTime[] = { uint8_t(2015/256), uint8_t(2015%256), 12, 18, 10, 10, 0 };  
+    uint8_t alarmTime[] = { 0, 0, 0, 0, 0, 0, 0 };  
+    WatchTimeService watchTimeService(ble, initialTime, alarmTime);
     setRTCfromWatchTime(initialTime);
     pWatchTimeService = &watchTimeService;
     
+    /* Enable over-the-air firmware updates. Instantiating DFUSservice introduces a
+     * control characteristic which can be used to trigger the application to
+     * handover control to a resident bootloader. */
+    DFUService dfu(ble);
+
     // Setup advertising
     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
     ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
@@ -284,175 +296,11 @@
     ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
     ble.gap().startAdvertising();
 
-    uint8_t curWatchTime[WatchTimeService::WatchTime_BlockSize];
+    // Turn off any alarm
+    AlarmOff();
+
     while (true) 
     {
         ble.waitForEvent();
-        
-        // TEST CODE    
-        loopCount++;
-        if (loopCount < 5)
-            continue;
-        loopCount = 0;
-        
-        print_time();
-        // Get current time and convert to watch time
-        time_t rawtime=rtc.time();
-        unixTimeToWatchTime(rawtime, curWatchTime);
-        pWatchTimeService->writeWatchTime(curWatchTime);
-
-        
-/*        printf ("Timest %02x %02x %02x %02x %02x %02x %02x %ld\r\n", testbuf[0],
-                testbuf[1], testbuf[2], testbuf[3], testbuf[4], testbuf[5], testbuf[6], retval); 
-        printf ("serv %d buflen %d mycode %d offs %d butcode %d\r\n", servcode, buflen, mycode, offs, butcode);
-        printf ("val %ld\r\n", watchTimeService.getValueHandle());
-        print_time();
-        
-        if (timeDisplayState != timeDisplayState_None)
-        {
-            int watchLedTime = watchTimeToBCD(curBinaryLedDisplayVal);
-            printf("watchTime %04x = ", watchLedTime);
-            for (int i = 15; i >= 0; i--)
-            {
-                printf("%d", (watchLedTime >> i) % 2);
-            }
-            printf("\r\n");
-        }
-        */
     }
 }
-
-/*
-
-#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
-GattCharacteristic timeBlockCharacteristic(UUID_TIME_BLOCK_CHARACTERISTIC, timeBlockInitValue, SIZE_OF_TIME_BLOCK, SIZE_OF_TIME_BLOCK,
-        GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
-
-// 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; 
-    testOut = !testOut;
-    tickCount++;
-    if (tickCount > 100)
-    {
-        showInfo = true;
-        tickCount = 0;
-    }
-}
-
-// Data written callback
-void onDataWrittenCallback(const GattCharacteristicWriteCBParams *params) 
-{
-    if ((params->charHandle == timeBlockCharacteristic.getValueHandle())) 
-    {
-        // Validate time
-        int year = params->data[0] * 100 + params->data[1];
-        int month = params->data[2];
-        int day = params->data[3];
-//        && (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));
-    
-
-    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;
-        }
-    }    
-}
-*/
--- a/nRF51822.lib	Mon Dec 14 22:58:31 2015 +0000
+++ b/nRF51822.lib	Tue Mar 01 13:03:32 2016 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#c7adea3c1e37
+http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#1751e2e2637a