High level Bluetooth Low Energy API and radio abstraction layer
Fork of BLE_API by
main.cpp@9:124ae067ae27, 2013-12-16 (annotated)
- Committer:
- ktownsend
- Date:
- Mon Dec 16 19:43:33 2013 +0000
- Revision:
- 9:124ae067ae27
- Parent:
- 7:5e1f0d7f7c7d
- Child:
- 11:200931be5617
Preview code enabling most advertising features (requires new nRF51 firmware)
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ktownsend | 0:ace2e8d3ce79 | 1 | #include "mbed.h" |
ktownsend | 0:ace2e8d3ce79 | 2 | |
ktownsend | 0:ace2e8d3ce79 | 3 | #include "uuid.h" |
ktownsend | 2:ffc5216bd2cc | 4 | #include "GattService.h" |
ktownsend | 2:ffc5216bd2cc | 5 | #include "GattCharacteristic.h" |
ktownsend | 0:ace2e8d3ce79 | 6 | #include "hw/nrf51822.h" |
ktownsend | 0:ace2e8d3ce79 | 7 | |
ktownsend | 0:ace2e8d3ce79 | 8 | DigitalOut myled ( LED1 ); |
ktownsend | 0:ace2e8d3ce79 | 9 | |
ktownsend | 0:ace2e8d3ce79 | 10 | /* Radio HW abstraction layer */ |
ktownsend | 0:ace2e8d3ce79 | 11 | nRF51822 radio; |
ktownsend | 0:ace2e8d3ce79 | 12 | |
ktownsend | 0:ace2e8d3ce79 | 13 | /* Battery Level Service */ |
ktownsend | 0:ace2e8d3ce79 | 14 | /* See --> https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.battery_service.xml */ |
ktownsend | 2:ffc5216bd2cc | 15 | GattService battService ( 0x180F ); |
ktownsend | 3:46de446e82ed | 16 | GattCharacteristic battLevel ( 0x2A19, 1, 1, BLE_GATT_CHAR_PROPERTIES_NOTIFY | BLE_GATT_CHAR_PROPERTIES_READ ); |
ktownsend | 0:ace2e8d3ce79 | 17 | |
ktownsend | 0:ace2e8d3ce79 | 18 | /* Heart Rate Monitor Service */ |
ktownsend | 0:ace2e8d3ce79 | 19 | /* See --> https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml */ |
ktownsend | 2:ffc5216bd2cc | 20 | GattService hrmService ( 0x180D ); |
ktownsend | 3:46de446e82ed | 21 | GattCharacteristic hrmRate ( 0x2A37, 2, 3, BLE_GATT_CHAR_PROPERTIES_NOTIFY ); |
ktownsend | 3:46de446e82ed | 22 | GattCharacteristic hrmLocation ( 0x2A39, 1, 1, BLE_GATT_CHAR_PROPERTIES_READ ); |
ktownsend | 0:ace2e8d3ce79 | 23 | |
ktownsend | 0:ace2e8d3ce79 | 24 | /* Health Thermometer Service */ |
ktownsend | 0:ace2e8d3ce79 | 25 | /* See --> https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.health_thermometer.xml */ |
ktownsend | 2:ffc5216bd2cc | 26 | GattService thermService ( 0x1809 ); |
ktownsend | 3:46de446e82ed | 27 | GattCharacteristic thermTemp ( 0x2A1C, 5, 13, BLE_GATT_CHAR_PROPERTIES_INDICATE ); |
ktownsend | 3:46de446e82ed | 28 | GattCharacteristic thermType ( 0x2A1D, 1, 1, BLE_GATT_CHAR_PROPERTIES_READ ); |
ktownsend | 3:46de446e82ed | 29 | GattCharacteristic thermInterval ( 0x2A21, 2, 2, BLE_GATT_CHAR_PROPERTIES_READ ); |
ktownsend | 0:ace2e8d3ce79 | 30 | |
ktownsend | 0:ace2e8d3ce79 | 31 | /* Notify = device (server) sends data when it changes */ |
ktownsend | 5:7635f81a8e09 | 32 | /* Indicate = device (server) sends data when it changes and client confirms reception */ |
ktownsend | 5:7635f81a8e09 | 33 | |
ktownsend | 5:7635f81a8e09 | 34 | /* GAP Advertising Example (iBeacon) */ |
ktownsend | 6:425638944835 | 35 | GapAdvertisingParams advParams ( GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED ); |
ktownsend | 5:7635f81a8e09 | 36 | GapAdvertisingData advData; |
ktownsend | 7:5e1f0d7f7c7d | 37 | GapAdvertisingData scanResponse; |
ktownsend | 5:7635f81a8e09 | 38 | |
ktownsend | 5:7635f81a8e09 | 39 | uint8_t iBeaconPayload[25] = { 0x4C, 0x00, 0x02, 0x15, 0xE2, 0x0A, 0x39, 0xF4, 0x73, 0xF5, 0x4B, 0xC4, 0xA1, 0x2F, 0x17, 0xD1, 0xAD, 0x07, 0xA9, 0x61, 0x00, 0x00, 0x00, 0x00, 0xC8 }; |
ktownsend | 5:7635f81a8e09 | 40 | |
ktownsend | 5:7635f81a8e09 | 41 | void startBeacon(void) |
ktownsend | 5:7635f81a8e09 | 42 | { |
ktownsend | 5:7635f81a8e09 | 43 | /* iBeacon includes the FLAG and MSD fields */ |
ktownsend | 5:7635f81a8e09 | 44 | advData.addFlags(GapAdvertisingData::BREDR_NOT_SUPPORTED); |
ktownsend | 5:7635f81a8e09 | 45 | advData.addData(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, iBeaconPayload, 25); |
ktownsend | 5:7635f81a8e09 | 46 | |
ktownsend | 5:7635f81a8e09 | 47 | wait(2); |
ktownsend | 5:7635f81a8e09 | 48 | radio.reset(); |
ktownsend | 7:5e1f0d7f7c7d | 49 | radio.setAdvertising(advParams, advData, scanResponse); |
ktownsend | 5:7635f81a8e09 | 50 | radio.start(); |
ktownsend | 5:7635f81a8e09 | 51 | } |
ktownsend | 5:7635f81a8e09 | 52 | |
ktownsend | 0:ace2e8d3ce79 | 53 | int main() |
ktownsend | 0:ace2e8d3ce79 | 54 | { |
ktownsend | 3:46de446e82ed | 55 | wait(2); |
ktownsend | 5:7635f81a8e09 | 56 | startBeacon(); |
ktownsend | 2:ffc5216bd2cc | 57 | while(1); |
ktownsend | 2:ffc5216bd2cc | 58 | |
ktownsend | 0:ace2e8d3ce79 | 59 | /* Add the battery level characteristic to the battery service */ |
ktownsend | 0:ace2e8d3ce79 | 60 | /* Note: This will also update the characteristic's .index field */ |
ktownsend | 0:ace2e8d3ce79 | 61 | /* so that we know where it's stored in the BLEService.characteristics */ |
ktownsend | 0:ace2e8d3ce79 | 62 | /* array. */ |
ktownsend | 0:ace2e8d3ce79 | 63 | battService.addCharacteristic(battLevel); |
ktownsend | 0:ace2e8d3ce79 | 64 | |
ktownsend | 0:ace2e8d3ce79 | 65 | /* Add the heart rate and sensor location chars to the HRM service */ |
ktownsend | 0:ace2e8d3ce79 | 66 | hrmService.addCharacteristic(hrmRate); |
ktownsend | 0:ace2e8d3ce79 | 67 | hrmService.addCharacteristic(hrmLocation); |
ktownsend | 0:ace2e8d3ce79 | 68 | |
ktownsend | 0:ace2e8d3ce79 | 69 | /* Add the Health Thermometer server characteristics */ |
ktownsend | 0:ace2e8d3ce79 | 70 | thermService.addCharacteristic(thermTemp); |
ktownsend | 0:ace2e8d3ce79 | 71 | thermService.addCharacteristic(thermType); |
ktownsend | 0:ace2e8d3ce79 | 72 | thermService.addCharacteristic(thermInterval); |
ktownsend | 0:ace2e8d3ce79 | 73 | |
ktownsend | 0:ace2e8d3ce79 | 74 | /* Reset the BLE hardware to make sure we get a clean start */ |
ktownsend | 0:ace2e8d3ce79 | 75 | wait(2); |
ktownsend | 0:ace2e8d3ce79 | 76 | radio.reset(); |
ktownsend | 0:ace2e8d3ce79 | 77 | |
ktownsend | 0:ace2e8d3ce79 | 78 | /* Add the services to the radio HAL */ |
ktownsend | 0:ace2e8d3ce79 | 79 | radio.addService(battService); |
ktownsend | 0:ace2e8d3ce79 | 80 | radio.addService(hrmService); |
ktownsend | 0:ace2e8d3ce79 | 81 | radio.addService(thermService); |
ktownsend | 0:ace2e8d3ce79 | 82 | |
ktownsend | 0:ace2e8d3ce79 | 83 | /* Start the services so that we can start pushing data out */ |
ktownsend | 0:ace2e8d3ce79 | 84 | radio.start(); |
ktownsend | 0:ace2e8d3ce79 | 85 | |
ktownsend | 0:ace2e8d3ce79 | 86 | /* Set the heart rate monitor location (one time only) */ |
ktownsend | 0:ace2e8d3ce79 | 87 | /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.body_sensor_location.xml */ |
ktownsend | 0:ace2e8d3ce79 | 88 | uint8_t location = 0x01; /* Chest */ |
ktownsend | 2:ffc5216bd2cc | 89 | radio.writeCharacteristic(hrmService, hrmLocation, (uint8_t*)&location, sizeof(location)); |
ktownsend | 0:ace2e8d3ce79 | 90 | |
ktownsend | 0:ace2e8d3ce79 | 91 | /* Update the battery level */ |
ktownsend | 0:ace2e8d3ce79 | 92 | /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.battery_level.xml */ |
ktownsend | 0:ace2e8d3ce79 | 93 | uint8_t batt = 72; /* Percentage (0..100) */ |
ktownsend | 2:ffc5216bd2cc | 94 | radio.writeCharacteristic(battService, battLevel, (uint8_t*)&batt, sizeof(batt)); |
ktownsend | 0:ace2e8d3ce79 | 95 | |
ktownsend | 0:ace2e8d3ce79 | 96 | /* Update the fixed health thermometer characteristics */ |
ktownsend | 0:ace2e8d3ce79 | 97 | /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_type.xml */ |
ktownsend | 0:ace2e8d3ce79 | 98 | uint8_t thermLocation = 6; /* Location = mouth */ |
ktownsend | 2:ffc5216bd2cc | 99 | radio.writeCharacteristic(thermService, thermType, (uint8_t*)&thermLocation, sizeof(thermLocation)); |
ktownsend | 0:ace2e8d3ce79 | 100 | /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.measurement_interval.xml */ |
ktownsend | 0:ace2e8d3ce79 | 101 | uint16_t thermDelay = 5; |
ktownsend | 2:ffc5216bd2cc | 102 | radio.writeCharacteristic(thermService, thermInterval, (uint8_t*)&thermDelay, sizeof(thermDelay)); |
ktownsend | 0:ace2e8d3ce79 | 103 | |
ktownsend | 0:ace2e8d3ce79 | 104 | /* Blinky + value updates */ |
ktownsend | 0:ace2e8d3ce79 | 105 | uint8_t hrmCounter = 100; |
ktownsend | 0:ace2e8d3ce79 | 106 | |
ktownsend | 0:ace2e8d3ce79 | 107 | while(1) |
ktownsend | 0:ace2e8d3ce79 | 108 | { |
ktownsend | 0:ace2e8d3ce79 | 109 | myled = 1; |
ktownsend | 0:ace2e8d3ce79 | 110 | wait(0.1); |
ktownsend | 0:ace2e8d3ce79 | 111 | myled = 0; |
ktownsend | 0:ace2e8d3ce79 | 112 | wait(0.1); |
ktownsend | 0:ace2e8d3ce79 | 113 | |
ktownsend | 0:ace2e8d3ce79 | 114 | /* Update the HRM measurement */ |
ktownsend | 0:ace2e8d3ce79 | 115 | /* First byte = 8-bit values, no extra info, Second byte = uint8_t HRM value */ |
ktownsend | 0:ace2e8d3ce79 | 116 | /* See --> https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml */ |
ktownsend | 0:ace2e8d3ce79 | 117 | hrmCounter++; |
ktownsend | 0:ace2e8d3ce79 | 118 | if (hrmCounter == 175) hrmCounter = 100; |
ktownsend | 0:ace2e8d3ce79 | 119 | uint8_t bpm[2] = { 0x00, hrmCounter }; |
ktownsend | 2:ffc5216bd2cc | 120 | radio.writeCharacteristic(hrmService, hrmRate, bpm, 2); |
ktownsend | 0:ace2e8d3ce79 | 121 | |
ktownsend | 0:ace2e8d3ce79 | 122 | /* Update the Health Thermometer measurement */ |
ktownsend | 0:ace2e8d3ce79 | 123 | |
ktownsend | 0:ace2e8d3ce79 | 124 | // NOTE: This is an IEEE-11073 32-bit float NOT a IEEE-754 float (standard single precision float type) !!! |
ktownsend | 0:ace2e8d3ce79 | 125 | // See: Section 2.2 of https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=242961 |
ktownsend | 0:ace2e8d3ce79 | 126 | // Example: |
ktownsend | 0:ace2e8d3ce79 | 127 | // Consider a temperature measurement of 36.4 degrees Celsius with precision of 0.1 degrees Celsius. |
ktownsend | 0:ace2e8d3ce79 | 128 | // The FLOAT-Type representation is a 32-bit value consisting of an exponent of an 8-bit signed integer |
ktownsend | 0:ace2e8d3ce79 | 129 | // followed by a mantissa of a 24-bit signed integer; here, the exponent is -1 (0xFF) and the mantissa |
ktownsend | 0:ace2e8d3ce79 | 130 | // is 364 (0x00016C). Therefore, the FLOAT-Type representation of 36.4 is 0xFF00016C. |
ktownsend | 0:ace2e8d3ce79 | 131 | |
ktownsend | 0:ace2e8d3ce79 | 132 | uint8_t temperature[5] = { 0x00, 0x00, 0x00, 0x00, 0xFF }; |
ktownsend | 0:ace2e8d3ce79 | 133 | // Use the hrm counter to provide a shifting temperature value (175 = 17.5C, etc.) |
ktownsend | 0:ace2e8d3ce79 | 134 | memcpy (temperature+1, &hrmCounter, 1); |
ktownsend | 2:ffc5216bd2cc | 135 | radio.writeCharacteristic(thermService, thermTemp, temperature, 5); |
ktownsend | 0:ace2e8d3ce79 | 136 | } |
ktownsend | 0:ace2e8d3ce79 | 137 | } |