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@0:0d5ac2fd4620, 2015-03-10 (annotated)
- Committer:
- Bobty
- Date:
- Tue Mar 10 15:29:07 2015 +0000
- Revision:
- 0:0d5ac2fd4620
- Child:
- 1:c3d7e673cdd2
First rev based on code at http://ble-intros.readthedocs.org/en/latest/AdvSamples/LEDReadWrite/
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 | 0:0d5ac2fd4620 | 14 | const static char DEVICE_NAME[] = "ALMW"; |
Bobty | 0:0d5ac2fd4620 | 15 | //static const uint16_t uuid16_list[] = {GattService::UUID_ALARM_WATCH_SERVICE, |
Bobty | 0:0d5ac2fd4620 | 16 | // GattService::UUID_DEVICE_INFORMATION_SERVICE}; |
Bobty | 0:0d5ac2fd4620 | 17 | // |
Bobty | 0:0d5ac2fd4620 | 18 | |
Bobty | 0:0d5ac2fd4620 | 19 | ///* |
Bobty | 0:0d5ac2fd4620 | 20 | //* Define a custom UUID, first as an array of uint8_t and then convert to |
Bobty | 0:0d5ac2fd4620 | 21 | //* a proper UUID later. The UUID must be 16 bytes (128-bits, 16 letters) |
Bobty | 0:0d5ac2fd4620 | 22 | //* long - here we have padded out to 16 bytes by adding an extra '0' at |
Bobty | 0:0d5ac2fd4620 | 23 | //* the end. Make sure you fill more than 4 bytes otherwise it will count |
Bobty | 0:0d5ac2fd4620 | 24 | //* as a 'short' code and you could end up using a predefined value from |
Bobty | 0:0d5ac2fd4620 | 25 | //* the BLE spec. |
Bobty | 0:0d5ac2fd4620 | 26 | //*/ |
Bobty | 0:0d5ac2fd4620 | 27 | //uint8_t raw_characteristic_uuid[16] = { |
Bobty | 0:0d5ac2fd4620 | 28 | // 'M', 'Y', '_', 'T', |
Bobty | 0:0d5ac2fd4620 | 29 | // 'E', 'S', 'T', '_', |
Bobty | 0:0d5ac2fd4620 | 30 | // 'C', 'H', 'A', 'R', |
Bobty | 0:0d5ac2fd4620 | 31 | // 0, 0, 0, 0 |
Bobty | 0:0d5ac2fd4620 | 32 | //}; |
Bobty | 0:0d5ac2fd4620 | 33 | //// Create a proper UUID - use the built in function to do this correctly |
Bobty | 0:0d5ac2fd4620 | 34 | //UUID characteristic_uuid = UUID(raw_characteristic_uuid); |
Bobty | 0:0d5ac2fd4620 | 35 | //// Setup some dummy properties for our characteristic |
Bobty | 0:0d5ac2fd4620 | 36 | //static uint8_t my_char_values[2] = { 15, 10 }; |
Bobty | 0:0d5ac2fd4620 | 37 | ///* |
Bobty | 0:0d5ac2fd4620 | 38 | //* Here we create our Characteristic adding in the dummy parameter values |
Bobty | 0:0d5ac2fd4620 | 39 | //* we just setup, we also make it readable and writeable meaning that a |
Bobty | 0:0d5ac2fd4620 | 40 | //* central can read and update the parameters we have stored. |
Bobty | 0:0d5ac2fd4620 | 41 | //*/ |
Bobty | 0:0d5ac2fd4620 | 42 | //GattCharacteristic pattern( |
Bobty | 0:0d5ac2fd4620 | 43 | // characteristic_uuid, |
Bobty | 0:0d5ac2fd4620 | 44 | // my_char_values, |
Bobty | 0:0d5ac2fd4620 | 45 | // sizeof(my_char_values), |
Bobty | 0:0d5ac2fd4620 | 46 | // sizeof(my_char_values), |
Bobty | 0:0d5ac2fd4620 | 47 | // GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
Bobty | 0:0d5ac2fd4620 | 48 | //); |
Bobty | 0:0d5ac2fd4620 | 49 | ///* |
Bobty | 0:0d5ac2fd4620 | 50 | //* List the Characteristics of our custom Service, can have one or more |
Bobty | 0:0d5ac2fd4620 | 51 | //* of these each with a custom UUID and parameter values. |
Bobty | 0:0d5ac2fd4620 | 52 | //*/ |
Bobty | 0:0d5ac2fd4620 | 53 | //GattCharacteristic *my_service_chars[] = { |
Bobty | 0:0d5ac2fd4620 | 54 | // &new_alert, |
Bobty | 0:0d5ac2fd4620 | 55 | //}; |
Bobty | 0:0d5ac2fd4620 | 56 | //// Now setup a custom Service UUID, in the same fashion as for the Characteristic |
Bobty | 0:0d5ac2fd4620 | 57 | //uint8_t raw_service_uuid[16] = { |
Bobty | 0:0d5ac2fd4620 | 58 | // 'M', 'Y', '_', 'T', |
Bobty | 0:0d5ac2fd4620 | 59 | // 'E', 'S', 'T', '_', |
Bobty | 0:0d5ac2fd4620 | 60 | // 'S', 'E', 'R', 'V', |
Bobty | 0:0d5ac2fd4620 | 61 | // 'I', 'C', 'E', 0 |
Bobty | 0:0d5ac2fd4620 | 62 | //}; |
Bobty | 0:0d5ac2fd4620 | 63 | //UUID service_uuid = UUID(raw_service_uuid); |
Bobty | 0:0d5ac2fd4620 | 64 | //// Setup the Service with the UUID and all of the Characteristics |
Bobty | 0:0d5ac2fd4620 | 65 | //GattService my_service( |
Bobty | 0:0d5ac2fd4620 | 66 | // service_uuid, |
Bobty | 0:0d5ac2fd4620 | 67 | // my_service_chars, |
Bobty | 0:0d5ac2fd4620 | 68 | // sizeof(my_service_chars) / sizeof(GattCharacteristic *) |
Bobty | 0:0d5ac2fd4620 | 69 | //); |
Bobty | 0:0d5ac2fd4620 | 70 | ///* |
Bobty | 0:0d5ac2fd4620 | 71 | //* Now list the long UUIDs of the services we offer, these will be bundled into the |
Bobty | 0:0d5ac2fd4620 | 72 | //* advertisement. It may look like repetition of 'raw_service_uuid' but here you can |
Bobty | 0:0d5ac2fd4620 | 73 | //* list multiple UUIDs one after another. |
Bobty | 0:0d5ac2fd4620 | 74 | //*/ |
Bobty | 0:0d5ac2fd4620 | 75 | //static const uint8_t uuid128_list[] = { |
Bobty | 0:0d5ac2fd4620 | 76 | // 'M', 'Y', '_', 'T', 'E', 'S', 'T', '_', 'S', 'E', 'R', 'V', 'I', 'C', 'E', 0 |
Bobty | 0:0d5ac2fd4620 | 77 | // // List more long UUIDs below... |
Bobty | 0:0d5ac2fd4620 | 78 | //}; |
Bobty | 0:0d5ac2fd4620 | 79 | // |
Bobty | 0:0d5ac2fd4620 | 80 | //... |
Bobty | 0:0d5ac2fd4620 | 81 | // |
Bobty | 0:0d5ac2fd4620 | 82 | ///* |
Bobty | 0:0d5ac2fd4620 | 83 | //* Now we change from using short (16-bit) UUIDs to long (128-bit) UUIDs, comment out |
Bobty | 0:0d5ac2fd4620 | 84 | //* the old section of the payload and add the new 128-bit section. |
Bobty | 0:0d5ac2fd4620 | 85 | //*/ |
Bobty | 0:0d5ac2fd4620 | 86 | ///*bluetooth->accumulateAdvertisingPayload( |
Bobty | 0:0d5ac2fd4620 | 87 | // GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, |
Bobty | 0:0d5ac2fd4620 | 88 | // (uint8_t *)uuid16_list, |
Bobty | 0:0d5ac2fd4620 | 89 | // sizeof(uuid16_list) |
Bobty | 0:0d5ac2fd4620 | 90 | //);*/ |
Bobty | 0:0d5ac2fd4620 | 91 | //bluetooth->accumulateAdvertisingPayload( |
Bobty | 0:0d5ac2fd4620 | 92 | // GapAdvertisingData::INCOMPLETE_LIST_128BIT_SERVICE_IDS, |
Bobty | 0:0d5ac2fd4620 | 93 | // (uint8_t *)uuid128_list, |
Bobty | 0:0d5ac2fd4620 | 94 | // sizeof(uuid128_list) |
Bobty | 0:0d5ac2fd4620 | 95 | //); |
Bobty | 0:0d5ac2fd4620 | 96 | // |
Bobty | 0:0d5ac2fd4620 | 97 | // |
Bobty | 0:0d5ac2fd4620 | 98 | // |
Bobty | 0:0d5ac2fd4620 | 99 | // |
Bobty | 0:0d5ac2fd4620 | 100 | // |
Bobty | 0:0d5ac2fd4620 | 101 | |
Bobty | 0:0d5ac2fd4620 | 102 | static volatile bool triggerSensorPolling = false; |
Bobty | 0:0d5ac2fd4620 | 103 | |
Bobty | 0:0d5ac2fd4620 | 104 | void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) |
Bobty | 0:0d5ac2fd4620 | 105 | { |
Bobty | 0:0d5ac2fd4620 | 106 | ble.startAdvertising(); // restart advertising |
Bobty | 0:0d5ac2fd4620 | 107 | } |
Bobty | 0:0d5ac2fd4620 | 108 | |
Bobty | 0:0d5ac2fd4620 | 109 | void periodicCallback(void) |
Bobty | 0:0d5ac2fd4620 | 110 | { |
Bobty | 0:0d5ac2fd4620 | 111 | ledIndicator = !ledIndicator; /* Do blinky on LED1 while we're waiting for BLE events */ |
Bobty | 0:0d5ac2fd4620 | 112 | testOut = !testOut; |
Bobty | 0:0d5ac2fd4620 | 113 | } |
Bobty | 0:0d5ac2fd4620 | 114 | |
Bobty | 0:0d5ac2fd4620 | 115 | int main(void) |
Bobty | 0:0d5ac2fd4620 | 116 | { |
Bobty | 0:0d5ac2fd4620 | 117 | ledIndicator = 0; |
Bobty | 0:0d5ac2fd4620 | 118 | testOut = 0; |
Bobty | 0:0d5ac2fd4620 | 119 | |
Bobty | 0:0d5ac2fd4620 | 120 | // Ticker is interrupt driven |
Bobty | 0:0d5ac2fd4620 | 121 | Ticker ticker; |
Bobty | 0:0d5ac2fd4620 | 122 | ticker.attach_us(periodicCallback, 100000); |
Bobty | 0:0d5ac2fd4620 | 123 | |
Bobty | 0:0d5ac2fd4620 | 124 | // Init BLE |
Bobty | 0:0d5ac2fd4620 | 125 | ble.init(); |
Bobty | 0:0d5ac2fd4620 | 126 | ble.onDisconnection(disconnectionCallback); |
Bobty | 0:0d5ac2fd4620 | 127 | |
Bobty | 0:0d5ac2fd4620 | 128 | // Setup advertising |
Bobty | 0:0d5ac2fd4620 | 129 | /* BREDR_NOT_SUPPORTED means classic bluetooth not supported; |
Bobty | 0:0d5ac2fd4620 | 130 | * LE_GENERAL_DISCOVERABLE means that this peripheral can be |
Bobty | 0:0d5ac2fd4620 | 131 | * discovered by any BLE scanner--i.e. any phone. */ |
Bobty | 0:0d5ac2fd4620 | 132 | ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
Bobty | 0:0d5ac2fd4620 | 133 | |
Bobty | 0:0d5ac2fd4620 | 134 | /* This is where we're collecting the device name into the advertisement payload. */ |
Bobty | 0:0d5ac2fd4620 | 135 | ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
Bobty | 0:0d5ac2fd4620 | 136 | |
Bobty | 0:0d5ac2fd4620 | 137 | /* We'd like for this BLE peripheral to be connectable. */ |
Bobty | 0:0d5ac2fd4620 | 138 | ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
Bobty | 0:0d5ac2fd4620 | 139 | |
Bobty | 0:0d5ac2fd4620 | 140 | /* set the interval at which advertisements are sent out; this has |
Bobty | 0:0d5ac2fd4620 | 141 | * an implication power consumption--radio activity being a |
Bobty | 0:0d5ac2fd4620 | 142 | * biggest draw on average power. The other software controllable |
Bobty | 0:0d5ac2fd4620 | 143 | * parameter which influences power is the radio's TX power |
Bobty | 0:0d5ac2fd4620 | 144 | * level--there's an API to adjust that. */ |
Bobty | 0:0d5ac2fd4620 | 145 | ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); /* 1000ms. */ |
Bobty | 0:0d5ac2fd4620 | 146 | |
Bobty | 0:0d5ac2fd4620 | 147 | /* we're finally good to go with advertisements. */ |
Bobty | 0:0d5ac2fd4620 | 148 | ble.startAdvertising(); |
Bobty | 0:0d5ac2fd4620 | 149 | |
Bobty | 0:0d5ac2fd4620 | 150 | while (true) |
Bobty | 0:0d5ac2fd4620 | 151 | { |
Bobty | 0:0d5ac2fd4620 | 152 | ble.waitForEvent(); |
Bobty | 0:0d5ac2fd4620 | 153 | } |
Bobty | 0:0d5ac2fd4620 | 154 | // /* Setup primary service. */ |
Bobty | 0:0d5ac2fd4620 | 155 | // uint8_t hrmCounter = 100; // init HRM to 100bps |
Bobty | 0:0d5ac2fd4620 | 156 | // HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER); |
Bobty | 0:0d5ac2fd4620 | 157 | // |
Bobty | 0:0d5ac2fd4620 | 158 | // /* Setup auxiliary service. */ |
Bobty | 0:0d5ac2fd4620 | 159 | // DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); |
Bobty | 0:0d5ac2fd4620 | 160 | // |
Bobty | 0:0d5ac2fd4620 | 161 | // /* Setup advertising. */ |
Bobty | 0:0d5ac2fd4620 | 162 | // ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
Bobty | 0:0d5ac2fd4620 | 163 | // ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); |
Bobty | 0:0d5ac2fd4620 | 164 | // ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); |
Bobty | 0:0d5ac2fd4620 | 165 | // ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
Bobty | 0:0d5ac2fd4620 | 166 | // ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
Bobty | 0:0d5ac2fd4620 | 167 | // ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); |
Bobty | 0:0d5ac2fd4620 | 168 | // ble.startAdvertising(); |
Bobty | 0:0d5ac2fd4620 | 169 | // |
Bobty | 0:0d5ac2fd4620 | 170 | // // infinite loop |
Bobty | 0:0d5ac2fd4620 | 171 | // while (1) { |
Bobty | 0:0d5ac2fd4620 | 172 | // // check for trigger from periodicCallback() |
Bobty | 0:0d5ac2fd4620 | 173 | // if (triggerSensorPolling && ble.getGapState().connected) { |
Bobty | 0:0d5ac2fd4620 | 174 | // triggerSensorPolling = false; |
Bobty | 0:0d5ac2fd4620 | 175 | // |
Bobty | 0:0d5ac2fd4620 | 176 | // // Do blocking calls or whatever is necessary for sensor polling. |
Bobty | 0:0d5ac2fd4620 | 177 | // // In our case, we simply update the HRM measurement. |
Bobty | 0:0d5ac2fd4620 | 178 | // hrmCounter++; |
Bobty | 0:0d5ac2fd4620 | 179 | // |
Bobty | 0:0d5ac2fd4620 | 180 | // // 100 <= HRM bps <=175 |
Bobty | 0:0d5ac2fd4620 | 181 | // if (hrmCounter == 175) { |
Bobty | 0:0d5ac2fd4620 | 182 | // hrmCounter = 100; |
Bobty | 0:0d5ac2fd4620 | 183 | // } |
Bobty | 0:0d5ac2fd4620 | 184 | // |
Bobty | 0:0d5ac2fd4620 | 185 | // // update bps |
Bobty | 0:0d5ac2fd4620 | 186 | // hrService.updateHeartRate(hrmCounter); |
Bobty | 0:0d5ac2fd4620 | 187 | // } else { |
Bobty | 0:0d5ac2fd4620 | 188 | // ble.waitForEvent(); // low power wait for event |
Bobty | 0:0d5ac2fd4620 | 189 | // } |
Bobty | 0:0d5ac2fd4620 | 190 | // } |
Bobty | 0:0d5ac2fd4620 | 191 | } |