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 Jul 27 15:25:59 2015 +0000
Revision:
3:a4b8d67de1b1
Parent:
2:9090120e2656
Child:
4:f0b030a3223f
Basic functionality of setting the time is working but no RTC is enabled

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 0:0d5ac2fd4620 3 // Rob Dobson, 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 2:9090120e2656 9
Bobty 2:9090120e2656 10 // BLE platform
Bobty 2:9090120e2656 11 BLE ble;
Bobty 2:9090120e2656 12
Bobty 2:9090120e2656 13 // Indicator LEDs
Bobty 2:9090120e2656 14 DigitalOut led1(LED1);
Bobty 2:9090120e2656 15
Bobty 2:9090120e2656 16 // Button press to show time
Bobty 2:9090120e2656 17 InterruptIn button(D8);
Bobty 2:9090120e2656 18
Bobty 2:9090120e2656 19 // Device name - this is the visible name of device on BLE
Bobty 3:a4b8d67de1b1 20 const static char DEVICE_NAME[] = "JoesAlarm";
Bobty 3:a4b8d67de1b1 21
Bobty 3:a4b8d67de1b1 22 // UUIDs of services offered
Bobty 3:a4b8d67de1b1 23 static const uint16_t uuid16_list[] = {ButtonService::BUTTON_SERVICE_UUID, WatchTimeService::WATCHTIME_SERVICE_UUID};
Bobty 3:a4b8d67de1b1 24
Bobty 3:a4b8d67de1b1 25 // Service offering to read and set the time on the watch
Bobty 3:a4b8d67de1b1 26 WatchTimeService *pWatchTimeService;
Bobty 2:9090120e2656 27
Bobty 2:9090120e2656 28 // TEST CODE
Bobty 3:a4b8d67de1b1 29 int callbackCount = 0;
Bobty 3:a4b8d67de1b1 30 uint8_t testbuf[WatchTimeService::WatchTime_BlockSize];
Bobty 3:a4b8d67de1b1 31 time_t retval = 0;
Bobty 3:a4b8d67de1b1 32 int servcode = 0;
Bobty 3:a4b8d67de1b1 33 int buflen = 0;
Bobty 3:a4b8d67de1b1 34 int mycode = 0;
Bobty 3:a4b8d67de1b1 35 int offs = 0;
Bobty 3:a4b8d67de1b1 36 int butcode = 0;
Bobty 2:9090120e2656 37 ButtonService *buttonServicePtr;
Bobty 2:9090120e2656 38
Bobty 2:9090120e2656 39 // Handle button press to read watch
Bobty 2:9090120e2656 40 void buttonPressedCallback(void)
Bobty 2:9090120e2656 41 {
Bobty 2:9090120e2656 42 // TEST CODE
Bobty 2:9090120e2656 43 buttonServicePtr->updateButtonState(true);
Bobty 2:9090120e2656 44 }
Bobty 2:9090120e2656 45
Bobty 2:9090120e2656 46 // TEST CODE
Bobty 2:9090120e2656 47 void buttonReleasedCallback(void)
Bobty 2:9090120e2656 48 {
Bobty 2:9090120e2656 49 // TEST CODE
Bobty 2:9090120e2656 50 buttonServicePtr->updateButtonState(false);
Bobty 2:9090120e2656 51 }
Bobty 2:9090120e2656 52
Bobty 2:9090120e2656 53 // Handle BLE disconnection - restart advertising
Bobty 2:9090120e2656 54 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
Bobty 2:9090120e2656 55 {
Bobty 2:9090120e2656 56 ble.gap().startAdvertising();
Bobty 2:9090120e2656 57 }
Bobty 2:9090120e2656 58
Bobty 2:9090120e2656 59 // TEST CODE
Bobty 2:9090120e2656 60 void periodicCallback(void)
Bobty 2:9090120e2656 61 {
Bobty 2:9090120e2656 62 led1 = !led1; /* Do blinky on LED1 to indicate system aliveness. */
Bobty 2:9090120e2656 63 }
Bobty 2:9090120e2656 64
Bobty 3:a4b8d67de1b1 65 time_t watchTimeToUnix(const uint8_t* pWatchTime)
Bobty 3:a4b8d67de1b1 66 {
Bobty 3:a4b8d67de1b1 67 struct tm tminfo;
Bobty 3:a4b8d67de1b1 68 tminfo.tm_year = int(pWatchTime[0])*256 + pWatchTime[1] - 1900;
Bobty 3:a4b8d67de1b1 69 tminfo.tm_mon = pWatchTime[2] - 1;
Bobty 3:a4b8d67de1b1 70 tminfo.tm_mday = pWatchTime[3];
Bobty 3:a4b8d67de1b1 71 tminfo.tm_hour = pWatchTime[4];
Bobty 3:a4b8d67de1b1 72 tminfo.tm_min = pWatchTime[5];
Bobty 3:a4b8d67de1b1 73 tminfo.tm_sec = pWatchTime[6];
Bobty 3:a4b8d67de1b1 74 tminfo.tm_isdst = -1;
Bobty 3:a4b8d67de1b1 75 time_t timest = mktime(&tminfo);
Bobty 3:a4b8d67de1b1 76 return timest;
Bobty 3:a4b8d67de1b1 77 }
Bobty 3:a4b8d67de1b1 78
Bobty 3:a4b8d67de1b1 79 void onDataWrittenCallback(const GattWriteCallbackParams *params)
Bobty 3:a4b8d67de1b1 80 {
Bobty 3:a4b8d67de1b1 81 // TEST code
Bobty 3:a4b8d67de1b1 82 callbackCount++;
Bobty 3:a4b8d67de1b1 83 memcpy(testbuf, params->data, WatchTimeService::WatchTime_BlockSize);
Bobty 3:a4b8d67de1b1 84 servcode = params->handle;
Bobty 3:a4b8d67de1b1 85 buflen = params->len;
Bobty 3:a4b8d67de1b1 86 mycode = pWatchTimeService->getValueHandle();
Bobty 3:a4b8d67de1b1 87 butcode = buttonServicePtr->getValueHandle();
Bobty 3:a4b8d67de1b1 88 offs = params->offset;
Bobty 3:a4b8d67de1b1 89
Bobty 3:a4b8d67de1b1 90 // Check if this is time setting
Bobty 3:a4b8d67de1b1 91 if (pWatchTimeService->getValueHandle() == params->handle)
Bobty 3:a4b8d67de1b1 92 {
Bobty 3:a4b8d67de1b1 93 if (params->len == WatchTimeService::WatchTime_BlockSize)
Bobty 3:a4b8d67de1b1 94 {
Bobty 3:a4b8d67de1b1 95 time_t timest = watchTimeToUnix(params->data);
Bobty 3:a4b8d67de1b1 96 retval = timest;
Bobty 3:a4b8d67de1b1 97 if (timest != -1)
Bobty 3:a4b8d67de1b1 98 set_time(timest);
Bobty 3:a4b8d67de1b1 99 }
Bobty 3:a4b8d67de1b1 100 }
Bobty 3:a4b8d67de1b1 101 }
Bobty 3:a4b8d67de1b1 102
Bobty 2:9090120e2656 103 int main(void)
Bobty 2:9090120e2656 104 {
Bobty 3:a4b8d67de1b1 105 printf("AlarmWatch\r\n");
Bobty 3:a4b8d67de1b1 106
Bobty 2:9090120e2656 107 // TEST CODE
Bobty 3:a4b8d67de1b1 108 memset(testbuf, 0, WatchTimeService::WatchTime_BlockSize);
Bobty 3:a4b8d67de1b1 109 int loopCount = 0;
Bobty 2:9090120e2656 110 led1 = 1;
Bobty 2:9090120e2656 111 Ticker ticker;
Bobty 2:9090120e2656 112 ticker.attach(periodicCallback, 1);
Bobty 2:9090120e2656 113 button.fall(buttonPressedCallback);
Bobty 2:9090120e2656 114 button.rise(buttonReleasedCallback);
Bobty 2:9090120e2656 115
Bobty 2:9090120e2656 116 // BLE init
Bobty 2:9090120e2656 117 ble.init();
Bobty 2:9090120e2656 118 ble.gap().onDisconnection(disconnectionCallback);
Bobty 3:a4b8d67de1b1 119 ble.onDataWritten(onDataWrittenCallback);
Bobty 3:a4b8d67de1b1 120
Bobty 2:9090120e2656 121 // TEST CODE
Bobty 2:9090120e2656 122 ButtonService buttonService(ble, false /* initial value for button pressed */);
Bobty 2:9090120e2656 123 buttonServicePtr = &buttonService;
Bobty 3:a4b8d67de1b1 124
Bobty 3:a4b8d67de1b1 125 // Watch Time Service
Bobty 3:a4b8d67de1b1 126 uint8_t initialTime[] = { uint8_t(2015/256), uint8_t(2015%256), 7, 26, 12, 8, 0 };
Bobty 3:a4b8d67de1b1 127 WatchTimeService watchTimeService(ble, initialTime);
Bobty 3:a4b8d67de1b1 128 pWatchTimeService = &watchTimeService;
Bobty 2:9090120e2656 129
Bobty 2:9090120e2656 130 // Setup advertising
Bobty 2:9090120e2656 131 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
Bobty 2:9090120e2656 132 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
Bobty 2:9090120e2656 133 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
Bobty 2:9090120e2656 134 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
Bobty 2:9090120e2656 135 ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
Bobty 2:9090120e2656 136 ble.gap().startAdvertising();
Bobty 2:9090120e2656 137
Bobty 2:9090120e2656 138 while (true) {
Bobty 2:9090120e2656 139 ble.waitForEvent();
Bobty 3:a4b8d67de1b1 140
Bobty 3:a4b8d67de1b1 141 loopCount++;
Bobty 3:a4b8d67de1b1 142 if (loopCount < 5)
Bobty 3:a4b8d67de1b1 143 continue;
Bobty 3:a4b8d67de1b1 144 loopCount = 0;
Bobty 3:a4b8d67de1b1 145
Bobty 3:a4b8d67de1b1 146 time_t rawtime;
Bobty 3:a4b8d67de1b1 147 struct tm * timeinfo;
Bobty 3:a4b8d67de1b1 148 time (&rawtime);
Bobty 3:a4b8d67de1b1 149 timeinfo = localtime (&rawtime);
Bobty 3:a4b8d67de1b1 150 printf ("Current local time and date: %s callbacks %d retval %d\r\n", asctime(timeinfo), callbackCount, retval);
Bobty 3:a4b8d67de1b1 151 printf ("Timest %02x %02x %02x %02x %02x %02x %02x %ld\r\n", testbuf[0],
Bobty 3:a4b8d67de1b1 152 testbuf[1], testbuf[2], testbuf[3], testbuf[4], testbuf[5], testbuf[6], retval);
Bobty 3:a4b8d67de1b1 153 printf ("serv %d buflen %d mycode %d offs %d butcode %d\r\n", servcode, buflen, mycode, offs, butcode);
Bobty 3:a4b8d67de1b1 154 printf ("val %ld\r\n", watchTimeService.getValueHandle());
Bobty 2:9090120e2656 155 }
Bobty 2:9090120e2656 156 }
Bobty 2:9090120e2656 157
Bobty 2:9090120e2656 158 /*
Bobty 2:9090120e2656 159
Bobty 2:9090120e2656 160 #include "mbed.h"
Bobty 0:0d5ac2fd4620 161 #include "BLEDevice.h"
Bobty 0:0d5ac2fd4620 162 #include "DeviceInformationService.h"
Bobty 0:0d5ac2fd4620 163
Bobty 0:0d5ac2fd4620 164 // BLE Device etc
Bobty 0:0d5ac2fd4620 165 BLEDevice ble;
Bobty 0:0d5ac2fd4620 166 DigitalOut ledIndicator(LED1);
Bobty 0:0d5ac2fd4620 167 DigitalOut testOut(p1);
Bobty 0:0d5ac2fd4620 168
Bobty 1:c3d7e673cdd2 169 // Device name
Bobty 1:c3d7e673cdd2 170 const static char DEVICE_NAME[] = "JOESALARM";
Bobty 1:c3d7e673cdd2 171
Bobty 1:c3d7e673cdd2 172 // UUID for CurTimeService & TimeBlockCharacteristic
Bobty 1:c3d7e673cdd2 173 const uint16_t UUID_CUR_TIME_SERVICE = 0xA000;
Bobty 1:c3d7e673cdd2 174 const uint16_t UUID_TIME_BLOCK_CHARACTERISTIC = 0xA001;
Bobty 1:c3d7e673cdd2 175
Bobty 1:c3d7e673cdd2 176 // List of supported service UUIDs
Bobty 1:c3d7e673cdd2 177 static const uint16_t uuid16_list[] = {UUID_CUR_TIME_SERVICE};
Bobty 0:0d5ac2fd4620 178
Bobty 1:c3d7e673cdd2 179 // Time is packed in an array of bytes
Bobty 1:c3d7e673cdd2 180 const int SIZE_OF_TIME_BLOCK = 7;
Bobty 1:c3d7e673cdd2 181 uint8_t timeBlockInitValue[SIZE_OF_TIME_BLOCK];
Bobty 1:c3d7e673cdd2 182 uint8_t curTimeBlock[SIZE_OF_TIME_BLOCK];
Bobty 1:c3d7e673cdd2 183
Bobty 1:c3d7e673cdd2 184 // GATT Characteristic for time block
Bobty 2:9090120e2656 185 GattCharacteristic timeBlockCharacteristic(UUID_TIME_BLOCK_CHARACTERISTIC, timeBlockInitValue, SIZE_OF_TIME_BLOCK, SIZE_OF_TIME_BLOCK,
Bobty 2:9090120e2656 186 GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
Bobty 1:c3d7e673cdd2 187
Bobty 1:c3d7e673cdd2 188 // Callback when connection lost
Bobty 0:0d5ac2fd4620 189 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
Bobty 0:0d5ac2fd4620 190 {
Bobty 0:0d5ac2fd4620 191 ble.startAdvertising(); // restart advertising
Bobty 0:0d5ac2fd4620 192 }
Bobty 0:0d5ac2fd4620 193
Bobty 1:c3d7e673cdd2 194 // Callback for ticker
Bobty 1:c3d7e673cdd2 195 int tickCount = 0;
Bobty 1:c3d7e673cdd2 196 bool showInfo = false;
Bobty 1:c3d7e673cdd2 197 int writeSinceLast = 0;
Bobty 0:0d5ac2fd4620 198 void periodicCallback(void)
Bobty 0:0d5ac2fd4620 199 {
Bobty 2:9090120e2656 200 ledIndicator = !ledIndicator;
Bobty 0:0d5ac2fd4620 201 testOut = !testOut;
Bobty 1:c3d7e673cdd2 202 tickCount++;
Bobty 1:c3d7e673cdd2 203 if (tickCount > 100)
Bobty 1:c3d7e673cdd2 204 {
Bobty 1:c3d7e673cdd2 205 showInfo = true;
Bobty 1:c3d7e673cdd2 206 tickCount = 0;
Bobty 1:c3d7e673cdd2 207 }
Bobty 0:0d5ac2fd4620 208 }
Bobty 0:0d5ac2fd4620 209
Bobty 1:c3d7e673cdd2 210 // Data written callback
Bobty 1:c3d7e673cdd2 211 void onDataWrittenCallback(const GattCharacteristicWriteCBParams *params)
Bobty 1:c3d7e673cdd2 212 {
Bobty 1:c3d7e673cdd2 213 if ((params->charHandle == timeBlockCharacteristic.getValueHandle()))
Bobty 1:c3d7e673cdd2 214 {
Bobty 2:9090120e2656 215 // Validate time
Bobty 2:9090120e2656 216 int year = params->data[0] * 100 + params->data[1];
Bobty 2:9090120e2656 217 int month = params->data[2];
Bobty 2:9090120e2656 218 int day = params->data[3];
Bobty 1:c3d7e673cdd2 219 // && (params->len == SIZE_OF_TIME_BLOCK)
Bobty 1:c3d7e673cdd2 220 writeSinceLast = params->len;
Bobty 1:c3d7e673cdd2 221 memcpy(curTimeBlock, params->data, SIZE_OF_TIME_BLOCK);
Bobty 1:c3d7e673cdd2 222 }
Bobty 1:c3d7e673cdd2 223 writeSinceLast = true;
Bobty 1:c3d7e673cdd2 224 }
Bobty 1:c3d7e673cdd2 225
Bobty 1:c3d7e673cdd2 226 // Main
Bobty 0:0d5ac2fd4620 227 int main(void)
Bobty 0:0d5ac2fd4620 228 {
Bobty 0:0d5ac2fd4620 229 ledIndicator = 0;
Bobty 0:0d5ac2fd4620 230 testOut = 0;
Bobty 0:0d5ac2fd4620 231
Bobty 0:0d5ac2fd4620 232 // Ticker is interrupt driven
Bobty 0:0d5ac2fd4620 233 Ticker ticker;
Bobty 0:0d5ac2fd4620 234 ticker.attach_us(periodicCallback, 100000);
Bobty 0:0d5ac2fd4620 235
Bobty 1:c3d7e673cdd2 236 // Initial value for the time block characteristic
Bobty 1:c3d7e673cdd2 237 memset(timeBlockInitValue, 0, sizeof(timeBlockInitValue));
Bobty 1:c3d7e673cdd2 238
Bobty 1:c3d7e673cdd2 239 // Init BLE and register callbacks
Bobty 0:0d5ac2fd4620 240 ble.init();
Bobty 0:0d5ac2fd4620 241 ble.onDisconnection(disconnectionCallback);
Bobty 1:c3d7e673cdd2 242 ble.onDataWritten(onDataWrittenCallback);
Bobty 1:c3d7e673cdd2 243
Bobty 1:c3d7e673cdd2 244 // Add the time setting service
Bobty 1:c3d7e673cdd2 245 GattCharacteristic *charTable[] = {&timeBlockCharacteristic};
Bobty 1:c3d7e673cdd2 246 GattService timeBlockService(UUID_CUR_TIME_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
Bobty 1:c3d7e673cdd2 247 ble.addService(timeBlockService);
Bobty 0:0d5ac2fd4620 248
Bobty 0:0d5ac2fd4620 249 // Setup advertising
Bobty 2:9090120e2656 250 // BREDR_NOT_SUPPORTED means classic bluetooth not supported;
Bobty 2:9090120e2656 251 // LE_GENERAL_DISCOVERABLE means that this peripheral can be
Bobty 2:9090120e2656 252 // discovered by any BLE scanner--i.e. any phone.
Bobty 0:0d5ac2fd4620 253 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
Bobty 0:0d5ac2fd4620 254
Bobty 1:c3d7e673cdd2 255 // Add services to payload
Bobty 1:c3d7e673cdd2 256 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
Bobty 1:c3d7e673cdd2 257
Bobty 2:9090120e2656 258 // This is where we're collecting the device name into the advertisement payload.
Bobty 0:0d5ac2fd4620 259 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
Bobty 0:0d5ac2fd4620 260
Bobty 2:9090120e2656 261 // We'd like for this BLE peripheral to be connectable.
Bobty 0:0d5ac2fd4620 262 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
Bobty 0:0d5ac2fd4620 263
Bobty 2:9090120e2656 264 // set the interval at which advertisements are sent out; this has
Bobty 2:9090120e2656 265 // an implication power consumption--radio activity being a
Bobty 2:9090120e2656 266 // biggest draw on average power. The other software controllable
Bobty 2:9090120e2656 267 // parameter which influences power is the radio's TX power
Bobty 2:9090120e2656 268 // level--there's an API to adjust that.
Bobty 2:9090120e2656 269 ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000));
Bobty 0:0d5ac2fd4620 270
Bobty 2:9090120e2656 271
Bobty 0:0d5ac2fd4620 272 ble.startAdvertising();
Bobty 0:0d5ac2fd4620 273
Bobty 0:0d5ac2fd4620 274 while (true)
Bobty 0:0d5ac2fd4620 275 {
Bobty 0:0d5ac2fd4620 276 ble.waitForEvent();
Bobty 1:c3d7e673cdd2 277
Bobty 1:c3d7e673cdd2 278 if (showInfo)
Bobty 1:c3d7e673cdd2 279 {
Bobty 1:c3d7e673cdd2 280 printf("Time info: ");
Bobty 1:c3d7e673cdd2 281 for (int i = 0; i < SIZE_OF_TIME_BLOCK; i++)
Bobty 1:c3d7e673cdd2 282 {
Bobty 1:c3d7e673cdd2 283 printf("%02d", curTimeBlock[i]);
Bobty 1:c3d7e673cdd2 284 }
Bobty 1:c3d7e673cdd2 285 printf(" - writeSinceLast %d\r\n", writeSinceLast);
Bobty 1:c3d7e673cdd2 286 showInfo = false;
Bobty 1:c3d7e673cdd2 287 writeSinceLast = 0;
Bobty 1:c3d7e673cdd2 288 }
Bobty 0:0d5ac2fd4620 289 }
Bobty 0:0d5ac2fd4620 290 }
Bobty 2:9090120e2656 291 */