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@5:2682353a8c32, 2015-12-14 (annotated)
- Committer:
- Bobty
- Date:
- Mon Dec 14 22:58:31 2015 +0000
- Revision:
- 5:2682353a8c32
- Parent:
- 4:f0b030a3223f
- Child:
- 6:4a12e0f03381
Works reliably - time only (no alarm functions) - doesn't display on binary digits as yet
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Bobty | 0:0d5ac2fd4620 | 1 | // BLE Alarm Watch |
Bobty | 2:9090120e2656 | 2 | // Based on BLE examples on MBED |
Bobty | 5:2682353a8c32 | 3 | // Rob Dobson, (c) 2015 |
Bobty | 0:0d5ac2fd4620 | 4 | |
Bobty | 0:0d5ac2fd4620 | 5 | #include "mbed.h" |
Bobty | 2:9090120e2656 | 6 | #include "BLE.h" |
Bobty | 2:9090120e2656 | 7 | #include "ButtonService.h" |
Bobty | 3:a4b8d67de1b1 | 8 | #include "WatchTimeService.h" |
Bobty | 4:f0b030a3223f | 9 | #include "nrf51_rtc.h" |
Bobty | 2:9090120e2656 | 10 | |
Bobty | 2:9090120e2656 | 11 | // BLE platform |
Bobty | 2:9090120e2656 | 12 | BLE ble; |
Bobty | 2:9090120e2656 | 13 | |
Bobty | 5:2682353a8c32 | 14 | // Hour LEDs |
Bobty | 5:2682353a8c32 | 15 | DigitalOut hourPins[5] = { p0, p1, p2, p3, p4 }; |
Bobty | 5:2682353a8c32 | 16 | |
Bobty | 5:2682353a8c32 | 17 | // Minute LEDs |
Bobty | 5:2682353a8c32 | 18 | DigitalOut minPins[6] = { p23, p24, p25, p28, p29, p30 }; |
Bobty | 2:9090120e2656 | 19 | |
Bobty | 2:9090120e2656 | 20 | // Button press to show time |
Bobty | 5:2682353a8c32 | 21 | InterruptIn button(p5); |
Bobty | 2:9090120e2656 | 22 | |
Bobty | 2:9090120e2656 | 23 | // Device name - this is the visible name of device on BLE |
Bobty | 5:2682353a8c32 | 24 | const static char DEVICE_NAME[] = "JoesAlarm"; |
Bobty | 3:a4b8d67de1b1 | 25 | |
Bobty | 3:a4b8d67de1b1 | 26 | // UUIDs of services offered |
Bobty | 3:a4b8d67de1b1 | 27 | static const uint16_t uuid16_list[] = {ButtonService::BUTTON_SERVICE_UUID, WatchTimeService::WATCHTIME_SERVICE_UUID}; |
Bobty | 3:a4b8d67de1b1 | 28 | |
Bobty | 3:a4b8d67de1b1 | 29 | // Service offering to read and set the time on the watch |
Bobty | 3:a4b8d67de1b1 | 30 | WatchTimeService *pWatchTimeService; |
Bobty | 2:9090120e2656 | 31 | |
Bobty | 5:2682353a8c32 | 32 | // Time display state variables |
Bobty | 5:2682353a8c32 | 33 | const int timeDisplayState_None = 0; |
Bobty | 5:2682353a8c32 | 34 | const int timeDisplayState_ShowTime = 1; |
Bobty | 5:2682353a8c32 | 35 | const int timeDisplayState_ShowAlarm = 2; |
Bobty | 5:2682353a8c32 | 36 | int timeDisplayState = timeDisplayState_None; |
Bobty | 5:2682353a8c32 | 37 | uint8_t curBinaryLedDisplayVal[WatchTimeService::WatchTime_BlockSize]; |
Bobty | 5:2682353a8c32 | 38 | int timeDisplayLastButtonTime = 0; |
Bobty | 5:2682353a8c32 | 39 | const int timeDisplayShowTimeSecs = 10; |
Bobty | 5:2682353a8c32 | 40 | const int timeDisplayMoveToShowAlarmSecs = 5; |
Bobty | 5:2682353a8c32 | 41 | |
Bobty | 5:2682353a8c32 | 42 | // Cur time disp info |
Bobty | 5:2682353a8c32 | 43 | int curTimeLEDBitPos = 0; |
Bobty | 5:2682353a8c32 | 44 | |
Bobty | 2:9090120e2656 | 45 | // TEST CODE |
Bobty | 3:a4b8d67de1b1 | 46 | int callbackCount = 0; |
Bobty | 3:a4b8d67de1b1 | 47 | uint8_t testbuf[WatchTimeService::WatchTime_BlockSize]; |
Bobty | 3:a4b8d67de1b1 | 48 | time_t retval = 0; |
Bobty | 3:a4b8d67de1b1 | 49 | int servcode = 0; |
Bobty | 3:a4b8d67de1b1 | 50 | int buflen = 0; |
Bobty | 3:a4b8d67de1b1 | 51 | int mycode = 0; |
Bobty | 3:a4b8d67de1b1 | 52 | int offs = 0; |
Bobty | 3:a4b8d67de1b1 | 53 | int butcode = 0; |
Bobty | 2:9090120e2656 | 54 | ButtonService *buttonServicePtr; |
Bobty | 5:2682353a8c32 | 55 | Ticker periodicCallbackToKeepTimerGoing; |
Bobty | 5:2682353a8c32 | 56 | Timeout timerForLEDMuxing; |
Bobty | 2:9090120e2656 | 57 | |
Bobty | 3:a4b8d67de1b1 | 58 | time_t watchTimeToUnix(const uint8_t* pWatchTime) |
Bobty | 3:a4b8d67de1b1 | 59 | { |
Bobty | 3:a4b8d67de1b1 | 60 | struct tm tminfo; |
Bobty | 3:a4b8d67de1b1 | 61 | tminfo.tm_year = int(pWatchTime[0])*256 + pWatchTime[1] - 1900; |
Bobty | 3:a4b8d67de1b1 | 62 | tminfo.tm_mon = pWatchTime[2] - 1; |
Bobty | 3:a4b8d67de1b1 | 63 | tminfo.tm_mday = pWatchTime[3]; |
Bobty | 3:a4b8d67de1b1 | 64 | tminfo.tm_hour = pWatchTime[4]; |
Bobty | 3:a4b8d67de1b1 | 65 | tminfo.tm_min = pWatchTime[5]; |
Bobty | 3:a4b8d67de1b1 | 66 | tminfo.tm_sec = pWatchTime[6]; |
Bobty | 3:a4b8d67de1b1 | 67 | tminfo.tm_isdst = -1; |
Bobty | 3:a4b8d67de1b1 | 68 | time_t timest = mktime(&tminfo); |
Bobty | 3:a4b8d67de1b1 | 69 | return timest; |
Bobty | 3:a4b8d67de1b1 | 70 | } |
Bobty | 3:a4b8d67de1b1 | 71 | |
Bobty | 5:2682353a8c32 | 72 | void unixTimeToWatchTime(time_t unixTime, uint8_t* pWatchTime) |
Bobty | 5:2682353a8c32 | 73 | { |
Bobty | 5:2682353a8c32 | 74 | // Convert to localtime |
Bobty | 5:2682353a8c32 | 75 | struct tm * timeinfo; |
Bobty | 5:2682353a8c32 | 76 | timeinfo = localtime (&unixTime); |
Bobty | 5:2682353a8c32 | 77 | pWatchTime[0] = (timeinfo->tm_year + 1900) / 256; |
Bobty | 5:2682353a8c32 | 78 | pWatchTime[1] = (timeinfo->tm_year + 1900) % 256; |
Bobty | 5:2682353a8c32 | 79 | pWatchTime[2] = timeinfo->tm_mon + 1; |
Bobty | 5:2682353a8c32 | 80 | pWatchTime[3] = timeinfo->tm_mday; |
Bobty | 5:2682353a8c32 | 81 | pWatchTime[4] = timeinfo->tm_hour; |
Bobty | 5:2682353a8c32 | 82 | pWatchTime[5] = timeinfo->tm_min; |
Bobty | 5:2682353a8c32 | 83 | pWatchTime[6] = timeinfo->tm_sec; |
Bobty | 5:2682353a8c32 | 84 | } |
Bobty | 5:2682353a8c32 | 85 | |
Bobty | 5:2682353a8c32 | 86 | int watchTimeToBCD(const uint8_t* pWatchTime) |
Bobty | 5:2682353a8c32 | 87 | { |
Bobty | 5:2682353a8c32 | 88 | // Simply combine the hour and minute values in a 4 digit BCD number |
Bobty | 5:2682353a8c32 | 89 | int bcdHourMin = pWatchTime[4] / 10; |
Bobty | 5:2682353a8c32 | 90 | bcdHourMin = (bcdHourMin << 4) + pWatchTime[4] % 10; |
Bobty | 5:2682353a8c32 | 91 | bcdHourMin = (bcdHourMin << 4) + pWatchTime[5] / 10; |
Bobty | 5:2682353a8c32 | 92 | bcdHourMin = (bcdHourMin << 4) + pWatchTime[5] % 10; |
Bobty | 5:2682353a8c32 | 93 | return bcdHourMin; |
Bobty | 5:2682353a8c32 | 94 | } |
Bobty | 5:2682353a8c32 | 95 | |
Bobty | 5:2682353a8c32 | 96 | void callbackForLEDMuxing(); |
Bobty | 5:2682353a8c32 | 97 | |
Bobty | 5:2682353a8c32 | 98 | void clearTimeLEDs() |
Bobty | 5:2682353a8c32 | 99 | { |
Bobty | 5:2682353a8c32 | 100 | for (int i = 0; i < 5; i++) |
Bobty | 5:2682353a8c32 | 101 | hourPins[i] = 0; |
Bobty | 5:2682353a8c32 | 102 | for (int i = 0; i < 6; i++) |
Bobty | 5:2682353a8c32 | 103 | minPins[i] = 0; |
Bobty | 5:2682353a8c32 | 104 | } |
Bobty | 5:2682353a8c32 | 105 | |
Bobty | 5:2682353a8c32 | 106 | //uint8_t* GetCurTimeAsWatchTime() |
Bobty | 5:2682353a8c32 | 107 | //{ |
Bobty | 5:2682353a8c32 | 108 | // // Get current time and convert to displayable time |
Bobty | 5:2682353a8c32 | 109 | // time_t rawtime=rtc.time(); |
Bobty | 5:2682353a8c32 | 110 | // unixTimeToWatchTime(rawtime, curBinaryLedDisplayVal); |
Bobty | 5:2682353a8c32 | 111 | //} |
Bobty | 5:2682353a8c32 | 112 | |
Bobty | 5:2682353a8c32 | 113 | void nextShowingTimeLEDs() |
Bobty | 5:2682353a8c32 | 114 | { |
Bobty | 5:2682353a8c32 | 115 | // Get current time and convert to displayable time |
Bobty | 5:2682353a8c32 | 116 | time_t rawtime=rtc.time(); |
Bobty | 5:2682353a8c32 | 117 | unixTimeToWatchTime(rawtime, curBinaryLedDisplayVal); |
Bobty | 5:2682353a8c32 | 118 | |
Bobty | 5:2682353a8c32 | 119 | // Clear LEDs |
Bobty | 5:2682353a8c32 | 120 | clearTimeLEDs(); |
Bobty | 5:2682353a8c32 | 121 | |
Bobty | 5:2682353a8c32 | 122 | // Stop displaying time after a certain number of seconds |
Bobty | 5:2682353a8c32 | 123 | if (rawtime - timeDisplayLastButtonTime >= timeDisplayShowTimeSecs) |
Bobty | 5:2682353a8c32 | 124 | return; |
Bobty | 5:2682353a8c32 | 125 | |
Bobty | 5:2682353a8c32 | 126 | // Display binary time |
Bobty | 5:2682353a8c32 | 127 | int hours = curBinaryLedDisplayVal[4]; |
Bobty | 5:2682353a8c32 | 128 | int mins = curBinaryLedDisplayVal[5]; |
Bobty | 5:2682353a8c32 | 129 | int mask = 1 << curTimeLEDBitPos; |
Bobty | 5:2682353a8c32 | 130 | if ((curTimeLEDBitPos < 5) && ((hours & mask) != 0)) |
Bobty | 5:2682353a8c32 | 131 | hourPins[curTimeLEDBitPos] = 1; |
Bobty | 5:2682353a8c32 | 132 | if ((mins & mask) != 0) |
Bobty | 5:2682353a8c32 | 133 | minPins[curTimeLEDBitPos] = 1; |
Bobty | 5:2682353a8c32 | 134 | curTimeLEDBitPos++; |
Bobty | 5:2682353a8c32 | 135 | if (curTimeLEDBitPos > 5) |
Bobty | 5:2682353a8c32 | 136 | curTimeLEDBitPos = 0; |
Bobty | 5:2682353a8c32 | 137 | |
Bobty | 5:2682353a8c32 | 138 | // Set for another callback |
Bobty | 5:2682353a8c32 | 139 | timerForLEDMuxing.attach(callbackForLEDMuxing, 0.001); |
Bobty | 5:2682353a8c32 | 140 | } |
Bobty | 5:2682353a8c32 | 141 | |
Bobty | 5:2682353a8c32 | 142 | void callbackForLEDMuxing() |
Bobty | 5:2682353a8c32 | 143 | { |
Bobty | 5:2682353a8c32 | 144 | nextShowingTimeLEDs(); |
Bobty | 5:2682353a8c32 | 145 | } |
Bobty | 5:2682353a8c32 | 146 | |
Bobty | 5:2682353a8c32 | 147 | void startShowingTimeLEDs() |
Bobty | 5:2682353a8c32 | 148 | { |
Bobty | 5:2682353a8c32 | 149 | curTimeLEDBitPos = 0; |
Bobty | 5:2682353a8c32 | 150 | timerForLEDMuxing.attach(callbackForLEDMuxing, 0.001); |
Bobty | 5:2682353a8c32 | 151 | } |
Bobty | 5:2682353a8c32 | 152 | |
Bobty | 5:2682353a8c32 | 153 | void stopShowingTimeLEDs() |
Bobty | 5:2682353a8c32 | 154 | { |
Bobty | 5:2682353a8c32 | 155 | clearTimeLEDs(); |
Bobty | 5:2682353a8c32 | 156 | } |
Bobty | 5:2682353a8c32 | 157 | |
Bobty | 5:2682353a8c32 | 158 | // Handle button press to read watch |
Bobty | 5:2682353a8c32 | 159 | void buttonPressedCallback(void) |
Bobty | 5:2682353a8c32 | 160 | { |
Bobty | 5:2682353a8c32 | 161 | // Get the time to display |
Bobty | 5:2682353a8c32 | 162 | time_t rawtime=rtc.time(); |
Bobty | 5:2682353a8c32 | 163 | |
Bobty | 5:2682353a8c32 | 164 | // Check if we should display current time or alarm time |
Bobty | 5:2682353a8c32 | 165 | if (rawtime - timeDisplayLastButtonTime > timeDisplayMoveToShowAlarmSecs) |
Bobty | 5:2682353a8c32 | 166 | { |
Bobty | 5:2682353a8c32 | 167 | timeDisplayState = timeDisplayState_ShowTime; |
Bobty | 5:2682353a8c32 | 168 | } |
Bobty | 5:2682353a8c32 | 169 | else |
Bobty | 5:2682353a8c32 | 170 | { |
Bobty | 5:2682353a8c32 | 171 | // TO BE DONE |
Bobty | 5:2682353a8c32 | 172 | // - move alarm time value to the curBinaryLedDisplayVal |
Bobty | 5:2682353a8c32 | 173 | timeDisplayState = timeDisplayState_ShowAlarm; |
Bobty | 5:2682353a8c32 | 174 | } |
Bobty | 5:2682353a8c32 | 175 | startShowingTimeLEDs(); |
Bobty | 5:2682353a8c32 | 176 | |
Bobty | 5:2682353a8c32 | 177 | // Remember when button last pressed |
Bobty | 5:2682353a8c32 | 178 | timeDisplayLastButtonTime = rawtime; |
Bobty | 5:2682353a8c32 | 179 | |
Bobty | 5:2682353a8c32 | 180 | // Update the button-state service |
Bobty | 5:2682353a8c32 | 181 | buttonServicePtr->updateButtonState(true); |
Bobty | 5:2682353a8c32 | 182 | } |
Bobty | 5:2682353a8c32 | 183 | |
Bobty | 5:2682353a8c32 | 184 | // TEST CODE |
Bobty | 5:2682353a8c32 | 185 | void buttonReleasedCallback(void) |
Bobty | 5:2682353a8c32 | 186 | { |
Bobty | 5:2682353a8c32 | 187 | // Update the button-state service |
Bobty | 5:2682353a8c32 | 188 | buttonServicePtr->updateButtonState(false); |
Bobty | 5:2682353a8c32 | 189 | } |
Bobty | 5:2682353a8c32 | 190 | |
Bobty | 5:2682353a8c32 | 191 | // Handle BLE disconnection - restart advertising |
Bobty | 5:2682353a8c32 | 192 | void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) |
Bobty | 5:2682353a8c32 | 193 | { |
Bobty | 5:2682353a8c32 | 194 | ble.gap().startAdvertising(); |
Bobty | 5:2682353a8c32 | 195 | } |
Bobty | 5:2682353a8c32 | 196 | |
Bobty | 5:2682353a8c32 | 197 | // TEST CODE |
Bobty | 5:2682353a8c32 | 198 | void periodicCallback(void) |
Bobty | 5:2682353a8c32 | 199 | { |
Bobty | 5:2682353a8c32 | 200 | // Update the rtc library time (it says in the notes on the rtc lib that this needs to happen |
Bobty | 5:2682353a8c32 | 201 | // more than once every few hundred seconds to avoid a rollover |
Bobty | 5:2682353a8c32 | 202 | rtc.time(); |
Bobty | 5:2682353a8c32 | 203 | } |
Bobty | 5:2682353a8c32 | 204 | |
Bobty | 5:2682353a8c32 | 205 | void setRTCfromWatchTime(const uint8_t* pWatchTime) |
Bobty | 5:2682353a8c32 | 206 | { |
Bobty | 5:2682353a8c32 | 207 | time_t timest = watchTimeToUnix(pWatchTime); |
Bobty | 5:2682353a8c32 | 208 | retval = timest; |
Bobty | 5:2682353a8c32 | 209 | if ((int)timest != -1) |
Bobty | 5:2682353a8c32 | 210 | { |
Bobty | 5:2682353a8c32 | 211 | rtc.set_time(timest); |
Bobty | 5:2682353a8c32 | 212 | minPins[5] = !minPins[5]; |
Bobty | 5:2682353a8c32 | 213 | } |
Bobty | 5:2682353a8c32 | 214 | } |
Bobty | 5:2682353a8c32 | 215 | |
Bobty | 3:a4b8d67de1b1 | 216 | void onDataWrittenCallback(const GattWriteCallbackParams *params) |
Bobty | 3:a4b8d67de1b1 | 217 | { |
Bobty | 3:a4b8d67de1b1 | 218 | // TEST code |
Bobty | 3:a4b8d67de1b1 | 219 | callbackCount++; |
Bobty | 3:a4b8d67de1b1 | 220 | memcpy(testbuf, params->data, WatchTimeService::WatchTime_BlockSize); |
Bobty | 3:a4b8d67de1b1 | 221 | servcode = params->handle; |
Bobty | 3:a4b8d67de1b1 | 222 | buflen = params->len; |
Bobty | 3:a4b8d67de1b1 | 223 | mycode = pWatchTimeService->getValueHandle(); |
Bobty | 3:a4b8d67de1b1 | 224 | butcode = buttonServicePtr->getValueHandle(); |
Bobty | 3:a4b8d67de1b1 | 225 | offs = params->offset; |
Bobty | 3:a4b8d67de1b1 | 226 | |
Bobty | 3:a4b8d67de1b1 | 227 | // Check if this is time setting |
Bobty | 3:a4b8d67de1b1 | 228 | if (pWatchTimeService->getValueHandle() == params->handle) |
Bobty | 3:a4b8d67de1b1 | 229 | { |
Bobty | 3:a4b8d67de1b1 | 230 | if (params->len == WatchTimeService::WatchTime_BlockSize) |
Bobty | 3:a4b8d67de1b1 | 231 | { |
Bobty | 5:2682353a8c32 | 232 | setRTCfromWatchTime(params->data); |
Bobty | 3:a4b8d67de1b1 | 233 | } |
Bobty | 3:a4b8d67de1b1 | 234 | } |
Bobty | 3:a4b8d67de1b1 | 235 | } |
Bobty | 3:a4b8d67de1b1 | 236 | |
Bobty | 4:f0b030a3223f | 237 | // TEST CODE |
Bobty | 4:f0b030a3223f | 238 | void print_time() |
Bobty | 4:f0b030a3223f | 239 | { |
Bobty | 4:f0b030a3223f | 240 | time_t rawtime=rtc.time(); |
Bobty | 4:f0b030a3223f | 241 | |
Bobty | 4:f0b030a3223f | 242 | // massage the time into a human-friendly format for printing |
Bobty | 4:f0b030a3223f | 243 | struct tm * timeinfo; |
Bobty | 4:f0b030a3223f | 244 | timeinfo = localtime(&rawtime); |
Bobty | 4:f0b030a3223f | 245 | char date[24]; |
Bobty | 4:f0b030a3223f | 246 | strftime(date,sizeof(date),"%H:%M:%S on %m/%d/%G",timeinfo); |
Bobty | 4:f0b030a3223f | 247 | printf("The current time is %s.\r\n",date); |
Bobty | 4:f0b030a3223f | 248 | } |
Bobty | 4:f0b030a3223f | 249 | |
Bobty | 2:9090120e2656 | 250 | int main(void) |
Bobty | 2:9090120e2656 | 251 | { |
Bobty | 3:a4b8d67de1b1 | 252 | printf("AlarmWatch\r\n"); |
Bobty | 3:a4b8d67de1b1 | 253 | |
Bobty | 2:9090120e2656 | 254 | // TEST CODE |
Bobty | 3:a4b8d67de1b1 | 255 | memset(testbuf, 0, WatchTimeService::WatchTime_BlockSize); |
Bobty | 3:a4b8d67de1b1 | 256 | int loopCount = 0; |
Bobty | 5:2682353a8c32 | 257 | periodicCallbackToKeepTimerGoing.attach(periodicCallback, 1); |
Bobty | 2:9090120e2656 | 258 | button.fall(buttonPressedCallback); |
Bobty | 2:9090120e2656 | 259 | button.rise(buttonReleasedCallback); |
Bobty | 2:9090120e2656 | 260 | |
Bobty | 5:2682353a8c32 | 261 | // Clear display |
Bobty | 5:2682353a8c32 | 262 | clearTimeLEDs(); |
Bobty | 5:2682353a8c32 | 263 | |
Bobty | 2:9090120e2656 | 264 | // BLE init |
Bobty | 2:9090120e2656 | 265 | ble.init(); |
Bobty | 2:9090120e2656 | 266 | ble.gap().onDisconnection(disconnectionCallback); |
Bobty | 3:a4b8d67de1b1 | 267 | ble.onDataWritten(onDataWrittenCallback); |
Bobty | 3:a4b8d67de1b1 | 268 | |
Bobty | 2:9090120e2656 | 269 | // TEST CODE |
Bobty | 2:9090120e2656 | 270 | ButtonService buttonService(ble, false /* initial value for button pressed */); |
Bobty | 2:9090120e2656 | 271 | buttonServicePtr = &buttonService; |
Bobty | 3:a4b8d67de1b1 | 272 | |
Bobty | 3:a4b8d67de1b1 | 273 | // Watch Time Service |
Bobty | 3:a4b8d67de1b1 | 274 | uint8_t initialTime[] = { uint8_t(2015/256), uint8_t(2015%256), 7, 26, 12, 8, 0 }; |
Bobty | 3:a4b8d67de1b1 | 275 | WatchTimeService watchTimeService(ble, initialTime); |
Bobty | 5:2682353a8c32 | 276 | setRTCfromWatchTime(initialTime); |
Bobty | 3:a4b8d67de1b1 | 277 | pWatchTimeService = &watchTimeService; |
Bobty | 5:2682353a8c32 | 278 | |
Bobty | 2:9090120e2656 | 279 | // Setup advertising |
Bobty | 2:9090120e2656 | 280 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
Bobty | 2:9090120e2656 | 281 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); |
Bobty | 2:9090120e2656 | 282 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
Bobty | 2:9090120e2656 | 283 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
Bobty | 2:9090120e2656 | 284 | ble.gap().setAdvertisingInterval(1000); /* 1000ms. */ |
Bobty | 2:9090120e2656 | 285 | ble.gap().startAdvertising(); |
Bobty | 2:9090120e2656 | 286 | |
Bobty | 5:2682353a8c32 | 287 | uint8_t curWatchTime[WatchTimeService::WatchTime_BlockSize]; |
Bobty | 5:2682353a8c32 | 288 | while (true) |
Bobty | 5:2682353a8c32 | 289 | { |
Bobty | 2:9090120e2656 | 290 | ble.waitForEvent(); |
Bobty | 3:a4b8d67de1b1 | 291 | |
Bobty | 5:2682353a8c32 | 292 | // TEST CODE |
Bobty | 3:a4b8d67de1b1 | 293 | loopCount++; |
Bobty | 3:a4b8d67de1b1 | 294 | if (loopCount < 5) |
Bobty | 3:a4b8d67de1b1 | 295 | continue; |
Bobty | 3:a4b8d67de1b1 | 296 | loopCount = 0; |
Bobty | 3:a4b8d67de1b1 | 297 | |
Bobty | 5:2682353a8c32 | 298 | print_time(); |
Bobty | 5:2682353a8c32 | 299 | // Get current time and convert to watch time |
Bobty | 5:2682353a8c32 | 300 | time_t rawtime=rtc.time(); |
Bobty | 5:2682353a8c32 | 301 | unixTimeToWatchTime(rawtime, curWatchTime); |
Bobty | 5:2682353a8c32 | 302 | pWatchTimeService->writeWatchTime(curWatchTime); |
Bobty | 5:2682353a8c32 | 303 | |
Bobty | 5:2682353a8c32 | 304 | |
Bobty | 5:2682353a8c32 | 305 | /* printf ("Timest %02x %02x %02x %02x %02x %02x %02x %ld\r\n", testbuf[0], |
Bobty | 3:a4b8d67de1b1 | 306 | testbuf[1], testbuf[2], testbuf[3], testbuf[4], testbuf[5], testbuf[6], retval); |
Bobty | 3:a4b8d67de1b1 | 307 | printf ("serv %d buflen %d mycode %d offs %d butcode %d\r\n", servcode, buflen, mycode, offs, butcode); |
Bobty | 3:a4b8d67de1b1 | 308 | printf ("val %ld\r\n", watchTimeService.getValueHandle()); |
Bobty | 4:f0b030a3223f | 309 | print_time(); |
Bobty | 5:2682353a8c32 | 310 | |
Bobty | 5:2682353a8c32 | 311 | if (timeDisplayState != timeDisplayState_None) |
Bobty | 5:2682353a8c32 | 312 | { |
Bobty | 5:2682353a8c32 | 313 | int watchLedTime = watchTimeToBCD(curBinaryLedDisplayVal); |
Bobty | 5:2682353a8c32 | 314 | printf("watchTime %04x = ", watchLedTime); |
Bobty | 5:2682353a8c32 | 315 | for (int i = 15; i >= 0; i--) |
Bobty | 5:2682353a8c32 | 316 | { |
Bobty | 5:2682353a8c32 | 317 | printf("%d", (watchLedTime >> i) % 2); |
Bobty | 5:2682353a8c32 | 318 | } |
Bobty | 5:2682353a8c32 | 319 | printf("\r\n"); |
Bobty | 5:2682353a8c32 | 320 | } |
Bobty | 5:2682353a8c32 | 321 | */ |
Bobty | 2:9090120e2656 | 322 | } |
Bobty | 2:9090120e2656 | 323 | } |
Bobty | 2:9090120e2656 | 324 | |
Bobty | 2:9090120e2656 | 325 | /* |
Bobty | 2:9090120e2656 | 326 | |
Bobty | 2:9090120e2656 | 327 | #include "mbed.h" |
Bobty | 0:0d5ac2fd4620 | 328 | #include "BLEDevice.h" |
Bobty | 0:0d5ac2fd4620 | 329 | #include "DeviceInformationService.h" |
Bobty | 0:0d5ac2fd4620 | 330 | |
Bobty | 0:0d5ac2fd4620 | 331 | // BLE Device etc |
Bobty | 0:0d5ac2fd4620 | 332 | BLEDevice ble; |
Bobty | 0:0d5ac2fd4620 | 333 | DigitalOut ledIndicator(LED1); |
Bobty | 0:0d5ac2fd4620 | 334 | DigitalOut testOut(p1); |
Bobty | 0:0d5ac2fd4620 | 335 | |
Bobty | 1:c3d7e673cdd2 | 336 | // Device name |
Bobty | 1:c3d7e673cdd2 | 337 | const static char DEVICE_NAME[] = "JOESALARM"; |
Bobty | 1:c3d7e673cdd2 | 338 | |
Bobty | 1:c3d7e673cdd2 | 339 | // UUID for CurTimeService & TimeBlockCharacteristic |
Bobty | 1:c3d7e673cdd2 | 340 | const uint16_t UUID_CUR_TIME_SERVICE = 0xA000; |
Bobty | 1:c3d7e673cdd2 | 341 | const uint16_t UUID_TIME_BLOCK_CHARACTERISTIC = 0xA001; |
Bobty | 1:c3d7e673cdd2 | 342 | |
Bobty | 1:c3d7e673cdd2 | 343 | // List of supported service UUIDs |
Bobty | 1:c3d7e673cdd2 | 344 | static const uint16_t uuid16_list[] = {UUID_CUR_TIME_SERVICE}; |
Bobty | 0:0d5ac2fd4620 | 345 | |
Bobty | 1:c3d7e673cdd2 | 346 | // Time is packed in an array of bytes |
Bobty | 1:c3d7e673cdd2 | 347 | const int SIZE_OF_TIME_BLOCK = 7; |
Bobty | 1:c3d7e673cdd2 | 348 | uint8_t timeBlockInitValue[SIZE_OF_TIME_BLOCK]; |
Bobty | 1:c3d7e673cdd2 | 349 | uint8_t curTimeBlock[SIZE_OF_TIME_BLOCK]; |
Bobty | 1:c3d7e673cdd2 | 350 | |
Bobty | 1:c3d7e673cdd2 | 351 | // GATT Characteristic for time block |
Bobty | 2:9090120e2656 | 352 | GattCharacteristic timeBlockCharacteristic(UUID_TIME_BLOCK_CHARACTERISTIC, timeBlockInitValue, SIZE_OF_TIME_BLOCK, SIZE_OF_TIME_BLOCK, |
Bobty | 2:9090120e2656 | 353 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); |
Bobty | 1:c3d7e673cdd2 | 354 | |
Bobty | 1:c3d7e673cdd2 | 355 | // Callback when connection lost |
Bobty | 0:0d5ac2fd4620 | 356 | void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) |
Bobty | 0:0d5ac2fd4620 | 357 | { |
Bobty | 0:0d5ac2fd4620 | 358 | ble.startAdvertising(); // restart advertising |
Bobty | 0:0d5ac2fd4620 | 359 | } |
Bobty | 0:0d5ac2fd4620 | 360 | |
Bobty | 1:c3d7e673cdd2 | 361 | // Callback for ticker |
Bobty | 1:c3d7e673cdd2 | 362 | int tickCount = 0; |
Bobty | 1:c3d7e673cdd2 | 363 | bool showInfo = false; |
Bobty | 1:c3d7e673cdd2 | 364 | int writeSinceLast = 0; |
Bobty | 0:0d5ac2fd4620 | 365 | void periodicCallback(void) |
Bobty | 0:0d5ac2fd4620 | 366 | { |
Bobty | 2:9090120e2656 | 367 | ledIndicator = !ledIndicator; |
Bobty | 0:0d5ac2fd4620 | 368 | testOut = !testOut; |
Bobty | 1:c3d7e673cdd2 | 369 | tickCount++; |
Bobty | 1:c3d7e673cdd2 | 370 | if (tickCount > 100) |
Bobty | 1:c3d7e673cdd2 | 371 | { |
Bobty | 1:c3d7e673cdd2 | 372 | showInfo = true; |
Bobty | 1:c3d7e673cdd2 | 373 | tickCount = 0; |
Bobty | 1:c3d7e673cdd2 | 374 | } |
Bobty | 0:0d5ac2fd4620 | 375 | } |
Bobty | 0:0d5ac2fd4620 | 376 | |
Bobty | 1:c3d7e673cdd2 | 377 | // Data written callback |
Bobty | 1:c3d7e673cdd2 | 378 | void onDataWrittenCallback(const GattCharacteristicWriteCBParams *params) |
Bobty | 1:c3d7e673cdd2 | 379 | { |
Bobty | 1:c3d7e673cdd2 | 380 | if ((params->charHandle == timeBlockCharacteristic.getValueHandle())) |
Bobty | 1:c3d7e673cdd2 | 381 | { |
Bobty | 2:9090120e2656 | 382 | // Validate time |
Bobty | 2:9090120e2656 | 383 | int year = params->data[0] * 100 + params->data[1]; |
Bobty | 2:9090120e2656 | 384 | int month = params->data[2]; |
Bobty | 2:9090120e2656 | 385 | int day = params->data[3]; |
Bobty | 1:c3d7e673cdd2 | 386 | // && (params->len == SIZE_OF_TIME_BLOCK) |
Bobty | 1:c3d7e673cdd2 | 387 | writeSinceLast = params->len; |
Bobty | 1:c3d7e673cdd2 | 388 | memcpy(curTimeBlock, params->data, SIZE_OF_TIME_BLOCK); |
Bobty | 1:c3d7e673cdd2 | 389 | } |
Bobty | 1:c3d7e673cdd2 | 390 | writeSinceLast = true; |
Bobty | 1:c3d7e673cdd2 | 391 | } |
Bobty | 1:c3d7e673cdd2 | 392 | |
Bobty | 1:c3d7e673cdd2 | 393 | // Main |
Bobty | 0:0d5ac2fd4620 | 394 | int main(void) |
Bobty | 0:0d5ac2fd4620 | 395 | { |
Bobty | 0:0d5ac2fd4620 | 396 | ledIndicator = 0; |
Bobty | 0:0d5ac2fd4620 | 397 | testOut = 0; |
Bobty | 0:0d5ac2fd4620 | 398 | |
Bobty | 0:0d5ac2fd4620 | 399 | // Ticker is interrupt driven |
Bobty | 0:0d5ac2fd4620 | 400 | Ticker ticker; |
Bobty | 0:0d5ac2fd4620 | 401 | ticker.attach_us(periodicCallback, 100000); |
Bobty | 0:0d5ac2fd4620 | 402 | |
Bobty | 1:c3d7e673cdd2 | 403 | // Initial value for the time block characteristic |
Bobty | 1:c3d7e673cdd2 | 404 | memset(timeBlockInitValue, 0, sizeof(timeBlockInitValue)); |
Bobty | 1:c3d7e673cdd2 | 405 | |
Bobty | 1:c3d7e673cdd2 | 406 | // Init BLE and register callbacks |
Bobty | 0:0d5ac2fd4620 | 407 | ble.init(); |
Bobty | 0:0d5ac2fd4620 | 408 | ble.onDisconnection(disconnectionCallback); |
Bobty | 1:c3d7e673cdd2 | 409 | ble.onDataWritten(onDataWrittenCallback); |
Bobty | 1:c3d7e673cdd2 | 410 | |
Bobty | 1:c3d7e673cdd2 | 411 | // Add the time setting service |
Bobty | 1:c3d7e673cdd2 | 412 | GattCharacteristic *charTable[] = {&timeBlockCharacteristic}; |
Bobty | 1:c3d7e673cdd2 | 413 | GattService timeBlockService(UUID_CUR_TIME_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); |
Bobty | 1:c3d7e673cdd2 | 414 | ble.addService(timeBlockService); |
Bobty | 0:0d5ac2fd4620 | 415 | |
Bobty | 0:0d5ac2fd4620 | 416 | // Setup advertising |
Bobty | 2:9090120e2656 | 417 | // BREDR_NOT_SUPPORTED means classic bluetooth not supported; |
Bobty | 2:9090120e2656 | 418 | // LE_GENERAL_DISCOVERABLE means that this peripheral can be |
Bobty | 2:9090120e2656 | 419 | // discovered by any BLE scanner--i.e. any phone. |
Bobty | 0:0d5ac2fd4620 | 420 | ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
Bobty | 0:0d5ac2fd4620 | 421 | |
Bobty | 1:c3d7e673cdd2 | 422 | // Add services to payload |
Bobty | 1:c3d7e673cdd2 | 423 | ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); |
Bobty | 1:c3d7e673cdd2 | 424 | |
Bobty | 2:9090120e2656 | 425 | // This is where we're collecting the device name into the advertisement payload. |
Bobty | 0:0d5ac2fd4620 | 426 | ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
Bobty | 0:0d5ac2fd4620 | 427 | |
Bobty | 2:9090120e2656 | 428 | // We'd like for this BLE peripheral to be connectable. |
Bobty | 0:0d5ac2fd4620 | 429 | ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
Bobty | 0:0d5ac2fd4620 | 430 | |
Bobty | 2:9090120e2656 | 431 | // set the interval at which advertisements are sent out; this has |
Bobty | 2:9090120e2656 | 432 | // an implication power consumption--radio activity being a |
Bobty | 2:9090120e2656 | 433 | // biggest draw on average power. The other software controllable |
Bobty | 2:9090120e2656 | 434 | // parameter which influences power is the radio's TX power |
Bobty | 2:9090120e2656 | 435 | // level--there's an API to adjust that. |
Bobty | 2:9090120e2656 | 436 | ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); |
Bobty | 0:0d5ac2fd4620 | 437 | |
Bobty | 2:9090120e2656 | 438 | |
Bobty | 0:0d5ac2fd4620 | 439 | ble.startAdvertising(); |
Bobty | 0:0d5ac2fd4620 | 440 | |
Bobty | 0:0d5ac2fd4620 | 441 | while (true) |
Bobty | 0:0d5ac2fd4620 | 442 | { |
Bobty | 0:0d5ac2fd4620 | 443 | ble.waitForEvent(); |
Bobty | 1:c3d7e673cdd2 | 444 | |
Bobty | 1:c3d7e673cdd2 | 445 | if (showInfo) |
Bobty | 1:c3d7e673cdd2 | 446 | { |
Bobty | 1:c3d7e673cdd2 | 447 | printf("Time info: "); |
Bobty | 1:c3d7e673cdd2 | 448 | for (int i = 0; i < SIZE_OF_TIME_BLOCK; i++) |
Bobty | 1:c3d7e673cdd2 | 449 | { |
Bobty | 1:c3d7e673cdd2 | 450 | printf("%02d", curTimeBlock[i]); |
Bobty | 1:c3d7e673cdd2 | 451 | } |
Bobty | 1:c3d7e673cdd2 | 452 | printf(" - writeSinceLast %d\r\n", writeSinceLast); |
Bobty | 1:c3d7e673cdd2 | 453 | showInfo = false; |
Bobty | 1:c3d7e673cdd2 | 454 | writeSinceLast = 0; |
Bobty | 1:c3d7e673cdd2 | 455 | } |
Bobty | 0:0d5ac2fd4620 | 456 | } |
Bobty | 0:0d5ac2fd4620 | 457 | } |
Bobty | 2:9090120e2656 | 458 | */ |