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
Diff: main.cpp
- 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"); + } + */ } }