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

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?

UserRevisionLine numberNew 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 */