{"componentChunkName":"component---src-templates-blog-post-js","path":"/posts/stm32discovery_7/","result":{"data":{"markdownRemark":{"html":"<p>After much trial and error, and looking through the mbed example \"mbed-os-example-ble-Thermometer\" (which you can pick up from ide.mbed.com by creating a new project from template), I was able to get the STM32 Discovery to output two services: an LED Service, which allows control over its LED (on/off), and a Sensor Service which reads the onboard temperature sensor and outputs the value onto the service, which can be read with the Lightblue app.</p>\n<p>The commit hash to check out is: b3a3e2050ad0cde59e4832fbfe94192c8bb75ef3 on the <code>stm32_discovery_mbed</code> project, but some of the highlights:</p>\n<ol>\n<li>Tell the mbed-os event queue to read the sensor every 500ms</li>\n<li>When the BLE service is read, update the temperature through the sensorServicePointer</li>\n<li>Use the template to modify the generic attribute profile in the class: see below</li>\n</ol>\n<pre><code>class SensorService {\npublic:\n    const static uint16_t SENSOR_SERVICE_UUID              = 0xB000;\n    const static uint16_t SENSOR_STATE_CHARACTERISTIC_UUID = 0xB001;\n\n    // Constructor. Colon means there is an initializer list before running constructor\n    SensorService(BLEDevice &#x26;_ble, float initialValueForSensorCharacteristic) :\n        ble(_ble), \n        valueBytes(initialValueForSensorCharacteristic), \n        tempMeasurement(SENSOR_STATE_CHARACTERISTIC_UUID, (TemperatureValueBytes *)valueBytes.getPointer(), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)\n    {\n        GattCharacteristic *charTable[] = {&#x26;tempMeasurement};\n        GattService         sensorService(SENSOR_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));\n        ble.addService(sensorService);\n    }\n\n    GattAttribute::Handle_t getValueHandle() const\n    {\n        return tempMeasurement.getValueHandle();\n    }\n\n    void updateTemperature(float temperature) {\n        if (ble.getGapState().connected) {\n            valueBytes.updateTemperature(temperature);\n            ble.gattServer().write(tempMeasurement.getValueHandle(), valueBytes.getPointer(), sizeof(TemperatureValueBytes));\n        }\n    }\n\nprivate:\n    \n    /* Private internal representation for the bytes used to work with the vaulue of the temperature characteristic. \n     * Copied over from project \"mbed-os-example-ble-Thermometer\"\n    */\n    struct TemperatureValueBytes {\n        static const unsigned OFFSET_OF_FLAGS    = 0;\n        static const unsigned OFFSET_OF_VALUE    = OFFSET_OF_FLAGS + sizeof(uint8_t);\n        static const unsigned SIZEOF_VALUE_BYTES = sizeof(uint8_t) + sizeof(float);\n\n        static const unsigned TEMPERATURE_UNITS_FLAG_POS = 0;\n        static const unsigned TIMESTAMP_FLAG_POS         = 1;\n        static const unsigned TEMPERATURE_TYPE_FLAG_POS  = 2;\n\n        static const uint8_t  TEMPERATURE_UNITS_CELSIUS    = 0;\n        static const uint8_t  TEMPERATURE_UNITS_FAHRENHEIT = 1;\n\n        TemperatureValueBytes(float initialTemperature) : bytes() {\n            /* Assumption: temperature values are expressed in celsius */\n            bytes[OFFSET_OF_FLAGS] =  (TEMPERATURE_UNITS_CELSIUS &#x3C;&#x3C; TEMPERATURE_UNITS_FLAG_POS) |\n                                      (false &#x3C;&#x3C; TIMESTAMP_FLAG_POS) |\n                                      (false &#x3C;&#x3C; TEMPERATURE_TYPE_FLAG_POS);\n            updateTemperature(initialTemperature);\n        }\n\n        void updateTemperature(float temp) {\n            uint32_t temp_ieee11073 = quick_ieee11073_from_float(temp);\n            memcpy(&#x26;bytes[OFFSET_OF_VALUE], &#x26;temp_ieee11073, sizeof(float));\n            memcpy(&#x26;bytes[OFFSET_OF_VALUE], &#x26;temp, sizeof(float));\n        }\n\n        uint8_t       *getPointer(void) {\n            return bytes;\n        }\n\n        const uint8_t *getPointer(void) const {\n            return bytes;\n        }\n\nprivate:\n        /**\n         * @brief A very quick conversion between a float temperature and 11073-20601 FLOAT-Type.\n         * @param temperature The temperature as a float.\n         * @return The temperature in 11073-20601 FLOAT-Type format.\n         */\n        uint32_t quick_ieee11073_from_float(float temperature) {\n            uint8_t  exponent = 0xFE; //Exponent is -2\n            uint32_t mantissa = (uint32_t)(temperature * 100);\n\n            return (((uint32_t)exponent) &#x3C;&#x3C; 24) | mantissa;\n        }\n\n        /* First byte: 8-bit flags. Second field is a float holding the temperature value. */\n        /* See https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.temperature_measurement.xml */\n        uint8_t bytes[SIZEOF_VALUE_BYTES];\n    };\n\nprotected:\n    BLE                         &#x26;ble;\n    TemperatureValueBytes           valueBytes;\n    ReadOnlyGattCharacteristic&#x3C;TemperatureValueBytes>  tempMeasurement;\n};\n</code></pre>\n<p>Another note: the code right now displays the data in little-endian format, so using this link (<a href=\"https://gregstoll.com/~gregstoll/floattohex/\">https://gregstoll.com/~gregstoll/floattohex/</a>) to convert the hex value that is visible on the Lightblue app requires you to check \"Swap Endianess\".</p>\n<p>Next Steps: </p>\n<ul>\n<li>Convert to newer version of Mbed-OS</li>\n<li>Add more sensor services over BLE</li>\n</ul>","frontmatter":{"title":"B-L475E-IOT01A - Temperature Sensor Reading over BLE"}}},"pageContext":{"slug":"/posts/stm32discovery_7/"}},"staticQueryHashes":["3649515864"]}