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@1:c3d7e673cdd2, 2015-03-10 (annotated)
- 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?
User | Revision | Line number | New 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 | } |