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:
Tue Mar 10 16:50:59 2015 +0000
Revision:
1:c3d7e673cdd2
Parent:
0:0d5ac2fd4620
Child:
2:9090120e2656
Working with some debug code but only valid for 1 byte write

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Bobty 0:0d5ac2fd4620 1 // BLE Alarm Watch
Bobty 0:0d5ac2fd4620 2 // Based on BLE heart-rate-monitor from MBED team
Bobty 0:0d5ac2fd4620 3 // Rob Dobson, 2015
Bobty 0:0d5ac2fd4620 4
Bobty 0:0d5ac2fd4620 5 #include "mbed.h"
Bobty 0:0d5ac2fd4620 6 #include "BLEDevice.h"
Bobty 0:0d5ac2fd4620 7 #include "DeviceInformationService.h"
Bobty 0:0d5ac2fd4620 8
Bobty 0:0d5ac2fd4620 9 // BLE Device etc
Bobty 0:0d5ac2fd4620 10 BLEDevice ble;
Bobty 0:0d5ac2fd4620 11 DigitalOut ledIndicator(LED1);
Bobty 0:0d5ac2fd4620 12 DigitalOut testOut(p1);
Bobty 0:0d5ac2fd4620 13
Bobty 1:c3d7e673cdd2 14 // Device name
Bobty 1:c3d7e673cdd2 15 const static char DEVICE_NAME[] = "JOESALARM";
Bobty 1:c3d7e673cdd2 16
Bobty 1:c3d7e673cdd2 17 // UUID for CurTimeService & TimeBlockCharacteristic
Bobty 1:c3d7e673cdd2 18 const uint16_t UUID_CUR_TIME_SERVICE = 0xA000;
Bobty 1:c3d7e673cdd2 19 const uint16_t UUID_TIME_BLOCK_CHARACTERISTIC = 0xA001;
Bobty 1:c3d7e673cdd2 20
Bobty 1:c3d7e673cdd2 21 // List of supported service UUIDs
Bobty 1:c3d7e673cdd2 22 static const uint16_t uuid16_list[] = {UUID_CUR_TIME_SERVICE};
Bobty 0:0d5ac2fd4620 23
Bobty 1:c3d7e673cdd2 24 // Time is packed in an array of bytes
Bobty 1:c3d7e673cdd2 25 const int SIZE_OF_TIME_BLOCK = 7;
Bobty 1:c3d7e673cdd2 26 uint8_t timeBlockInitValue[SIZE_OF_TIME_BLOCK];
Bobty 1:c3d7e673cdd2 27 uint8_t curTimeBlock[SIZE_OF_TIME_BLOCK];
Bobty 1:c3d7e673cdd2 28
Bobty 1:c3d7e673cdd2 29 // GATT Characteristic for time block
Bobty 1:c3d7e673cdd2 30 ReadWriteGattCharacteristic<uint8_t> timeBlockCharacteristic(UUID_TIME_BLOCK_CHARACTERISTIC, timeBlockInitValue);
Bobty 1:c3d7e673cdd2 31
Bobty 1:c3d7e673cdd2 32 // Callback when connection lost
Bobty 0:0d5ac2fd4620 33 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
Bobty 0:0d5ac2fd4620 34 {
Bobty 0:0d5ac2fd4620 35 ble.startAdvertising(); // restart advertising
Bobty 0:0d5ac2fd4620 36 }
Bobty 0:0d5ac2fd4620 37
Bobty 1:c3d7e673cdd2 38 // Callback for ticker
Bobty 1:c3d7e673cdd2 39 int tickCount = 0;
Bobty 1:c3d7e673cdd2 40 bool showInfo = false;
Bobty 1:c3d7e673cdd2 41 int writeSinceLast = 0;
Bobty 0:0d5ac2fd4620 42 void periodicCallback(void)
Bobty 0:0d5ac2fd4620 43 {
Bobty 0:0d5ac2fd4620 44 ledIndicator = !ledIndicator; /* Do blinky on LED1 while we're waiting for BLE events */
Bobty 0:0d5ac2fd4620 45 testOut = !testOut;
Bobty 1:c3d7e673cdd2 46 tickCount++;
Bobty 1:c3d7e673cdd2 47 if (tickCount > 100)
Bobty 1:c3d7e673cdd2 48 {
Bobty 1:c3d7e673cdd2 49 showInfo = true;
Bobty 1:c3d7e673cdd2 50 tickCount = 0;
Bobty 1:c3d7e673cdd2 51 }
Bobty 0:0d5ac2fd4620 52 }
Bobty 0:0d5ac2fd4620 53
Bobty 1:c3d7e673cdd2 54 // Data written callback
Bobty 1:c3d7e673cdd2 55 void onDataWrittenCallback(const GattCharacteristicWriteCBParams *params)
Bobty 1:c3d7e673cdd2 56 {
Bobty 1:c3d7e673cdd2 57 if ((params->charHandle == timeBlockCharacteristic.getValueHandle()))
Bobty 1:c3d7e673cdd2 58 {
Bobty 1:c3d7e673cdd2 59 // && (params->len == SIZE_OF_TIME_BLOCK)
Bobty 1:c3d7e673cdd2 60 writeSinceLast = params->len;
Bobty 1:c3d7e673cdd2 61 memcpy(curTimeBlock, params->data, SIZE_OF_TIME_BLOCK);
Bobty 1:c3d7e673cdd2 62 }
Bobty 1:c3d7e673cdd2 63 writeSinceLast = true;
Bobty 1:c3d7e673cdd2 64 }
Bobty 1:c3d7e673cdd2 65
Bobty 1:c3d7e673cdd2 66 // Main
Bobty 0:0d5ac2fd4620 67 int main(void)
Bobty 0:0d5ac2fd4620 68 {
Bobty 0:0d5ac2fd4620 69 ledIndicator = 0;
Bobty 0:0d5ac2fd4620 70 testOut = 0;
Bobty 0:0d5ac2fd4620 71
Bobty 0:0d5ac2fd4620 72 // Ticker is interrupt driven
Bobty 0:0d5ac2fd4620 73 Ticker ticker;
Bobty 0:0d5ac2fd4620 74 ticker.attach_us(periodicCallback, 100000);
Bobty 0:0d5ac2fd4620 75
Bobty 1:c3d7e673cdd2 76 // Initial value for the time block characteristic
Bobty 1:c3d7e673cdd2 77 memset(timeBlockInitValue, 0, sizeof(timeBlockInitValue));
Bobty 1:c3d7e673cdd2 78
Bobty 1:c3d7e673cdd2 79 // Init BLE and register callbacks
Bobty 0:0d5ac2fd4620 80 ble.init();
Bobty 0:0d5ac2fd4620 81 ble.onDisconnection(disconnectionCallback);
Bobty 1:c3d7e673cdd2 82 ble.onDataWritten(onDataWrittenCallback);
Bobty 1:c3d7e673cdd2 83
Bobty 1:c3d7e673cdd2 84 // Add the time setting service
Bobty 1:c3d7e673cdd2 85 GattCharacteristic *charTable[] = {&timeBlockCharacteristic};
Bobty 1:c3d7e673cdd2 86 GattService timeBlockService(UUID_CUR_TIME_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
Bobty 1:c3d7e673cdd2 87 ble.addService(timeBlockService);
Bobty 0:0d5ac2fd4620 88
Bobty 0:0d5ac2fd4620 89 // Setup advertising
Bobty 0:0d5ac2fd4620 90 /* BREDR_NOT_SUPPORTED means classic bluetooth not supported;
Bobty 0:0d5ac2fd4620 91 * LE_GENERAL_DISCOVERABLE means that this peripheral can be
Bobty 0:0d5ac2fd4620 92 * discovered by any BLE scanner--i.e. any phone. */
Bobty 0:0d5ac2fd4620 93 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
Bobty 0:0d5ac2fd4620 94
Bobty 1:c3d7e673cdd2 95 // Add services to payload
Bobty 1:c3d7e673cdd2 96 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
Bobty 1:c3d7e673cdd2 97
Bobty 0:0d5ac2fd4620 98 /* This is where we're collecting the device name into the advertisement payload. */
Bobty 0:0d5ac2fd4620 99 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
Bobty 0:0d5ac2fd4620 100
Bobty 0:0d5ac2fd4620 101 /* We'd like for this BLE peripheral to be connectable. */
Bobty 0:0d5ac2fd4620 102 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
Bobty 0:0d5ac2fd4620 103
Bobty 0:0d5ac2fd4620 104 /* set the interval at which advertisements are sent out; this has
Bobty 0:0d5ac2fd4620 105 * an implication power consumption--radio activity being a
Bobty 0:0d5ac2fd4620 106 * biggest draw on average power. The other software controllable
Bobty 0:0d5ac2fd4620 107 * parameter which influences power is the radio's TX power
Bobty 0:0d5ac2fd4620 108 * level--there's an API to adjust that. */
Bobty 0:0d5ac2fd4620 109 ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); /* 1000ms. */
Bobty 0:0d5ac2fd4620 110
Bobty 0:0d5ac2fd4620 111 /* we're finally good to go with advertisements. */
Bobty 0:0d5ac2fd4620 112 ble.startAdvertising();
Bobty 0:0d5ac2fd4620 113
Bobty 0:0d5ac2fd4620 114 while (true)
Bobty 0:0d5ac2fd4620 115 {
Bobty 0:0d5ac2fd4620 116 ble.waitForEvent();
Bobty 1:c3d7e673cdd2 117
Bobty 1:c3d7e673cdd2 118 if (showInfo)
Bobty 1:c3d7e673cdd2 119 {
Bobty 1:c3d7e673cdd2 120 printf("Time info: ");
Bobty 1:c3d7e673cdd2 121 for (int i = 0; i < SIZE_OF_TIME_BLOCK; i++)
Bobty 1:c3d7e673cdd2 122 {
Bobty 1:c3d7e673cdd2 123 printf("%02d", curTimeBlock[i]);
Bobty 1:c3d7e673cdd2 124 }
Bobty 1:c3d7e673cdd2 125 printf(" - writeSinceLast %d\r\n", writeSinceLast);
Bobty 1:c3d7e673cdd2 126 showInfo = false;
Bobty 1:c3d7e673cdd2 127 writeSinceLast = 0;
Bobty 1:c3d7e673cdd2 128 }
Bobty 0:0d5ac2fd4620 129 }
Bobty 0:0d5ac2fd4620 130 // /* Setup primary service. */
Bobty 0:0d5ac2fd4620 131 // uint8_t hrmCounter = 100; // init HRM to 100bps
Bobty 0:0d5ac2fd4620 132 // HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER);
Bobty 0:0d5ac2fd4620 133 //
Bobty 0:0d5ac2fd4620 134 // /* Setup auxiliary service. */
Bobty 0:0d5ac2fd4620 135 // DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
Bobty 0:0d5ac2fd4620 136 //
Bobty 0:0d5ac2fd4620 137 // /* Setup advertising. */
Bobty 0:0d5ac2fd4620 138 // ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
Bobty 0:0d5ac2fd4620 139 // ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
Bobty 0:0d5ac2fd4620 140 // ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
Bobty 0:0d5ac2fd4620 141 // ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
Bobty 0:0d5ac2fd4620 142 // ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
Bobty 0:0d5ac2fd4620 143 // ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000));
Bobty 0:0d5ac2fd4620 144 // ble.startAdvertising();
Bobty 0:0d5ac2fd4620 145 //
Bobty 0:0d5ac2fd4620 146 // // infinite loop
Bobty 0:0d5ac2fd4620 147 // while (1) {
Bobty 0:0d5ac2fd4620 148 // // check for trigger from periodicCallback()
Bobty 0:0d5ac2fd4620 149 // if (triggerSensorPolling && ble.getGapState().connected) {
Bobty 0:0d5ac2fd4620 150 // triggerSensorPolling = false;
Bobty 0:0d5ac2fd4620 151 //
Bobty 0:0d5ac2fd4620 152 // // Do blocking calls or whatever is necessary for sensor polling.
Bobty 0:0d5ac2fd4620 153 // // In our case, we simply update the HRM measurement.
Bobty 0:0d5ac2fd4620 154 // hrmCounter++;
Bobty 0:0d5ac2fd4620 155 //
Bobty 0:0d5ac2fd4620 156 // // 100 <= HRM bps <=175
Bobty 0:0d5ac2fd4620 157 // if (hrmCounter == 175) {
Bobty 0:0d5ac2fd4620 158 // hrmCounter = 100;
Bobty 0:0d5ac2fd4620 159 // }
Bobty 0:0d5ac2fd4620 160 //
Bobty 0:0d5ac2fd4620 161 // // update bps
Bobty 0:0d5ac2fd4620 162 // hrService.updateHeartRate(hrmCounter);
Bobty 0:0d5ac2fd4620 163 // } else {
Bobty 0:0d5ac2fd4620 164 // ble.waitForEvent(); // low power wait for event
Bobty 0:0d5ac2fd4620 165 // }
Bobty 0:0d5ac2fd4620 166 // }
Bobty 0:0d5ac2fd4620 167 }