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

Revision:
5:2682353a8c32
Parent:
4:f0b030a3223f
Child:
6:4a12e0f03381
--- a/main.cpp	Mon Jul 27 19:30:11 2015 +0000
+++ b/main.cpp	Mon Dec 14 22:58:31 2015 +0000
@@ -1,6 +1,6 @@
 // BLE Alarm Watch
 // Based on BLE examples on MBED
-// Rob Dobson, 2015
+// Rob Dobson, (c) 2015
 
 #include "mbed.h"
 #include "BLE.h"
@@ -11,14 +11,17 @@
 // BLE platform
 BLE ble;
 
-// Indicator LEDs
-DigitalOut  led1(LED1);
+// 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(D8);
+InterruptIn button(p5);
 
 // Device name - this is the visible name of device on BLE
-const static char     DEVICE_NAME[] = "JoesAlarm";
+const static char DEVICE_NAME[] = "JoesAlarm";
 
 // UUIDs of services offered
 static const uint16_t uuid16_list[] = {ButtonService::BUTTON_SERVICE_UUID, WatchTimeService::WATCHTIME_SERVICE_UUID};
@@ -26,6 +29,19 @@
 // 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;
+
+// Cur time disp info
+int curTimeLEDBitPos = 0;
+
 // TEST CODE
 int callbackCount = 0;
 uint8_t testbuf[WatchTimeService::WatchTime_BlockSize];
@@ -36,36 +52,8 @@
 int offs = 0;
 int butcode = 0;
 ButtonService *buttonServicePtr;
-
-// Handle button press to read watch
-void buttonPressedCallback(void)
-{
-// TEST CODE
-    buttonServicePtr->updateButtonState(true);
-}
-
-// TEST CODE
-void buttonReleasedCallback(void)
-{
-// TEST CODE
-    buttonServicePtr->updateButtonState(false);
-}
-
-// Handle BLE disconnection - restart advertising
-void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
-{
-    ble.gap().startAdvertising();
-}
-
-// TEST CODE
-void periodicCallback(void)
-{
-    led1 = !led1; /* Do blinky on LED1 to indicate system aliveness. */
-    
-    // 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();
-}
+Ticker periodicCallbackToKeepTimerGoing;
+Timeout timerForLEDMuxing;
 
 time_t watchTimeToUnix(const uint8_t* pWatchTime)
 {
@@ -81,6 +69,150 @@
     return timest;
 }
 
+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;
+}
+
+int watchTimeToBCD(const uint8_t* pWatchTime)
+{
+    // 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;
+}
+
+//uint8_t* GetCurTimeAsWatchTime()
+//{
+//    // Get current time and convert to displayable time
+//    time_t rawtime=rtc.time();
+//    unixTimeToWatchTime(rawtime, curBinaryLedDisplayVal);
+//}
+    
+void nextShowingTimeLEDs()
+{
+    // 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();
+}
+    
+void startShowingTimeLEDs()
+{
+    curTimeLEDBitPos = 0;
+    timerForLEDMuxing.attach(callbackForLEDMuxing, 0.001);
+}
+
+void stopShowingTimeLEDs()
+{
+    clearTimeLEDs();
+}
+
+// Handle button press to read watch
+void buttonPressedCallback(void)
+{
+    // Get the time to display
+    time_t rawtime=rtc.time();
+    
+    // Check if we should display current time or alarm time
+    if (rawtime - timeDisplayLastButtonTime > timeDisplayMoveToShowAlarmSecs)
+    {
+        timeDisplayState = timeDisplayState_ShowTime;
+    }
+    else
+    {
+        // TO BE DONE 
+        // - move alarm time value to the curBinaryLedDisplayVal
+        timeDisplayState = timeDisplayState_ShowAlarm;
+    }
+    startShowingTimeLEDs();
+    
+    // Remember when button last pressed
+    timeDisplayLastButtonTime = rawtime;
+
+    // Update the button-state service
+    buttonServicePtr->updateButtonState(true);
+}
+
+// TEST CODE
+void buttonReleasedCallback(void)
+{
+    // Update the button-state service
+    buttonServicePtr->updateButtonState(false);
+}
+
+// Handle BLE disconnection - restart advertising
+void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
+{
+    ble.gap().startAdvertising();
+}
+
+// TEST CODE
+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();
+}
+
+void setRTCfromWatchTime(const uint8_t* pWatchTime)
+{
+    time_t timest = watchTimeToUnix(pWatchTime);
+    retval = timest;
+    if ((int)timest != -1)
+    {
+        rtc.set_time(timest);
+        minPins[5] = !minPins[5];
+    }
+}
+
 void onDataWrittenCallback(const GattWriteCallbackParams *params) 
 {
     // TEST code
@@ -97,10 +229,7 @@
     {
         if (params->len == WatchTimeService::WatchTime_BlockSize)
         {
-            time_t timest = watchTimeToUnix(params->data);
-            retval = timest;
-            if (timest != -1)
-                rtc.set_time(timest);
+            setRTCfromWatchTime(params->data);
         }
     }
 }
@@ -125,12 +254,13 @@
     // TEST CODE
     memset(testbuf, 0, WatchTimeService::WatchTime_BlockSize);
     int loopCount = 0;
-    led1 = 1;
-    Ticker ticker;
-    ticker.attach(periodicCallback, 1);
+    periodicCallbackToKeepTimerGoing.attach(periodicCallback, 1);
     button.fall(buttonPressedCallback);
     button.rise(buttonReleasedCallback);
 
+    // Clear display
+    clearTimeLEDs();
+    
     // BLE init
     ble.init();
     ble.gap().onDisconnection(disconnectionCallback);
@@ -143,8 +273,9 @@
     // Watch Time Service
     uint8_t initialTime[] = { uint8_t(2015/256), uint8_t(2015%256), 7, 26, 12, 8, 0 };    
     WatchTimeService watchTimeService(ble, initialTime);
+    setRTCfromWatchTime(initialTime);
     pWatchTimeService = &watchTimeService;
-
+    
     // 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));
@@ -153,24 +284,41 @@
     ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
     ble.gap().startAdvertising();
 
-    while (true) {
+    uint8_t curWatchTime[WatchTimeService::WatchTime_BlockSize];
+    while (true) 
+    {
         ble.waitForEvent();
         
+        // TEST CODE    
         loopCount++;
         if (loopCount < 5)
             continue;
         loopCount = 0;
         
-        time_t rawtime;
-        struct tm * timeinfo;        
-        time (&rawtime);
-        timeinfo = localtime (&rawtime);
-        printf ("Current local time and date: %s callbacks %d retval %d\r\n", asctime(timeinfo), callbackCount, retval);
-        printf ("Timest %02x %02x %02x %02x %02x %02x %02x %ld\r\n", testbuf[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");
+        }
+        */
     }
 }