iTracker mbed os sample to show how to user the BLE API to expose sensor values (float and ints)

Committer:
knaresh89
Date:
Mon Feb 12 06:41:24 2018 +0000
Revision:
0:e4fe77192b73
iTracker mbed os sample to show how to user the BLE API to expose sensor values (float and ints)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
knaresh89 0:e4fe77192b73 1 #include "mbed.h"
knaresh89 0:e4fe77192b73 2 #include "ble/BLE.h"
knaresh89 0:e4fe77192b73 3 #include "SEGGER_RTT.h"
knaresh89 0:e4fe77192b73 4 #include "BME280_SPI.h"
knaresh89 0:e4fe77192b73 5
knaresh89 0:e4fe77192b73 6 //For float values make sure you create a wrapper class to handle the exponent and mantissa properly
knaresh89 0:e4fe77192b73 7 struct ValueBytes {
knaresh89 0:e4fe77192b73 8 static const unsigned OFFSET_OF_FLAGS = 0;
knaresh89 0:e4fe77192b73 9 static const unsigned OFFSET_OF_VALUE = OFFSET_OF_FLAGS + sizeof(uint8_t);
knaresh89 0:e4fe77192b73 10 static const unsigned SIZEOF_VALUE_BYTES = sizeof(uint8_t) + sizeof(float);
knaresh89 0:e4fe77192b73 11
knaresh89 0:e4fe77192b73 12 static const unsigned UNITS_FLAG_POS = 0;
knaresh89 0:e4fe77192b73 13 static const unsigned TIMESTAMP_FLAG_POS = 1;
knaresh89 0:e4fe77192b73 14 static const unsigned TYPE_FLAG_POS = 2;
knaresh89 0:e4fe77192b73 15
knaresh89 0:e4fe77192b73 16 static const uint8_t UNITS_UNIT1 = 0; //add as many possible units that the value byte can hold
knaresh89 0:e4fe77192b73 17 static const uint8_t UNITS_UNIT2 = 1;
knaresh89 0:e4fe77192b73 18
knaresh89 0:e4fe77192b73 19 ValueBytes(float initialValue) : bytes() {
knaresh89 0:e4fe77192b73 20 /* Assumption: values are expressed in some units of mesurement */
knaresh89 0:e4fe77192b73 21 bytes[OFFSET_OF_FLAGS] = (UNITS_UNIT1 << UNITS_FLAG_POS) |
knaresh89 0:e4fe77192b73 22 (false << TIMESTAMP_FLAG_POS) |
knaresh89 0:e4fe77192b73 23 (false << TYPE_FLAG_POS);
knaresh89 0:e4fe77192b73 24 updateValue(initialValue);
knaresh89 0:e4fe77192b73 25 }
knaresh89 0:e4fe77192b73 26
knaresh89 0:e4fe77192b73 27 void updateValue(float temp) {
knaresh89 0:e4fe77192b73 28 uint32_t temp_ieee11073 = quick_ieee11073_from_float(temp);
knaresh89 0:e4fe77192b73 29 memcpy(&bytes[OFFSET_OF_VALUE], &temp_ieee11073, sizeof(float));
knaresh89 0:e4fe77192b73 30 }
knaresh89 0:e4fe77192b73 31
knaresh89 0:e4fe77192b73 32 uint8_t *getPointer(void) {
knaresh89 0:e4fe77192b73 33 return bytes;
knaresh89 0:e4fe77192b73 34 }
knaresh89 0:e4fe77192b73 35
knaresh89 0:e4fe77192b73 36 const uint8_t *getPointer(void) const {
knaresh89 0:e4fe77192b73 37 return bytes;
knaresh89 0:e4fe77192b73 38 }
knaresh89 0:e4fe77192b73 39
knaresh89 0:e4fe77192b73 40 private:
knaresh89 0:e4fe77192b73 41 /**
knaresh89 0:e4fe77192b73 42 * @brief A very quick conversion between a float vale and 11073-20601 FLOAT-Type.
knaresh89 0:e4fe77192b73 43 * @param value The sensor value as a float.
knaresh89 0:e4fe77192b73 44 * @return The value in 11073-20601 FLOAT-Type format.
knaresh89 0:e4fe77192b73 45 */
knaresh89 0:e4fe77192b73 46 uint32_t quick_ieee11073_from_float(float value) {
knaresh89 0:e4fe77192b73 47 uint8_t exponent = 0xFE; //Exponent is -2
knaresh89 0:e4fe77192b73 48 uint32_t mantissa = (uint32_t)(value * 100);
knaresh89 0:e4fe77192b73 49
knaresh89 0:e4fe77192b73 50 return (((uint32_t)exponent) << 24) | mantissa;
knaresh89 0:e4fe77192b73 51 }
knaresh89 0:e4fe77192b73 52
knaresh89 0:e4fe77192b73 53 private:
knaresh89 0:e4fe77192b73 54 /* First byte: 8-bit flags. Second field is a float holding the value. */
knaresh89 0:e4fe77192b73 55 /* See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml */
knaresh89 0:e4fe77192b73 56 uint8_t bytes[SIZEOF_VALUE_BYTES];
knaresh89 0:e4fe77192b73 57 };
knaresh89 0:e4fe77192b73 58
knaresh89 0:e4fe77192b73 59 ValueBytes valueBytes(0.0f);
knaresh89 0:e4fe77192b73 60 ReadOnlyGattCharacteristic<ValueBytes> tempMeasurement(GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, (ValueBytes *)valueBytes.getPointer(), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); //characteristics that can be used to store a float value
knaresh89 0:e4fe77192b73 61
knaresh89 0:e4fe77192b73 62 /**Function to update the BLE characteristics value that holds a float value
knaresh89 0:e4fe77192b73 63 * @param value the float value to update
knaresh89 0:e4fe77192b73 64 */
knaresh89 0:e4fe77192b73 65 void updateCharacteristic(float value)
knaresh89 0:e4fe77192b73 66 {
knaresh89 0:e4fe77192b73 67 if (BLE::Instance(BLE::DEFAULT_INSTANCE).getGapState().connected) {
knaresh89 0:e4fe77192b73 68 valueBytes.updateValue(value);
knaresh89 0:e4fe77192b73 69 BLE::Instance(BLE::DEFAULT_INSTANCE).gattServer().write(tempMeasurement.getValueHandle(), valueBytes.getPointer(), sizeof(ValueBytes));
knaresh89 0:e4fe77192b73 70 }
knaresh89 0:e4fe77192b73 71 }
knaresh89 0:e4fe77192b73 72
knaresh89 0:e4fe77192b73 73
knaresh89 0:e4fe77192b73 74
knaresh89 0:e4fe77192b73 75
knaresh89 0:e4fe77192b73 76 DigitalOut led(LED1, 1);
knaresh89 0:e4fe77192b73 77 uint16_t customServiceUUID = 0xA000;
knaresh89 0:e4fe77192b73 78 uint16_t readCharUUID = 0xA001;
knaresh89 0:e4fe77192b73 79 uint16_t writeCharUUID = 0xA002;
knaresh89 0:e4fe77192b73 80
knaresh89 0:e4fe77192b73 81 const static char DEVICE_NAME[] = "iTracker"; // change this
knaresh89 0:e4fe77192b73 82 static const uint16_t uuid16_list[] = {0xFFFF}; //Custom UUID, FFFF is reserved for development
knaresh89 0:e4fe77192b73 83
knaresh89 0:e4fe77192b73 84
knaresh89 0:e4fe77192b73 85 /* Set Up custom Characteristics */
knaresh89 0:e4fe77192b73 86 static uint8_t readValue[10] = {0};
knaresh89 0:e4fe77192b73 87 ReadOnlyArrayGattCharacteristic<uint8_t, sizeof(readValue)> readChar(readCharUUID, readValue);
knaresh89 0:e4fe77192b73 88
knaresh89 0:e4fe77192b73 89 static uint8_t writeValue[10] = {0};
knaresh89 0:e4fe77192b73 90 WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(writeValue)> writeChar(writeCharUUID, writeValue);
knaresh89 0:e4fe77192b73 91
knaresh89 0:e4fe77192b73 92 /* Set up custom service */
knaresh89 0:e4fe77192b73 93 GattCharacteristic *characteristics[] = {&readChar, &writeChar};
knaresh89 0:e4fe77192b73 94 GattService customService(customServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
knaresh89 0:e4fe77192b73 95
knaresh89 0:e4fe77192b73 96
knaresh89 0:e4fe77192b73 97 /*
knaresh89 0:e4fe77192b73 98 * Restart advertising when phone app disconnects
knaresh89 0:e4fe77192b73 99 */
knaresh89 0:e4fe77192b73 100 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *)
knaresh89 0:e4fe77192b73 101 {
knaresh89 0:e4fe77192b73 102 BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising();
knaresh89 0:e4fe77192b73 103 }
knaresh89 0:e4fe77192b73 104
knaresh89 0:e4fe77192b73 105 /*
knaresh89 0:e4fe77192b73 106 * Handle writes to writeCharacteristic
knaresh89 0:e4fe77192b73 107 */
knaresh89 0:e4fe77192b73 108 void writeCharCallback(const GattWriteCallbackParams *params)
knaresh89 0:e4fe77192b73 109 {
knaresh89 0:e4fe77192b73 110 /* Check to see what characteristic was written, by handle */
knaresh89 0:e4fe77192b73 111 if(params->handle == writeChar.getValueHandle()) {
knaresh89 0:e4fe77192b73 112 /* toggle LED if only 1 byte is written */
knaresh89 0:e4fe77192b73 113 if(params->len == 1) {
knaresh89 0:e4fe77192b73 114 //led = params->data[0];
knaresh89 0:e4fe77192b73 115 (params->data[0] == 0x00) ? SEGGER_RTT_printf(0, "led on\n\r") : SEGGER_RTT_printf(0, "led off\n\r"); // print led toggle
knaresh89 0:e4fe77192b73 116 }
knaresh89 0:e4fe77192b73 117 /* Print the data if more than 1 byte is written */
knaresh89 0:e4fe77192b73 118 else {
knaresh89 0:e4fe77192b73 119 SEGGER_RTT_printf(0, "Data received: length = %d, data = 0x",params->len);
knaresh89 0:e4fe77192b73 120 for(int x=0; x < params->len; x++) {
knaresh89 0:e4fe77192b73 121 SEGGER_RTT_printf(0, "%x", params->data[x]);
knaresh89 0:e4fe77192b73 122 }
knaresh89 0:e4fe77192b73 123 SEGGER_RTT_printf(0, "\n\r");
knaresh89 0:e4fe77192b73 124 }
knaresh89 0:e4fe77192b73 125 /* Update the readChar with the value of writeChar */
knaresh89 0:e4fe77192b73 126 BLE::Instance(BLE::DEFAULT_INSTANCE).gattServer().write(readChar.getValueHandle(), params->data, params->len);
knaresh89 0:e4fe77192b73 127 }
knaresh89 0:e4fe77192b73 128 }
knaresh89 0:e4fe77192b73 129 /*
knaresh89 0:e4fe77192b73 130 * Initialization callback
knaresh89 0:e4fe77192b73 131 */
knaresh89 0:e4fe77192b73 132 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
knaresh89 0:e4fe77192b73 133 {
knaresh89 0:e4fe77192b73 134 BLE &ble = params->ble;
knaresh89 0:e4fe77192b73 135 ble_error_t error = params->error;
knaresh89 0:e4fe77192b73 136
knaresh89 0:e4fe77192b73 137 if (error != BLE_ERROR_NONE) {
knaresh89 0:e4fe77192b73 138 return;
knaresh89 0:e4fe77192b73 139 }
knaresh89 0:e4fe77192b73 140
knaresh89 0:e4fe77192b73 141 ble.gap().onDisconnection(disconnectionCallback);
knaresh89 0:e4fe77192b73 142 ble.gattServer().onDataWritten(writeCharCallback);
knaresh89 0:e4fe77192b73 143
knaresh89 0:e4fe77192b73 144 /* Setup advertising */
knaresh89 0:e4fe77192b73 145 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); // BLE only, no classic BT
knaresh89 0:e4fe77192b73 146 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); // advertising type
knaresh89 0:e4fe77192b73 147 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); // add name
knaresh89 0:e4fe77192b73 148 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // UUID's broadcast in advertising packet
knaresh89 0:e4fe77192b73 149 ble.gap().setAdvertisingInterval(100); // 100ms.
knaresh89 0:e4fe77192b73 150
knaresh89 0:e4fe77192b73 151 /* Add our custom service */
knaresh89 0:e4fe77192b73 152 ble.addService(customService);
knaresh89 0:e4fe77192b73 153
knaresh89 0:e4fe77192b73 154 /* Start advertising */
knaresh89 0:e4fe77192b73 155 ble.gap().startAdvertising();
knaresh89 0:e4fe77192b73 156 }
knaresh89 0:e4fe77192b73 157
knaresh89 0:e4fe77192b73 158 /*
knaresh89 0:e4fe77192b73 159 * Main loop
knaresh89 0:e4fe77192b73 160 */
knaresh89 0:e4fe77192b73 161 int main(void)
knaresh89 0:e4fe77192b73 162 {
knaresh89 0:e4fe77192b73 163 /* initialize stuff */
knaresh89 0:e4fe77192b73 164 SEGGER_RTT_printf(0, "\n\r********* Starting Main Loop *********\n\r");
knaresh89 0:e4fe77192b73 165
knaresh89 0:e4fe77192b73 166 BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
knaresh89 0:e4fe77192b73 167 ble.init(bleInitComplete);
knaresh89 0:e4fe77192b73 168
knaresh89 0:e4fe77192b73 169 /* SpinWait for initialization to complete. This is necessary because the
knaresh89 0:e4fe77192b73 170 * BLE object is used in the main loop below. */
knaresh89 0:e4fe77192b73 171 while (ble.hasInitialized() == false) {
knaresh89 0:e4fe77192b73 172 /* spin loop */
knaresh89 0:e4fe77192b73 173 }
knaresh89 0:e4fe77192b73 174
knaresh89 0:e4fe77192b73 175 BME280_SPI sensor(p3, p5, p4, p2); // mosi, miso, sclk, cs
knaresh89 0:e4fe77192b73 176
knaresh89 0:e4fe77192b73 177 /*while (true) {
knaresh89 0:e4fe77192b73 178 SEGGER_RTT_printf(0, "%2.2f degC, %04.2f hPa, %2.2f %%\n", sensor.getTemperature(), sensor.getPressure(), sensor.getHumidity());
knaresh89 0:e4fe77192b73 179 wait(5.0);
knaresh89 0:e4fe77192b73 180 }*/
knaresh89 0:e4fe77192b73 181
knaresh89 0:e4fe77192b73 182 /* Infinite loop waiting for BLE interrupt events */
knaresh89 0:e4fe77192b73 183 while (true) {
knaresh89 0:e4fe77192b73 184 ble.waitForEvent(); /* Save power */
knaresh89 0:e4fe77192b73 185 }
knaresh89 0:e4fe77192b73 186 }
knaresh89 0:e4fe77192b73 187
knaresh89 0:e4fe77192b73 188