Fedor Chervyakov / Mbed OS bme280-ble-sensor
Committer:
Fedor Chervyakov
Date:
Sat Sep 07 01:23:44 2019 +0300
Revision:
3:ab403ff774aa
Parent:
2:45ed62566694
Add Gatt server for the Environmental service

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Fedor Chervyakov 2:45ed62566694 1 /* BME280 BLE sensor -- main.cpp
Fedor Chervyakov 1:667b9825e7ee 2 *
Fedor Chervyakov 1:667b9825e7ee 3 * Licensed under the Apache License, Version 2.0 (the "License");
Fedor Chervyakov 1:667b9825e7ee 4 * you may not use this file except in compliance with the License.
Fedor Chervyakov 1:667b9825e7ee 5 * You may obtain a copy of the License at
Fedor Chervyakov 1:667b9825e7ee 6 *
Fedor Chervyakov 1:667b9825e7ee 7 * http://www.apache.org/licenses/LICENSE-2.0
Fedor Chervyakov 1:667b9825e7ee 8 *
Fedor Chervyakov 1:667b9825e7ee 9 * Unless required by applicable law or agreed to in writing, software
Fedor Chervyakov 1:667b9825e7ee 10 * distributed under the License is distributed on an "AS IS" BASIS,
Fedor Chervyakov 1:667b9825e7ee 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Fedor Chervyakov 1:667b9825e7ee 12 * See the License for the specific language governing permissions and
Fedor Chervyakov 1:667b9825e7ee 13 * limitations under the License.
Fedor Chervyakov 1:667b9825e7ee 14 *
Fedor Chervyakov 1:667b9825e7ee 15 * Copyright 2019 Fedor Chervyakov
Fedor Chervyakov 1:667b9825e7ee 16 */
fedorc 0:22a4f6c99d74 17
fedorc 0:22a4f6c99d74 18 #include "mbed.h"
Fedor Chervyakov 2:45ed62566694 19
Fedor Chervyakov 2:45ed62566694 20 #include <stdio.h>
Fedor Chervyakov 2:45ed62566694 21
Fedor Chervyakov 2:45ed62566694 22 #include "events/EventQueue.h"
Fedor Chervyakov 2:45ed62566694 23 #include "platform/Callback.h"
Fedor Chervyakov 2:45ed62566694 24 #include "platform/NonCopyable.h"
Fedor Chervyakov 2:45ed62566694 25
Fedor Chervyakov 2:45ed62566694 26 #include "ble/BLE.h"
Fedor Chervyakov 2:45ed62566694 27 #include "ble/Gap.h"
Fedor Chervyakov 2:45ed62566694 28 #include "ble/GattClient.h"
Fedor Chervyakov 2:45ed62566694 29 #include "ble/GattServer.h"
Fedor Chervyakov 2:45ed62566694 30 #include "ble/GapAdvertisingParams.h"
Fedor Chervyakov 2:45ed62566694 31 #include "ble/GapAdvertisingData.h"
Fedor Chervyakov 2:45ed62566694 32 #include "ble/FunctionPointerWithContext.h"
Fedor Chervyakov 2:45ed62566694 33 #include "ble/services/EnvironmentalService.h"
Fedor Chervyakov 2:45ed62566694 34
Fedor Chervyakov 1:667b9825e7ee 35 #include "bme280_wrapper.h"
Fedor Chervyakov 2:45ed62566694 36 #include "stats_report.h"
Fedor Chervyakov 2:45ed62566694 37
Fedor Chervyakov 2:45ed62566694 38
Fedor Chervyakov 2:45ed62566694 39 using mbed::callback;
Fedor Chervyakov 2:45ed62566694 40
Fedor Chervyakov 2:45ed62566694 41 Thread t;
Fedor Chervyakov 2:45ed62566694 42 Thread stats_report_thread;
Fedor Chervyakov 2:45ed62566694 43
Fedor Chervyakov 2:45ed62566694 44 AnalogIn lm35_input(A0); /* ADC input pin connected to Vout of LM35 */
Fedor Chervyakov 2:45ed62566694 45
Fedor Chervyakov 2:45ed62566694 46
Fedor Chervyakov 2:45ed62566694 47 #define SLEEP_TIME 5 /* loop delay in seconds */
Fedor Chervyakov 2:45ed62566694 48 #define V_SUPPLY 3.3 /* System voltage */
Fedor Chervyakov 2:45ed62566694 49 #define K_LM35 0.01 /* Linear coefficient in transfer function of LM35: Vout = K [V/degC] * T [degC] */
Fedor Chervyakov 2:45ed62566694 50 #define BLE_DEVICE_NAME "BME280 sensor"
Fedor Chervyakov 2:45ed62566694 51 #define UPDATE_RATE 5000 /* ms */
Fedor Chervyakov 2:45ed62566694 52
Fedor Chervyakov 2:45ed62566694 53
Fedor Chervyakov 2:45ed62566694 54 class BME280BLE : private mbed::NonCopyable<BME280BLE>, public ble::Gap::EventHandler {
Fedor Chervyakov 2:45ed62566694 55 public:
Fedor Chervyakov 2:45ed62566694 56
Fedor Chervyakov 2:45ed62566694 57 BME280BLE(events::EventQueue &event_queue, BLE &ble_interface) :
Fedor Chervyakov 2:45ed62566694 58 _ble_interface(ble_interface),
Fedor Chervyakov 2:45ed62566694 59 _gap(_ble_interface.gap()),
Fedor Chervyakov 2:45ed62566694 60 _event_queue(event_queue),
Fedor Chervyakov 2:45ed62566694 61 _post_init_cb(),
Fedor Chervyakov 2:45ed62566694 62 _bme280(BME280(I2C_SDA, I2C_SCL)),
Fedor Chervyakov 2:45ed62566694 63 _env_service(NULL),
Fedor Chervyakov 2:45ed62566694 64 _env_service_uuid(GattService::UUID_ENVIRONMENTAL_SERVICE)
Fedor Chervyakov 2:45ed62566694 65 {
Fedor Chervyakov 2:45ed62566694 66 }
Fedor Chervyakov 2:45ed62566694 67
Fedor Chervyakov 2:45ed62566694 68 ~BME280BLE() {
Fedor Chervyakov 2:45ed62566694 69 stop();
Fedor Chervyakov 2:45ed62566694 70 }
Fedor Chervyakov 2:45ed62566694 71
Fedor Chervyakov 2:45ed62566694 72 void on_init(mbed::Callback<void(BLE&, events::EventQueue&)> cb) {
Fedor Chervyakov 2:45ed62566694 73 _post_init_cb = cb;
Fedor Chervyakov 2:45ed62566694 74 }
Fedor Chervyakov 2:45ed62566694 75
Fedor Chervyakov 2:45ed62566694 76 bool start() {
Fedor Chervyakov 2:45ed62566694 77
Fedor Chervyakov 2:45ed62566694 78 printf("BLE process has started. \r\n");
Fedor Chervyakov 2:45ed62566694 79
Fedor Chervyakov 2:45ed62566694 80 if (_ble_interface.hasInitialized()) {
Fedor Chervyakov 2:45ed62566694 81 printf("Error: the BLE instance has already been initialized! \r\n");
Fedor Chervyakov 2:45ed62566694 82 return false;
Fedor Chervyakov 2:45ed62566694 83 }
Fedor Chervyakov 2:45ed62566694 84
Fedor Chervyakov 2:45ed62566694 85 /* Set Gap EventHandler to this class */
Fedor Chervyakov 2:45ed62566694 86 _gap.setEventHandler(this);
Fedor Chervyakov 2:45ed62566694 87
Fedor Chervyakov 2:45ed62566694 88 _ble_interface.onEventsToProcess(
Fedor Chervyakov 2:45ed62566694 89 makeFunctionPointer(this, &BME280BLE::schedule_ble_events)
Fedor Chervyakov 2:45ed62566694 90 );
Fedor Chervyakov 2:45ed62566694 91
Fedor Chervyakov 2:45ed62566694 92 /* Initialize BLE interface */
Fedor Chervyakov 2:45ed62566694 93 ble_error_t error = _ble_interface.init(this, &BME280BLE::when_init_complete);
Fedor Chervyakov 2:45ed62566694 94 if (error) {
Fedor Chervyakov 2:45ed62566694 95 printf("Error: %u returned by BLE::init.\r\n", error);
Fedor Chervyakov 2:45ed62566694 96 return false;
Fedor Chervyakov 2:45ed62566694 97 }
Fedor Chervyakov 2:45ed62566694 98
Fedor Chervyakov 2:45ed62566694 99 _event_queue.call_every(UPDATE_RATE, this, &BME280BLE::update_measurements);
Fedor Chervyakov 2:45ed62566694 100
Fedor Chervyakov 2:45ed62566694 101 return true;
Fedor Chervyakov 2:45ed62566694 102 }
Fedor Chervyakov 2:45ed62566694 103
Fedor Chervyakov 2:45ed62566694 104 void stop() {
Fedor Chervyakov 2:45ed62566694 105 if (_ble_interface.hasInitialized()) {
Fedor Chervyakov 2:45ed62566694 106 _ble_interface.shutdown();
Fedor Chervyakov 2:45ed62566694 107 printf("BLE process stopped.\r\n");
Fedor Chervyakov 2:45ed62566694 108 }
Fedor Chervyakov 2:45ed62566694 109
Fedor Chervyakov 2:45ed62566694 110 }
Fedor Chervyakov 2:45ed62566694 111
Fedor Chervyakov 2:45ed62566694 112 private:
Fedor Chervyakov 2:45ed62566694 113
Fedor Chervyakov 2:45ed62566694 114 void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *event) {
Fedor Chervyakov 2:45ed62566694 115 _event_queue.call(mbed::callback(&event->ble, &BLE::processEvents));
Fedor Chervyakov 2:45ed62566694 116 }
Fedor Chervyakov 2:45ed62566694 117
Fedor Chervyakov 2:45ed62566694 118 void when_init_complete(BLE::InitializationCompleteCallbackContext *event) {
Fedor Chervyakov 2:45ed62566694 119
Fedor Chervyakov 2:45ed62566694 120 if (event->error) {
Fedor Chervyakov 2:45ed62566694 121 printf("Error %u during the initialization.\r\n", event->error);
Fedor Chervyakov 2:45ed62566694 122 }
Fedor Chervyakov 2:45ed62566694 123 printf("BLE instance initialized.\r\n");
Fedor Chervyakov 2:45ed62566694 124
Fedor Chervyakov 2:45ed62566694 125 /* Setup environmental service */
Fedor Chervyakov 2:45ed62566694 126 _env_service = new EnvironmentalService(_ble_interface);
Fedor Chervyakov 2:45ed62566694 127
Fedor Chervyakov 2:45ed62566694 128 if (!set_advertising_parameters()) {
Fedor Chervyakov 2:45ed62566694 129 return;
Fedor Chervyakov 2:45ed62566694 130 }
fedorc 0:22a4f6c99d74 131
Fedor Chervyakov 2:45ed62566694 132 if (!set_advertising_data()) {
Fedor Chervyakov 2:45ed62566694 133 return;
Fedor Chervyakov 2:45ed62566694 134 }
Fedor Chervyakov 2:45ed62566694 135
Fedor Chervyakov 2:45ed62566694 136 if (!start_advertising()){
Fedor Chervyakov 2:45ed62566694 137 return;
Fedor Chervyakov 2:45ed62566694 138 }
Fedor Chervyakov 2:45ed62566694 139
Fedor Chervyakov 2:45ed62566694 140
Fedor Chervyakov 2:45ed62566694 141 if (_post_init_cb) {
Fedor Chervyakov 2:45ed62566694 142 _post_init_cb(_ble_interface, _event_queue);
Fedor Chervyakov 2:45ed62566694 143 }
Fedor Chervyakov 2:45ed62566694 144 }
Fedor Chervyakov 2:45ed62566694 145
Fedor Chervyakov 2:45ed62566694 146 bool set_advertising_parameters() {
Fedor Chervyakov 2:45ed62566694 147 ble_error_t error = _gap.setAdvertisingParameters(
Fedor Chervyakov 2:45ed62566694 148 ble::LEGACY_ADVERTISING_HANDLE,
Fedor Chervyakov 2:45ed62566694 149 ble::AdvertisingParameters(
Fedor Chervyakov 2:45ed62566694 150 ble::advertising_type_t::CONNECTABLE_UNDIRECTED,
Fedor Chervyakov 2:45ed62566694 151 ble::adv_interval_t(ble::millisecond_t(1000))
Fedor Chervyakov 2:45ed62566694 152 )
Fedor Chervyakov 2:45ed62566694 153 );
Fedor Chervyakov 2:45ed62566694 154
Fedor Chervyakov 2:45ed62566694 155 if (error) {
Fedor Chervyakov 2:45ed62566694 156 printf("Gap::setAdvertisingParameters() failed with error %d", error);
Fedor Chervyakov 2:45ed62566694 157 return false;
Fedor Chervyakov 2:45ed62566694 158 }
Fedor Chervyakov 2:45ed62566694 159
Fedor Chervyakov 2:45ed62566694 160 return true;
Fedor Chervyakov 2:45ed62566694 161 }
Fedor Chervyakov 2:45ed62566694 162
Fedor Chervyakov 2:45ed62566694 163 bool set_advertising_data() {
Fedor Chervyakov 2:45ed62566694 164 /* Use the simple builder to construct the payload; it fails at runtime
Fedor Chervyakov 2:45ed62566694 165 * if there is not enough space left in the buffer */
Fedor Chervyakov 2:45ed62566694 166 ble_error_t error = _gap.setAdvertisingPayload(
Fedor Chervyakov 2:45ed62566694 167 ble::LEGACY_ADVERTISING_HANDLE,
Fedor Chervyakov 2:45ed62566694 168 ble::AdvertisingDataSimpleBuilder<ble::LEGACY_ADVERTISING_MAX_SIZE>()
Fedor Chervyakov 2:45ed62566694 169 .setFlags()
Fedor Chervyakov 2:45ed62566694 170 .setLocalServiceList(mbed::make_Span(&_env_service_uuid, 1))
Fedor Chervyakov 2:45ed62566694 171 .setName(BLE_DEVICE_NAME)
Fedor Chervyakov 2:45ed62566694 172 .getAdvertisingData()
Fedor Chervyakov 2:45ed62566694 173 );
Fedor Chervyakov 2:45ed62566694 174
Fedor Chervyakov 2:45ed62566694 175 if (error) {
Fedor Chervyakov 2:45ed62566694 176 printf("Gap::setAdvertisingPayload() failed with error %d", error);
Fedor Chervyakov 2:45ed62566694 177 return false;
Fedor Chervyakov 2:45ed62566694 178 }
Fedor Chervyakov 2:45ed62566694 179
Fedor Chervyakov 2:45ed62566694 180 return true;
Fedor Chervyakov 2:45ed62566694 181 }
Fedor Chervyakov 2:45ed62566694 182
Fedor Chervyakov 2:45ed62566694 183 bool start_advertising() {
Fedor Chervyakov 2:45ed62566694 184 /* Start advertising the set */
Fedor Chervyakov 2:45ed62566694 185 ble_error_t error = _gap.startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
Fedor Chervyakov 2:45ed62566694 186
Fedor Chervyakov 2:45ed62566694 187 if (error) {
Fedor Chervyakov 2:45ed62566694 188 printf("Error %u during gap.startAdvertising.\r\n", error);
Fedor Chervyakov 2:45ed62566694 189 return false;
Fedor Chervyakov 2:45ed62566694 190 } else {
Fedor Chervyakov 2:45ed62566694 191 printf("Advertising started.\r\n");
Fedor Chervyakov 2:45ed62566694 192 return true;
Fedor Chervyakov 2:45ed62566694 193 }
Fedor Chervyakov 2:45ed62566694 194 }
Fedor Chervyakov 2:45ed62566694 195
Fedor Chervyakov 2:45ed62566694 196 private:
Fedor Chervyakov 2:45ed62566694 197 /* Gap::EventHandler */
Fedor Chervyakov 2:45ed62566694 198
Fedor Chervyakov 2:45ed62566694 199 virtual void onConnectionComplete(const ble::ConnectionCompleteEvent &event) {
Fedor Chervyakov 2:45ed62566694 200 printf("Connected.\r\n");
Fedor Chervyakov 2:45ed62566694 201 }
Fedor Chervyakov 2:45ed62566694 202
Fedor Chervyakov 2:45ed62566694 203 virtual void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &event) {
Fedor Chervyakov 2:45ed62566694 204 printf("Disconnected.\r\n");
Fedor Chervyakov 2:45ed62566694 205 start_advertising();
Fedor Chervyakov 2:45ed62566694 206 }
Fedor Chervyakov 2:45ed62566694 207
Fedor Chervyakov 2:45ed62566694 208 private:
Fedor Chervyakov 2:45ed62566694 209 /* EnvironmentalService */
Fedor Chervyakov 2:45ed62566694 210
Fedor Chervyakov 2:45ed62566694 211 void update_measurements() {
Fedor Chervyakov 2:45ed62566694 212
Fedor Chervyakov 2:45ed62566694 213 struct bme280_data *comp_data;
Fedor Chervyakov 2:45ed62566694 214 EnvironmentalService::HumidityType_t humidity; // uint16_t
Fedor Chervyakov 2:45ed62566694 215 EnvironmentalService::PressureType_t pressure; // uint32_t
Fedor Chervyakov 2:45ed62566694 216 float temperature; // int16_t
Fedor Chervyakov 2:45ed62566694 217
Fedor Chervyakov 2:45ed62566694 218 _bme280.force_measurement();
Fedor Chervyakov 2:45ed62566694 219
Fedor Chervyakov 2:45ed62566694 220 comp_data = &_bme280.comp_data;
Fedor Chervyakov 2:45ed62566694 221
Fedor Chervyakov 2:45ed62566694 222 temperature = comp_data->temperature;
Fedor Chervyakov 2:45ed62566694 223 humidity = comp_data->humidity;
Fedor Chervyakov 2:45ed62566694 224 pressure = comp_data->pressure;
Fedor Chervyakov 2:45ed62566694 225
Fedor Chervyakov 2:45ed62566694 226 _env_service->updateTemperature(temperature);
Fedor Chervyakov 2:45ed62566694 227 _env_service->updatePressure(pressure);
Fedor Chervyakov 2:45ed62566694 228 _env_service->updateHumidity(humidity);
Fedor Chervyakov 2:45ed62566694 229
Fedor Chervyakov 2:45ed62566694 230 }
Fedor Chervyakov 2:45ed62566694 231
Fedor Chervyakov 2:45ed62566694 232 private:
Fedor Chervyakov 2:45ed62566694 233 BLE &_ble_interface;
Fedor Chervyakov 2:45ed62566694 234 Gap &_gap;
Fedor Chervyakov 2:45ed62566694 235 EnvironmentalService *_env_service;
Fedor Chervyakov 2:45ed62566694 236 UUID _env_service_uuid;
Fedor Chervyakov 2:45ed62566694 237
Fedor Chervyakov 2:45ed62566694 238 events::EventQueue &_event_queue;
Fedor Chervyakov 2:45ed62566694 239 mbed::Callback<void(BLE&, events::EventQueue&)> _post_init_cb;
Fedor Chervyakov 2:45ed62566694 240
Fedor Chervyakov 2:45ed62566694 241 BME280 _bme280;
Fedor Chervyakov 2:45ed62566694 242
Fedor Chervyakov 2:45ed62566694 243 };
Fedor Chervyakov 2:45ed62566694 244
Fedor Chervyakov 2:45ed62566694 245
fedorc 0:22a4f6c99d74 246
fedorc 0:22a4f6c99d74 247 void print_sensor_data(struct bme280_data *comp_data)
fedorc 0:22a4f6c99d74 248 {
fedorc 0:22a4f6c99d74 249 float temp, press, hum;
Fedor Chervyakov 2:45ed62566694 250
fedorc 0:22a4f6c99d74 251 temp = comp_data->temperature;
fedorc 0:22a4f6c99d74 252 press = 0.01 * comp_data->pressure;
fedorc 0:22a4f6c99d74 253 hum = comp_data->humidity;
Fedor Chervyakov 2:45ed62566694 254
Fedor Chervyakov 1:667b9825e7ee 255 printf("BME280 %0.2lf deg C, %0.2lf hPa, %0.2lf%%\n", temp, press, hum);
fedorc 0:22a4f6c99d74 256 }
fedorc 0:22a4f6c99d74 257
Fedor Chervyakov 2:45ed62566694 258
Fedor Chervyakov 2:45ed62566694 259 float lm35_temperature() {
Fedor Chervyakov 2:45ed62566694 260 float temperature;
Fedor Chervyakov 2:45ed62566694 261
Fedor Chervyakov 2:45ed62566694 262 temperature = lm35_input.read() * V_SUPPLY / (K_LM35 * (1+10/4.7)) ;
Fedor Chervyakov 2:45ed62566694 263
Fedor Chervyakov 2:45ed62566694 264 return temperature;
Fedor Chervyakov 2:45ed62566694 265 }
Fedor Chervyakov 2:45ed62566694 266
Fedor Chervyakov 2:45ed62566694 267
Fedor Chervyakov 2:45ed62566694 268 void print_stats() {
Fedor Chervyakov 2:45ed62566694 269 SystemReport sys_report(SLEEP_TIME * 1000);
Fedor Chervyakov 2:45ed62566694 270
Fedor Chervyakov 2:45ed62566694 271 while (true) {
Fedor Chervyakov 2:45ed62566694 272 sys_report.report_state();
Fedor Chervyakov 2:45ed62566694 273 wait(SLEEP_TIME);
Fedor Chervyakov 2:45ed62566694 274 }
Fedor Chervyakov 2:45ed62566694 275 }
Fedor Chervyakov 2:45ed62566694 276
Fedor Chervyakov 2:45ed62566694 277
Fedor Chervyakov 2:45ed62566694 278
fedorc 0:22a4f6c99d74 279 // main() runs in its own thread in the OS
fedorc 0:22a4f6c99d74 280 int main()
fedorc 0:22a4f6c99d74 281 {
Fedor Chervyakov 2:45ed62566694 282 events::EventQueue event_queue; /* Event queue */
Fedor Chervyakov 2:45ed62566694 283 BLE &ble_interface = BLE::Instance(); /* Bluetooth interface */
Fedor Chervyakov 2:45ed62566694 284 BME280BLE ble_process(event_queue, ble_interface);
Fedor Chervyakov 2:45ed62566694 285
Fedor Chervyakov 2:45ed62566694 286 ble_process.start();
fedorc 0:22a4f6c99d74 287
Fedor Chervyakov 2:45ed62566694 288 t.start(mbed::callback(&event_queue, &EventQueue::dispatch_forever));
Fedor Chervyakov 2:45ed62566694 289 stats_report_thread.start(print_stats);
Fedor Chervyakov 2:45ed62566694 290
fedorc 0:22a4f6c99d74 291 while (true) {
Fedor Chervyakov 2:45ed62566694 292 printf("LM35 %.2f deg C; ", lm35_temperature());
Fedor Chervyakov 2:45ed62566694 293
Fedor Chervyakov 2:45ed62566694 294 wait(SLEEP_TIME);
fedorc 0:22a4f6c99d74 295 }
Fedor Chervyakov 2:45ed62566694 296
fedorc 0:22a4f6c99d74 297 }