An example BLE Health Thermometer using the mbed BLE API and Nordic NRF51822
Dependencies: BLE_API_Native_blog TMP102 mbed
main.cpp@0:701da26ee5cb, 2014-02-23 (annotated)
- Committer:
- donalm
- Date:
- Sun Feb 23 12:51:28 2014 +0000
- Revision:
- 0:701da26ee5cb
- Child:
- 2:f11df1469db2
Ready.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
donalm | 0:701da26ee5cb | 1 | /* mbed Microcontroller Library |
donalm | 0:701da26ee5cb | 2 | * Copyright (c) 2006-2014 ARM Limited |
donalm | 0:701da26ee5cb | 3 | * |
donalm | 0:701da26ee5cb | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
donalm | 0:701da26ee5cb | 5 | * you may not use this file except in compliance with the License. |
donalm | 0:701da26ee5cb | 6 | * You may obtain a copy of the License at |
donalm | 0:701da26ee5cb | 7 | * |
donalm | 0:701da26ee5cb | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
donalm | 0:701da26ee5cb | 9 | * |
donalm | 0:701da26ee5cb | 10 | * Unless required by applicable law or agreed to in writing, software |
donalm | 0:701da26ee5cb | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
donalm | 0:701da26ee5cb | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
donalm | 0:701da26ee5cb | 13 | * See the License for the specific language governing permissions and |
donalm | 0:701da26ee5cb | 14 | * limitations under the License. |
donalm | 0:701da26ee5cb | 15 | */ |
donalm | 0:701da26ee5cb | 16 | |
donalm | 0:701da26ee5cb | 17 | #include "mbed.h" |
donalm | 0:701da26ee5cb | 18 | #include "TMP102.h" |
donalm | 0:701da26ee5cb | 19 | #include "nRF51822n.h" |
donalm | 0:701da26ee5cb | 20 | |
donalm | 0:701da26ee5cb | 21 | nRF51822n nrf; /* BLE radio driver */ |
donalm | 0:701da26ee5cb | 22 | TMP102 healthThemometer(p22, p20, 0x90); /* The TMP102 connected to our board */ |
donalm | 0:701da26ee5cb | 23 | |
donalm | 0:701da26ee5cb | 24 | /* LEDs and serial output for debug: */ |
donalm | 0:701da26ee5cb | 25 | DigitalOut led1(LED1); |
donalm | 0:701da26ee5cb | 26 | DigitalOut led2(LED2); |
donalm | 0:701da26ee5cb | 27 | Serial pc(USBTX,USBRX); |
donalm | 0:701da26ee5cb | 28 | |
donalm | 0:701da26ee5cb | 29 | |
donalm | 0:701da26ee5cb | 30 | /* Device Information service */ |
donalm | 0:701da26ee5cb | 31 | uint8_t manufacturerName[4] = { 'm', 'b', 'e', 'd' }; |
donalm | 0:701da26ee5cb | 32 | GattService deviceInformationService ( GattService::UUID_DEVICE_INFORMATION_SERVICE ); |
donalm | 0:701da26ee5cb | 33 | GattCharacteristic deviceManufacturer ( GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR, |
donalm | 0:701da26ee5cb | 34 | sizeof(manufacturerName), sizeof(manufacturerName), |
donalm | 0:701da26ee5cb | 35 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); |
donalm | 0:701da26ee5cb | 36 | |
donalm | 0:701da26ee5cb | 37 | /* Health Thermometer Service */ |
donalm | 0:701da26ee5cb | 38 | uint8_t thermTempPayload[5] = { 0, 0, 0, 0, 0 }; |
donalm | 0:701da26ee5cb | 39 | GattService thermService (GattService::UUID_HEALTH_THERMOMETER_SERVICE); |
donalm | 0:701da26ee5cb | 40 | GattCharacteristic thermTemp (GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, |
donalm | 0:701da26ee5cb | 41 | 5, 5, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE); |
donalm | 0:701da26ee5cb | 42 | |
donalm | 0:701da26ee5cb | 43 | /* Battery Level Service */ |
donalm | 0:701da26ee5cb | 44 | uint8_t batt = 100; /* Battery level */ |
donalm | 0:701da26ee5cb | 45 | uint8_t read_batt = 0; /* Variable to hold battery level reads */ |
donalm | 0:701da26ee5cb | 46 | GattService battService ( GattService::UUID_BATTERY_SERVICE ); |
donalm | 0:701da26ee5cb | 47 | GattCharacteristic battLevel ( GattCharacteristic::UUID_BATTERY_LEVEL_CHAR, 1, 1, |
donalm | 0:701da26ee5cb | 48 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | |
donalm | 0:701da26ee5cb | 49 | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ); |
donalm | 0:701da26ee5cb | 50 | |
donalm | 0:701da26ee5cb | 51 | |
donalm | 0:701da26ee5cb | 52 | /* Advertising data and parameters */ |
donalm | 0:701da26ee5cb | 53 | GapAdvertisingData advData; |
donalm | 0:701da26ee5cb | 54 | GapAdvertisingData scanResponse; |
donalm | 0:701da26ee5cb | 55 | GapAdvertisingParams advParams ( GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED ); |
donalm | 0:701da26ee5cb | 56 | uint16_t uuid16_list[] = {GattService::UUID_HEALTH_THERMOMETER_SERVICE, |
donalm | 0:701da26ee5cb | 57 | GattService::UUID_BATTERY_SERVICE}; |
donalm | 0:701da26ee5cb | 58 | |
donalm | 0:701da26ee5cb | 59 | uint32_t quick_ieee11073_from_float(float temperature); |
donalm | 0:701da26ee5cb | 60 | void updateServiceValues(void); |
donalm | 0:701da26ee5cb | 61 | |
donalm | 0:701da26ee5cb | 62 | /**************************************************************************/ |
donalm | 0:701da26ee5cb | 63 | /*! |
donalm | 0:701da26ee5cb | 64 | @brief This custom class can be used to override any GapEvents |
donalm | 0:701da26ee5cb | 65 | that you are interested in handling on an application level. |
donalm | 0:701da26ee5cb | 66 | */ |
donalm | 0:701da26ee5cb | 67 | /**************************************************************************/ |
donalm | 0:701da26ee5cb | 68 | class GapEventHandler : public GapEvents |
donalm | 0:701da26ee5cb | 69 | { |
donalm | 0:701da26ee5cb | 70 | virtual void onTimeout(void) |
donalm | 0:701da26ee5cb | 71 | { |
donalm | 0:701da26ee5cb | 72 | pc.printf("Advertising Timeout!\n\r"); |
donalm | 0:701da26ee5cb | 73 | // Restart the advertising process with a much slower interval, |
donalm | 0:701da26ee5cb | 74 | // only start advertising again after a button press, etc. |
donalm | 0:701da26ee5cb | 75 | } |
donalm | 0:701da26ee5cb | 76 | |
donalm | 0:701da26ee5cb | 77 | virtual void onConnected(void) |
donalm | 0:701da26ee5cb | 78 | { |
donalm | 0:701da26ee5cb | 79 | pc.printf("Connected!\n\r"); |
donalm | 0:701da26ee5cb | 80 | } |
donalm | 0:701da26ee5cb | 81 | |
donalm | 0:701da26ee5cb | 82 | virtual void onDisconnected(void) |
donalm | 0:701da26ee5cb | 83 | { |
donalm | 0:701da26ee5cb | 84 | pc.printf("Disconnected!\n\r"); |
donalm | 0:701da26ee5cb | 85 | pc.printf("Restarting the advertising process\n\r"); |
donalm | 0:701da26ee5cb | 86 | nrf.getGap().startAdvertising(advParams); |
donalm | 0:701da26ee5cb | 87 | } |
donalm | 0:701da26ee5cb | 88 | }; |
donalm | 0:701da26ee5cb | 89 | |
donalm | 0:701da26ee5cb | 90 | /**************************************************************************/ |
donalm | 0:701da26ee5cb | 91 | /*! |
donalm | 0:701da26ee5cb | 92 | @brief This custom class can be used to override any GattServerEvents |
donalm | 0:701da26ee5cb | 93 | that you are interested in handling on an application level. |
donalm | 0:701da26ee5cb | 94 | */ |
donalm | 0:701da26ee5cb | 95 | /**************************************************************************/ |
donalm | 0:701da26ee5cb | 96 | class GattServerEventHandler : public GattServerEvents |
donalm | 0:701da26ee5cb | 97 | { |
donalm | 0:701da26ee5cb | 98 | //virtual void onDataSent(void) {} |
donalm | 0:701da26ee5cb | 99 | //virtual void onDataWritten(void) {} |
donalm | 0:701da26ee5cb | 100 | |
donalm | 0:701da26ee5cb | 101 | virtual void onUpdatesEnabled(uint16_t charHandle) |
donalm | 0:701da26ee5cb | 102 | { |
donalm | 0:701da26ee5cb | 103 | if (charHandle == thermTemp.handle) |
donalm | 0:701da26ee5cb | 104 | { |
donalm | 0:701da26ee5cb | 105 | pc.printf("Temperature indication enabled\n\r"); |
donalm | 0:701da26ee5cb | 106 | } |
donalm | 0:701da26ee5cb | 107 | } |
donalm | 0:701da26ee5cb | 108 | |
donalm | 0:701da26ee5cb | 109 | virtual void onUpdatesDisabled(uint16_t charHandle) |
donalm | 0:701da26ee5cb | 110 | { |
donalm | 0:701da26ee5cb | 111 | if (charHandle == thermTemp.handle) |
donalm | 0:701da26ee5cb | 112 | { |
donalm | 0:701da26ee5cb | 113 | pc.printf("Temperature indication disabled\n\r"); |
donalm | 0:701da26ee5cb | 114 | } |
donalm | 0:701da26ee5cb | 115 | } |
donalm | 0:701da26ee5cb | 116 | |
donalm | 0:701da26ee5cb | 117 | virtual void onConfirmationReceived(uint16_t charHandle) |
donalm | 0:701da26ee5cb | 118 | { |
donalm | 0:701da26ee5cb | 119 | if (charHandle == thermTemp.handle) |
donalm | 0:701da26ee5cb | 120 | { |
donalm | 0:701da26ee5cb | 121 | pc.printf("Temperature indication received\n\r"); |
donalm | 0:701da26ee5cb | 122 | } |
donalm | 0:701da26ee5cb | 123 | } |
donalm | 0:701da26ee5cb | 124 | }; |
donalm | 0:701da26ee5cb | 125 | |
donalm | 0:701da26ee5cb | 126 | /**************************************************************************/ |
donalm | 0:701da26ee5cb | 127 | /*! |
donalm | 0:701da26ee5cb | 128 | @brief Program entry point |
donalm | 0:701da26ee5cb | 129 | */ |
donalm | 0:701da26ee5cb | 130 | /**************************************************************************/ |
donalm | 0:701da26ee5cb | 131 | int main(void) |
donalm | 0:701da26ee5cb | 132 | { |
donalm | 0:701da26ee5cb | 133 | pc.baud(115200); |
donalm | 0:701da26ee5cb | 134 | |
donalm | 0:701da26ee5cb | 135 | /* Setup blinky: led1 is toggled in main, led2 is toggled via Ticker */ |
donalm | 0:701da26ee5cb | 136 | led1=1; |
donalm | 0:701da26ee5cb | 137 | led2=0; |
donalm | 0:701da26ee5cb | 138 | |
donalm | 0:701da26ee5cb | 139 | /* Setup the local GAP/GATT event handlers */ |
donalm | 0:701da26ee5cb | 140 | nrf.getGap().setEventHandler(new GapEventHandler()); |
donalm | 0:701da26ee5cb | 141 | nrf.getGattServer().setEventHandler(new GattServerEventHandler()); |
donalm | 0:701da26ee5cb | 142 | |
donalm | 0:701da26ee5cb | 143 | /* Initialise the nRF51822 */ |
donalm | 0:701da26ee5cb | 144 | pc.printf("Initialising the nRF51822\n\r"); |
donalm | 0:701da26ee5cb | 145 | nrf.init(); |
donalm | 0:701da26ee5cb | 146 | |
donalm | 0:701da26ee5cb | 147 | /* Make sure we get a clean start */ |
donalm | 0:701da26ee5cb | 148 | nrf.reset(); |
donalm | 0:701da26ee5cb | 149 | |
donalm | 0:701da26ee5cb | 150 | /* Add BLE-Only flag and complete service list to the advertising data */ |
donalm | 0:701da26ee5cb | 151 | advData.addFlags(GapAdvertisingData::BREDR_NOT_SUPPORTED); |
donalm | 0:701da26ee5cb | 152 | advData.addData(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, |
donalm | 0:701da26ee5cb | 153 | (uint8_t*)uuid16_list, sizeof(uuid16_list)); |
donalm | 0:701da26ee5cb | 154 | advData.addAppearance(GapAdvertisingData::GENERIC_THERMOMETER); |
donalm | 0:701da26ee5cb | 155 | nrf.getGap().setAdvertisingData(advData, scanResponse); |
donalm | 0:701da26ee5cb | 156 | |
donalm | 0:701da26ee5cb | 157 | /* Health Thermometer Service */ |
donalm | 0:701da26ee5cb | 158 | thermService.addCharacteristic(thermTemp); |
donalm | 0:701da26ee5cb | 159 | nrf.getGattServer().addService(thermService); |
donalm | 0:701da26ee5cb | 160 | |
donalm | 0:701da26ee5cb | 161 | /* Add the Battery Level service */ |
donalm | 0:701da26ee5cb | 162 | battService.addCharacteristic(battLevel); |
donalm | 0:701da26ee5cb | 163 | nrf.getGattServer().addService(battService); |
donalm | 0:701da26ee5cb | 164 | |
donalm | 0:701da26ee5cb | 165 | /* Start advertising (make sure you've added all your data first) */ |
donalm | 0:701da26ee5cb | 166 | nrf.getGap().startAdvertising(advParams); |
donalm | 0:701da26ee5cb | 167 | |
donalm | 0:701da26ee5cb | 168 | /* Now that we're live, update the battery level characteristic, and */ |
donalm | 0:701da26ee5cb | 169 | /* change the device manufacturer characteristic to 'mbed' */ |
donalm | 0:701da26ee5cb | 170 | nrf.getGattServer().updateValue(battLevel.handle, (uint8_t*)&batt, sizeof(batt)); |
donalm | 0:701da26ee5cb | 171 | nrf.getGattServer().updateValue(deviceManufacturer.handle, manufacturerName, sizeof(manufacturerName)); |
donalm | 0:701da26ee5cb | 172 | nrf.getGattServer().updateValue(thermTemp.handle, thermTempPayload, sizeof(thermTempPayload)); |
donalm | 0:701da26ee5cb | 173 | |
donalm | 0:701da26ee5cb | 174 | |
donalm | 0:701da26ee5cb | 175 | for (;;) |
donalm | 0:701da26ee5cb | 176 | { |
donalm | 0:701da26ee5cb | 177 | wait(1); |
donalm | 0:701da26ee5cb | 178 | updateServiceValues(); |
donalm | 0:701da26ee5cb | 179 | } |
donalm | 0:701da26ee5cb | 180 | } |
donalm | 0:701da26ee5cb | 181 | |
donalm | 0:701da26ee5cb | 182 | /**************************************************************************/ |
donalm | 0:701da26ee5cb | 183 | /*! |
donalm | 0:701da26ee5cb | 184 | @brief Ticker callback to switch led2 state |
donalm | 0:701da26ee5cb | 185 | */ |
donalm | 0:701da26ee5cb | 186 | /**************************************************************************/ |
donalm | 0:701da26ee5cb | 187 | void updateServiceValues(void) |
donalm | 0:701da26ee5cb | 188 | { |
donalm | 0:701da26ee5cb | 189 | /* Toggle the LEDs */ |
donalm | 0:701da26ee5cb | 190 | led1 = !led1; |
donalm | 0:701da26ee5cb | 191 | led2 = !led2; |
donalm | 0:701da26ee5cb | 192 | |
donalm | 0:701da26ee5cb | 193 | /* Update battery level */ |
donalm | 0:701da26ee5cb | 194 | nrf.getGattServer().updateValue(battLevel.handle, (uint8_t*)&batt, sizeof(batt)); |
donalm | 0:701da26ee5cb | 195 | |
donalm | 0:701da26ee5cb | 196 | /* Update the temperature */ |
donalm | 0:701da26ee5cb | 197 | float temperature = healthThemometer.read(); |
donalm | 0:701da26ee5cb | 198 | uint32_t temp_ieee11073 = quick_ieee11073_from_float(temperature); |
donalm | 0:701da26ee5cb | 199 | memcpy(thermTempPayload+1, &temp_ieee11073, 4); |
donalm | 0:701da26ee5cb | 200 | nrf.getGattServer().updateValue(thermTemp.handle, thermTempPayload, sizeof(thermTempPayload)); |
donalm | 0:701da26ee5cb | 201 | printf("Temperature: %f Celsius\r\n", temperature); |
donalm | 0:701da26ee5cb | 202 | } |
donalm | 0:701da26ee5cb | 203 | |
donalm | 0:701da26ee5cb | 204 | /** |
donalm | 0:701da26ee5cb | 205 | * @brief A very quick conversion between a float temperature and 11073-20601 FLOAT-Type. |
donalm | 0:701da26ee5cb | 206 | * @param temperature The temperature as a float. |
donalm | 0:701da26ee5cb | 207 | * @return The temperature in 11073-20601 FLOAT-Type format. |
donalm | 0:701da26ee5cb | 208 | */ |
donalm | 0:701da26ee5cb | 209 | uint32_t quick_ieee11073_from_float(float temperature) |
donalm | 0:701da26ee5cb | 210 | { |
donalm | 0:701da26ee5cb | 211 | uint8_t exponent = 0xFF; //exponent is -1 |
donalm | 0:701da26ee5cb | 212 | uint32_t mantissa = (uint32_t)(temperature*10); |
donalm | 0:701da26ee5cb | 213 | |
donalm | 0:701da26ee5cb | 214 | return ( ((uint32_t)exponent) << 24) | mantissa; |
donalm | 0:701da26ee5cb | 215 | } |