This is an example of BLE GATT Client, which receives broadcast data from BLE_Server_BME280 ( a GATT server) , then transfers values up to mbed Device Connector (cloud).

Please refer details about BLEClient_mbedDevConn below. https://github.com/soramame21/BLEClient_mbedDevConn

The location of required BLE GATT server, BLE_Server_BME280, is at here. https://developer.mbed.org/users/edamame22/code/BLE_Server_BME280/

Committer:
edamame22
Date:
Wed Apr 26 11:20:41 2017 +0900
Revision:
1:8950e6a891df
Parent:
0:29983394c6b6
Child:
2:b894b3508057
Fix a momery overrun bug, moved global variables to local func

Who changed what in which revision?

UserRevisionLine numberNew contents of line
edamame22 0:29983394c6b6 1 /*
edamame22 0:29983394c6b6 2 * Copyright (c) 2015 ARM Limited. All rights reserved.
edamame22 0:29983394c6b6 3 * SPDX-License-Identifier: Apache-2.0
edamame22 0:29983394c6b6 4 * Licensed under the Apache License, Version 2.0 (the License); you may
edamame22 0:29983394c6b6 5 * not use this file except in compliance with the License.
edamame22 0:29983394c6b6 6 * You may obtain a copy of the License at
edamame22 0:29983394c6b6 7 *
edamame22 0:29983394c6b6 8 * http://www.apache.org/licenses/LICENSE-2.0
edamame22 0:29983394c6b6 9 *
edamame22 0:29983394c6b6 10 * Unless required by applicable law or agreed to in writing, software
edamame22 0:29983394c6b6 11 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
edamame22 0:29983394c6b6 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
edamame22 0:29983394c6b6 13 * See the License for the specific language governing permissions and
edamame22 0:29983394c6b6 14 * limitations under the License.
edamame22 0:29983394c6b6 15 */
edamame22 0:29983394c6b6 16
edamame22 0:29983394c6b6 17 #include "simpleclient.h"
edamame22 0:29983394c6b6 18 #include <string>
edamame22 0:29983394c6b6 19 #include <sstream>
edamame22 0:29983394c6b6 20 #include <vector>
edamame22 0:29983394c6b6 21 #include "mbed-trace/mbed_trace.h"
edamame22 0:29983394c6b6 22 #include "mbedtls/entropy_poll.h"
edamame22 0:29983394c6b6 23
edamame22 0:29983394c6b6 24 #include <events/mbed_events.h>
edamame22 0:29983394c6b6 25 #include <mbed.h>
edamame22 0:29983394c6b6 26 #include "ble/BLE.h"
edamame22 0:29983394c6b6 27 #include "ble/DiscoveredCharacteristic.h"
edamame22 0:29983394c6b6 28 #include "ble/DiscoveredService.h"
edamame22 0:29983394c6b6 29
edamame22 0:29983394c6b6 30 #include "security.h"
edamame22 0:29983394c6b6 31
edamame22 0:29983394c6b6 32 #include "mbed.h"
edamame22 0:29983394c6b6 33 #include "rtos.h"
edamame22 0:29983394c6b6 34
edamame22 0:29983394c6b6 35 #if MBED_CONF_APP_NETWORK_INTERFACE == WIFI
edamame22 0:29983394c6b6 36 #include "ESP8266Interface.h"
edamame22 0:29983394c6b6 37 ESP8266Interface esp(MBED_CONF_APP_WIFI_TX, MBED_CONF_APP_WIFI_RX);
edamame22 0:29983394c6b6 38 #elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET
edamame22 0:29983394c6b6 39 #include "EthernetInterface.h"
edamame22 0:29983394c6b6 40 EthernetInterface eth;
edamame22 0:29983394c6b6 41 #elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_LOWPAN_ND
edamame22 0:29983394c6b6 42 #define MESH
edamame22 0:29983394c6b6 43 #include "NanostackInterface.h"
edamame22 0:29983394c6b6 44 LoWPANNDInterface mesh;
edamame22 0:29983394c6b6 45 #elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_THREAD
edamame22 0:29983394c6b6 46 #define MESH
edamame22 0:29983394c6b6 47 #include "NanostackInterface.h"
edamame22 0:29983394c6b6 48 ThreadInterface mesh;
edamame22 0:29983394c6b6 49 #endif
edamame22 0:29983394c6b6 50
edamame22 0:29983394c6b6 51 #if defined(MESH)
edamame22 0:29983394c6b6 52 #if MBED_CONF_APP_MESH_RADIO_TYPE == ATMEL
edamame22 0:29983394c6b6 53 #include "NanostackRfPhyAtmel.h"
edamame22 0:29983394c6b6 54 NanostackRfPhyAtmel rf_phy(ATMEL_SPI_MOSI, ATMEL_SPI_MISO, ATMEL_SPI_SCLK, ATMEL_SPI_CS,
edamame22 0:29983394c6b6 55 ATMEL_SPI_RST, ATMEL_SPI_SLP, ATMEL_SPI_IRQ, ATMEL_I2C_SDA, ATMEL_I2C_SCL);
edamame22 0:29983394c6b6 56 #elif MBED_CONF_APP_MESH_RADIO_TYPE == MCR20
edamame22 0:29983394c6b6 57 #include "NanostackRfPhyMcr20a.h"
edamame22 0:29983394c6b6 58 NanostackRfPhyMcr20a rf_phy(MCR20A_SPI_MOSI, MCR20A_SPI_MISO, MCR20A_SPI_SCLK, MCR20A_SPI_CS, MCR20A_SPI_RST, MCR20A_SPI_IRQ);
edamame22 0:29983394c6b6 59 #endif //MBED_CONF_APP_RADIO_TYPE
edamame22 0:29983394c6b6 60 #endif //MESH
edamame22 0:29983394c6b6 61
edamame22 0:29983394c6b6 62 #ifndef MESH
edamame22 0:29983394c6b6 63 // This is address to mbed Device Connector
edamame22 0:29983394c6b6 64 #define MBED_SERVER_ADDRESS "coap://api.connector.mbed.com:5684"
edamame22 0:29983394c6b6 65 #else
edamame22 0:29983394c6b6 66 // This is address to mbed Device Connector
edamame22 0:29983394c6b6 67 #define MBED_SERVER_ADDRESS "coaps://[2607:f0d0:2601:52::20]:5684"
edamame22 0:29983394c6b6 68 #endif
edamame22 0:29983394c6b6 69
edamame22 0:29983394c6b6 70 Serial output(USBTX, USBRX);
edamame22 0:29983394c6b6 71
edamame22 0:29983394c6b6 72 // Status indication
edamame22 0:29983394c6b6 73 DigitalOut red_led(LED1);
edamame22 0:29983394c6b6 74 DigitalOut green_led(LED2);
edamame22 0:29983394c6b6 75 DigitalOut blue_led(LED3);
edamame22 0:29983394c6b6 76 Ticker status_ticker;
edamame22 0:29983394c6b6 77 // Ren, begin
edamame22 0:29983394c6b6 78 enum charType {
edamame22 0:29983394c6b6 79 PRESSURE,
edamame22 0:29983394c6b6 80 TEMPERATURE,
edamame22 0:29983394c6b6 81 HUMIDITY
edamame22 0:29983394c6b6 82 };
edamame22 0:29983394c6b6 83 const char * dbg_CharType[HUMIDITY+1]={"Pressure","Temperature","Humidity"};
edamame22 0:29983394c6b6 84 const char * objName[HUMIDITY+1]={"3323","3303","3304"};
edamame22 0:29983394c6b6 85 static bool is_active[HUMIDITY+1];
edamame22 0:29983394c6b6 86 static float dataprint[HUMIDITY+1]={0,0,0};
edamame22 0:29983394c6b6 87 /*
edamame22 0:29983394c6b6 88 * The BME280 sensor contains 3 float properties.
edamame22 0:29983394c6b6 89 * Those are updated once BLE Gatt client read the values.
edamame22 0:29983394c6b6 90 */
edamame22 0:29983394c6b6 91 class BME280Resource {
edamame22 0:29983394c6b6 92 public:
edamame22 0:29983394c6b6 93 BME280Resource() {
edamame22 0:29983394c6b6 94 // create Pressure object '3323'.
edamame22 0:29983394c6b6 95 for(int m=0; m<HUMIDITY+1; m++) {
edamame22 0:29983394c6b6 96 bme280[m] = M2MInterfaceFactory::create_object(objName[m]);
edamame22 0:29983394c6b6 97 tmp_inst[m] = bme280[m] ->create_object_instance();
edamame22 0:29983394c6b6 98 tmp_res[m] = tmp_inst[m]->create_dynamic_resource("5700", dbg_CharType[m],
edamame22 0:29983394c6b6 99 M2MResourceInstance::STRING, true /* observable */);
edamame22 0:29983394c6b6 100 tmp_res[m]->set_operation(M2MBase::GET_ALLOWED);
edamame22 0:29983394c6b6 101 tmp_res[m]->set_value((uint8_t*)"0.0", 3);
edamame22 0:29983394c6b6 102 }
edamame22 0:29983394c6b6 103 }
edamame22 0:29983394c6b6 104
edamame22 0:29983394c6b6 105 void set_bme280_value(float val, int h){
edamame22 0:29983394c6b6 106 char tmp_buf[50];
edamame22 0:29983394c6b6 107 int len;
edamame22 0:29983394c6b6 108 if (h<PRESSURE || h>HUMIDITY) {
edamame22 0:29983394c6b6 109 printf("data type h (input) is wrong!!");
edamame22 0:29983394c6b6 110 return;
edamame22 0:29983394c6b6 111 }
edamame22 0:29983394c6b6 112 if (h==HUMIDITY)
edamame22 0:29983394c6b6 113 len=sprintf(tmp_buf,"%0.2f%%",val);
edamame22 0:29983394c6b6 114 else if (h==PRESSURE)
edamame22 0:29983394c6b6 115 len=sprintf(tmp_buf,"%0.1f hPa",val);
edamame22 0:29983394c6b6 116 else
edamame22 0:29983394c6b6 117 len=sprintf(tmp_buf,"%0.2f degC",val);
edamame22 0:29983394c6b6 118
edamame22 0:29983394c6b6 119 tmp_res[h]->set_value((uint8_t*)tmp_buf, len);
edamame22 0:29983394c6b6 120 //printf("set_value(tmp_bug=%s\r\n", tmp_buf);
edamame22 0:29983394c6b6 121 }
edamame22 0:29983394c6b6 122
edamame22 0:29983394c6b6 123
edamame22 0:29983394c6b6 124 M2MObject* get_object(int idx) {
edamame22 0:29983394c6b6 125 if (idx<PRESSURE || idx>HUMIDITY) return NULL;
edamame22 0:29983394c6b6 126 return bme280[idx];
edamame22 0:29983394c6b6 127 }
edamame22 0:29983394c6b6 128 private:
edamame22 0:29983394c6b6 129 M2MObject* bme280[HUMIDITY+1];
edamame22 0:29983394c6b6 130 M2MObjectInstance* tmp_inst[HUMIDITY+1];
edamame22 0:29983394c6b6 131 M2MResource* tmp_res[HUMIDITY+1];
edamame22 0:29983394c6b6 132 };
edamame22 0:29983394c6b6 133
edamame22 0:29983394c6b6 134 static BME280Resource *demo1;
edamame22 0:29983394c6b6 135 // Ren, end
edamame22 0:29983394c6b6 136
edamame22 0:29983394c6b6 137 /************************************************************BLE Stuff from here *********************************/
edamame22 0:29983394c6b6 138 BLE &ble = BLE::Instance();
edamame22 0:29983394c6b6 139 static DiscoveredCharacteristic bme280Characteristic[HUMIDITY+1];
edamame22 0:29983394c6b6 140 static bool triggerLedCharacteristic;
edamame22 0:29983394c6b6 141 static const char PEER_NAME[] = "BME280";
edamame22 1:8950e6a891df 142
edamame22 0:29983394c6b6 143
edamame22 0:29983394c6b6 144 static EventQueue eventQueue(
edamame22 0:29983394c6b6 145 /* event count */ 16 * /* event size */ 32
edamame22 0:29983394c6b6 146 );
edamame22 0:29983394c6b6 147
edamame22 0:29983394c6b6 148 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
edamame22 0:29983394c6b6 149 // parse the advertising payload, looking for data type COMPLETE_LOCAL_NAME
edamame22 0:29983394c6b6 150 // The advertising payload is a collection of key/value records where
edamame22 0:29983394c6b6 151 // byte 0: length of the record excluding this byte
edamame22 0:29983394c6b6 152 // byte 1: The key, it is the type of the data
edamame22 0:29983394c6b6 153 // byte [2..N] The value. N is equal to byte0 - 1
edamame22 0:29983394c6b6 154
edamame22 0:29983394c6b6 155 //printf("Starting advertisementCallback...\r\n");
edamame22 0:29983394c6b6 156 for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
edamame22 0:29983394c6b6 157
edamame22 0:29983394c6b6 158 const uint8_t record_length = params->advertisingData[i];
edamame22 0:29983394c6b6 159 if (record_length == 0) {
edamame22 0:29983394c6b6 160 continue;
edamame22 0:29983394c6b6 161 }
edamame22 0:29983394c6b6 162 const uint8_t type = params->advertisingData[i + 1];
edamame22 0:29983394c6b6 163 const uint8_t* value = params->advertisingData + i + 2;
edamame22 0:29983394c6b6 164 const uint8_t value_length = record_length - 1;
edamame22 0:29983394c6b6 165
edamame22 0:29983394c6b6 166 if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
edamame22 0:29983394c6b6 167 if ((value_length == sizeof(PEER_NAME)) && (memcmp(value, PEER_NAME, value_length) == 0)) {
edamame22 0:29983394c6b6 168 printf(
edamame22 0:29983394c6b6 169 "adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
edamame22 0:29983394c6b6 170 params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2],
edamame22 0:29983394c6b6 171 params->peerAddr[1], params->peerAddr[0], params->rssi, params->isScanResponse, params->type
edamame22 0:29983394c6b6 172 );
edamame22 0:29983394c6b6 173 BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
edamame22 0:29983394c6b6 174 break;
edamame22 0:29983394c6b6 175 }
edamame22 0:29983394c6b6 176 }
edamame22 0:29983394c6b6 177 i += record_length;
edamame22 0:29983394c6b6 178 }
edamame22 0:29983394c6b6 179 }
edamame22 0:29983394c6b6 180
edamame22 0:29983394c6b6 181 void serviceDiscoveryCallback(const DiscoveredService *service) {
edamame22 0:29983394c6b6 182 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
edamame22 0:29983394c6b6 183 printf("S type short UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
edamame22 0:29983394c6b6 184 } else {
edamame22 0:29983394c6b6 185 printf("S type long UUID-");
edamame22 0:29983394c6b6 186 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
edamame22 0:29983394c6b6 187 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
edamame22 0:29983394c6b6 188 printf("%02x", longUUIDBytes[i]);
edamame22 0:29983394c6b6 189 }
edamame22 0:29983394c6b6 190 printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
edamame22 0:29983394c6b6 191 }
edamame22 0:29983394c6b6 192 }
edamame22 0:29983394c6b6 193
edamame22 0:29983394c6b6 194 /***
edamame22 0:29983394c6b6 195 This function called read() initially, following read() calls
edamame22 0:29983394c6b6 196 are repeated inside triggerRead function
edamame22 0:29983394c6b6 197 ***/
edamame22 0:29983394c6b6 198 void updateLedCharacteristic(void) {
edamame22 0:29983394c6b6 199 if (!BLE::Instance().gattClient().isServiceDiscoveryActive()) {
edamame22 0:29983394c6b6 200 //printf("02 updateLedCharacteristic\n");
edamame22 0:29983394c6b6 201 for(int g=0; g<HUMIDITY+1; g++) {
edamame22 0:29983394c6b6 202 if (is_active[g]) bme280Characteristic[g].read();
edamame22 0:29983394c6b6 203 }
edamame22 0:29983394c6b6 204 }
edamame22 0:29983394c6b6 205 }
edamame22 0:29983394c6b6 206
edamame22 0:29983394c6b6 207
edamame22 0:29983394c6b6 208 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
edamame22 0:29983394c6b6 209 int tmp_uuid;
edamame22 0:29983394c6b6 210 tmp_uuid=characteristicP->getUUID().getShortUUID();
edamame22 0:29983394c6b6 211 printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
edamame22 0:29983394c6b6 212 if ((tmp_uuid < GattCharacteristic::UUID_PRESSURE_CHAR) ||
edamame22 0:29983394c6b6 213 (tmp_uuid > GattCharacteristic::UUID_HUMIDITY_CHAR)) return;
edamame22 0:29983394c6b6 214 triggerLedCharacteristic = true;
edamame22 0:29983394c6b6 215 if (tmp_uuid == GattCharacteristic::UUID_PRESSURE_CHAR) {
edamame22 0:29983394c6b6 216 bme280Characteristic[PRESSURE] = *characteristicP; is_active[PRESSURE] = true;
edamame22 0:29983394c6b6 217 printf(" is_active[PRESSURE] = true\r\n");
edamame22 0:29983394c6b6 218 }
edamame22 0:29983394c6b6 219 else if (tmp_uuid == GattCharacteristic::UUID_TEMPERATURE_CHAR) {
edamame22 0:29983394c6b6 220 bme280Characteristic[TEMPERATURE] = *characteristicP; is_active[TEMPERATURE] = true;
edamame22 0:29983394c6b6 221 printf(" is_active[TEMPERATURE] = true\r\n");
edamame22 0:29983394c6b6 222 } else {
edamame22 0:29983394c6b6 223 bme280Characteristic[HUMIDITY] = *characteristicP; is_active[HUMIDITY] = true;
edamame22 0:29983394c6b6 224 printf(" is_active[HUMIDITY] = true\r\n");
edamame22 0:29983394c6b6 225 }
edamame22 0:29983394c6b6 226 }
edamame22 0:29983394c6b6 227
edamame22 0:29983394c6b6 228 void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
edamame22 0:29983394c6b6 229 printf("terminated SD for handle %u\r\n", connectionHandle);
edamame22 0:29983394c6b6 230 if (triggerLedCharacteristic) {
edamame22 0:29983394c6b6 231 triggerLedCharacteristic = false;
edamame22 0:29983394c6b6 232 eventQueue.call(updateLedCharacteristic);
edamame22 0:29983394c6b6 233 }
edamame22 0:29983394c6b6 234 }
edamame22 0:29983394c6b6 235
edamame22 0:29983394c6b6 236 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
edamame22 0:29983394c6b6 237 int ret;
edamame22 0:29983394c6b6 238 printf("Connected to BME280 now...\r\n");
edamame22 0:29983394c6b6 239 if (params->role == Gap::CENTRAL) {
edamame22 0:29983394c6b6 240 BLE &ble = BLE::Instance();
edamame22 0:29983394c6b6 241 ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
edamame22 0:29983394c6b6 242 // Ren, connect to ENVIRONMENT service
edamame22 0:29983394c6b6 243 ret=ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, GattService::UUID_ENVIRONMENTAL_SERVICE);
edamame22 0:29983394c6b6 244 printf("ble.gattClient().launchServiceDiscovery = %d\r\n", ret);
edamame22 0:29983394c6b6 245 }
edamame22 0:29983394c6b6 246 }
edamame22 0:29983394c6b6 247
edamame22 0:29983394c6b6 248 //ASHOK's triggerRead function
edamame22 0:29983394c6b6 249
edamame22 0:29983394c6b6 250 void triggerRead(const GattReadCallbackParams *response) {
edamame22 1:8950e6a891df 251 int k=0;
edamame22 1:8950e6a891df 252 uint8_t dataforClient[4] = {0,0,0,0};
edamame22 1:8950e6a891df 253 uint32_t final_dataforClient = 0;
edamame22 0:29983394c6b6 254 for(int j=0; j<HUMIDITY+1; j++) {
edamame22 0:29983394c6b6 255 if (is_active[j]) {
edamame22 0:29983394c6b6 256 if (response->handle == bme280Characteristic[j].getValueHandle()){
edamame22 1:8950e6a891df 257 if ( response-> len > 4) {
edamame22 1:8950e6a891df 258 printf("response-> len is wrong :%d, %s, skipping read", response-> len, dbg_CharType[j]);
edamame22 1:8950e6a891df 259 break;
edamame22 1:8950e6a891df 260 }
edamame22 0:29983394c6b6 261 for(int i=0; i< response-> len; i++) {
edamame22 0:29983394c6b6 262 dataforClient[i] = response -> data[i];
edamame22 0:29983394c6b6 263 }
edamame22 1:8950e6a891df 264 printf("%d B, ", response->len);
edamame22 0:29983394c6b6 265 //BLE packet contains 4 bytes of 8 bit int's each. Combine all of them to form a single 32-bit int.
edamame22 0:29983394c6b6 266 final_dataforClient = ((uint32_t)dataforClient[3]<<24) | (dataforClient[2]<<16) | (dataforClient[1] << 8) | (dataforClient[0]);
edamame22 0:29983394c6b6 267 //Ren debug
edamame22 0:29983394c6b6 268 dataprint[j] = ( j==PRESSURE)? (float) final_dataforClient/10 : (float) final_dataforClient/100;
edamame22 0:29983394c6b6 269 demo1->set_bme280_value(dataprint[j], j);
edamame22 0:29983394c6b6 270 if (j==HUMIDITY) {
edamame22 0:29983394c6b6 271 k=0; printf("%s = %0.2f%% ", dbg_CharType[j], dataprint[j]);
edamame22 0:29983394c6b6 272 } else
edamame22 0:29983394c6b6 273 {
edamame22 0:29983394c6b6 274 k=j+1;
edamame22 0:29983394c6b6 275 if(j==PRESSURE) printf("%s = %0.1f hPa ", dbg_CharType[j], dataprint[j]);
edamame22 0:29983394c6b6 276 else printf("%s = %0.2f degC ", dbg_CharType[j], dataprint[j]);
edamame22 0:29983394c6b6 277 }
edamame22 0:29983394c6b6 278 break;
edamame22 0:29983394c6b6 279 }
edamame22 0:29983394c6b6 280 }
edamame22 0:29983394c6b6 281 }
edamame22 0:29983394c6b6 282 printf("\r\n");
edamame22 0:29983394c6b6 283 bme280Characteristic[k].read();
edamame22 0:29983394c6b6 284 }
edamame22 0:29983394c6b6 285
edamame22 0:29983394c6b6 286 // BLE disconnected
edamame22 0:29983394c6b6 287 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) {
edamame22 0:29983394c6b6 288 printf("BLE disconnected\r\n");
edamame22 0:29983394c6b6 289 /* Start scanning and try to connect again */
edamame22 0:29983394c6b6 290 BLE::Instance().gap().startScan(advertisementCallback);
edamame22 0:29983394c6b6 291 }
edamame22 0:29983394c6b6 292
edamame22 0:29983394c6b6 293 void onBleInitError(BLE &ble, ble_error_t error)
edamame22 0:29983394c6b6 294 {
edamame22 0:29983394c6b6 295 /* Initialization error handling should go here */
edamame22 0:29983394c6b6 296 printf("BLE Error = %u\r\n", error);
edamame22 0:29983394c6b6 297 }
edamame22 0:29983394c6b6 298
edamame22 0:29983394c6b6 299 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
edamame22 0:29983394c6b6 300 {
edamame22 0:29983394c6b6 301 printf("I'm inside BLE init Complete\r\n");
edamame22 0:29983394c6b6 302 BLE& ble = params->ble;
edamame22 0:29983394c6b6 303 ble_error_t error = params->error;
edamame22 0:29983394c6b6 304
edamame22 0:29983394c6b6 305 if (error != BLE_ERROR_NONE) {
edamame22 0:29983394c6b6 306 /* In case of error, forward the error handling to onBleInitError */
edamame22 0:29983394c6b6 307 onBleInitError(ble, error);
edamame22 0:29983394c6b6 308 return;
edamame22 0:29983394c6b6 309 }
edamame22 0:29983394c6b6 310
edamame22 0:29983394c6b6 311 /* Ensure that it is the default instance of BLE */
edamame22 0:29983394c6b6 312 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
edamame22 0:29983394c6b6 313 printf("Not the default instance\r\n");
edamame22 0:29983394c6b6 314 return;
edamame22 0:29983394c6b6 315 }
edamame22 0:29983394c6b6 316
edamame22 0:29983394c6b6 317 // Ren, clear discovered Characteristic at beginning
edamame22 0:29983394c6b6 318 for(int i=0; i<HUMIDITY+1; i++) {
edamame22 0:29983394c6b6 319 dataprint[i]=0.0; is_active[i]=false;
edamame22 0:29983394c6b6 320 }
edamame22 0:29983394c6b6 321
edamame22 0:29983394c6b6 322 ble.gap().onDisconnection(disconnectionCallback);
edamame22 0:29983394c6b6 323 ble.gap().onConnection(connectionCallback);
edamame22 0:29983394c6b6 324
edamame22 0:29983394c6b6 325 // On reading data, call triggerRead function.
edamame22 0:29983394c6b6 326 ble.gattClient().onDataRead(triggerRead);
edamame22 0:29983394c6b6 327
edamame22 0:29983394c6b6 328 // scan interval: 400ms and scan window: 400ms.
edamame22 0:29983394c6b6 329 // Every 400ms the device will scan for 400ms
edamame22 0:29983394c6b6 330 // This means that the device will scan continuously.
edamame22 0:29983394c6b6 331 ble.gap().setScanParams(400, 400);
edamame22 0:29983394c6b6 332 error = ble.gap().startScan(advertisementCallback);
edamame22 0:29983394c6b6 333 printf("BLE Error startScan = %u\r\n", error);
edamame22 0:29983394c6b6 334
edamame22 0:29983394c6b6 335 }
edamame22 0:29983394c6b6 336
edamame22 0:29983394c6b6 337 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
edamame22 0:29983394c6b6 338 BLE &ble = BLE::Instance();
edamame22 0:29983394c6b6 339 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
edamame22 0:29983394c6b6 340 }
edamame22 0:29983394c6b6 341
edamame22 0:29983394c6b6 342 /************************************************************BLE Stuff to here *********************************/
edamame22 0:29983394c6b6 343
edamame22 0:29983394c6b6 344 void blinky() {
edamame22 0:29983394c6b6 345 green_led = !green_led;
edamame22 0:29983394c6b6 346 }
edamame22 0:29983394c6b6 347
edamame22 0:29983394c6b6 348 // These are example resource values for the Device Object
edamame22 0:29983394c6b6 349 struct MbedClientDevice device = {
edamame22 0:29983394c6b6 350 "Manufacturer_String", // Manufacturer
edamame22 0:29983394c6b6 351 "Type_String", // Type
edamame22 0:29983394c6b6 352 "ModelNumber_String", // ModelNumber
edamame22 0:29983394c6b6 353 "SerialNumber_String" // SerialNumber
edamame22 0:29983394c6b6 354 };
edamame22 0:29983394c6b6 355
edamame22 0:29983394c6b6 356 // Instantiate the class which implements LWM2M Client API (from simpleclient.h)
edamame22 0:29983394c6b6 357 MbedClient mbed_client(device);
edamame22 0:29983394c6b6 358
edamame22 0:29983394c6b6 359 // Network interaction must be performed outside of interrupt context
edamame22 0:29983394c6b6 360 Semaphore updates(0);
edamame22 0:29983394c6b6 361 volatile bool registered = false;
edamame22 0:29983394c6b6 362 volatile bool clicked = false;
edamame22 0:29983394c6b6 363 osThreadId mainThread;
edamame22 0:29983394c6b6 364
edamame22 0:29983394c6b6 365 #ifdef TARGET_K64F
edamame22 0:29983394c6b6 366 // Set up Hardware interrupt button.
edamame22 0:29983394c6b6 367 InterruptIn obs_button(SW2);
edamame22 0:29983394c6b6 368 InterruptIn unreg_button(SW3);
edamame22 0:29983394c6b6 369 #else
edamame22 0:29983394c6b6 370 //In non K64F boards , set up a timer to simulate updating resource,
edamame22 0:29983394c6b6 371 // there is no functionality to unregister.
edamame22 0:29983394c6b6 372 Ticker timer;
edamame22 0:29983394c6b6 373 #endif
edamame22 0:29983394c6b6 374
edamame22 0:29983394c6b6 375 /*
edamame22 0:29983394c6b6 376 * The button contains one property (click count).
edamame22 0:29983394c6b6 377 * When `handle_button_click` is executed, the counter updates.
edamame22 0:29983394c6b6 378 */
edamame22 0:29983394c6b6 379 class ButtonResource {
edamame22 0:29983394c6b6 380 public:
edamame22 0:29983394c6b6 381 ButtonResource(): counter(0) {
edamame22 0:29983394c6b6 382 // create ObjectID with metadata tag of 'BTN_SW2', which is 'digital input'
edamame22 0:29983394c6b6 383 btn_object = M2MInterfaceFactory::create_object("BTN_SW2");
edamame22 0:29983394c6b6 384 M2MObjectInstance* btn_inst = btn_object->create_object_instance();
edamame22 0:29983394c6b6 385 // create resource with ID '5501', which is digital input counter
edamame22 0:29983394c6b6 386 M2MResource* btn_res = btn_inst->create_dynamic_resource("5501", "Button",
edamame22 0:29983394c6b6 387 M2MResourceInstance::INTEGER, true /* observable */);
edamame22 0:29983394c6b6 388 // we can read this value
edamame22 0:29983394c6b6 389 btn_res->set_operation(M2MBase::GET_ALLOWED);
edamame22 0:29983394c6b6 390 // set initial value (all values in mbed Client are buffers)
edamame22 0:29983394c6b6 391 // to be able to read this data easily in the Connector console, we'll use a string
edamame22 0:29983394c6b6 392 btn_res->set_value((uint8_t*)"0", 1);
edamame22 0:29983394c6b6 393 }
edamame22 0:29983394c6b6 394
edamame22 0:29983394c6b6 395 ~ButtonResource() {
edamame22 0:29983394c6b6 396 }
edamame22 0:29983394c6b6 397
edamame22 0:29983394c6b6 398 M2MObject* get_object() {
edamame22 0:29983394c6b6 399 return btn_object;
edamame22 0:29983394c6b6 400 }
edamame22 0:29983394c6b6 401
edamame22 0:29983394c6b6 402 /*
edamame22 0:29983394c6b6 403 * When you press the button, we read the current value of the click counter
edamame22 0:29983394c6b6 404 * from mbed Device Connector, then up the value with one.
edamame22 0:29983394c6b6 405 */
edamame22 0:29983394c6b6 406 void handle_button_click() {
edamame22 0:29983394c6b6 407 M2MObjectInstance* inst = btn_object->object_instance();
edamame22 0:29983394c6b6 408 M2MResource* res = inst->resource("5501");
edamame22 0:29983394c6b6 409
edamame22 0:29983394c6b6 410 // up counter
edamame22 0:29983394c6b6 411 counter++;
edamame22 0:29983394c6b6 412 printf("handle_button_click, new value of counter is %d\r\n", counter);
edamame22 0:29983394c6b6 413 // serialize the value of counter as a string, and tell connector
edamame22 0:29983394c6b6 414 char buffer[20];
edamame22 0:29983394c6b6 415 int size = sprintf(buffer,"%d",counter);
edamame22 0:29983394c6b6 416 res->set_value((uint8_t*)buffer, size);
edamame22 0:29983394c6b6 417 }
edamame22 0:29983394c6b6 418
edamame22 0:29983394c6b6 419 private:
edamame22 0:29983394c6b6 420 M2MObject* btn_object;
edamame22 0:29983394c6b6 421 uint16_t counter;
edamame22 0:29983394c6b6 422 };
edamame22 0:29983394c6b6 423
edamame22 0:29983394c6b6 424
edamame22 0:29983394c6b6 425 void unregister() {
edamame22 0:29983394c6b6 426 registered = false;
edamame22 0:29983394c6b6 427 updates.release();
edamame22 0:29983394c6b6 428 }
edamame22 0:29983394c6b6 429
edamame22 0:29983394c6b6 430 void button_clicked() {
edamame22 0:29983394c6b6 431 clicked = true;
edamame22 0:29983394c6b6 432 updates.release();
edamame22 0:29983394c6b6 433 }
edamame22 0:29983394c6b6 434
edamame22 0:29983394c6b6 435 // debug printf function
edamame22 0:29983394c6b6 436 void trace_printer(const char* str) {
edamame22 0:29983394c6b6 437 printf("%s\r\n", str);
edamame22 0:29983394c6b6 438 }
edamame22 0:29983394c6b6 439
edamame22 0:29983394c6b6 440 /****************************************************************More BLE Stuff from here****************/
edamame22 0:29983394c6b6 441 //BLE thread init and further calls to other BLE methods.
edamame22 0:29983394c6b6 442 void BLE_thread_init(void){
edamame22 0:29983394c6b6 443 printf("I'm inside BLE thread_init.....\r\n");
edamame22 0:29983394c6b6 444 eventQueue.call_every(500, blinky);
edamame22 0:29983394c6b6 445 //Schedule events before starting the thread since there might be some missed events while scanning / pairing.
edamame22 0:29983394c6b6 446 ble.onEventsToProcess(scheduleBleEventsProcessing);
edamame22 0:29983394c6b6 447 ble.init(bleInitComplete);
edamame22 0:29983394c6b6 448 //Loop forever the BLE thread
edamame22 0:29983394c6b6 449 eventQueue.dispatch_forever();
edamame22 0:29983394c6b6 450 }
edamame22 0:29983394c6b6 451
edamame22 0:29983394c6b6 452 /****************************************************************More BLE Stuff to here****************/
edamame22 0:29983394c6b6 453
edamame22 0:29983394c6b6 454 // Entry point to the program
edamame22 0:29983394c6b6 455 int main() {
edamame22 0:29983394c6b6 456
edamame22 0:29983394c6b6 457 unsigned int seed;
edamame22 0:29983394c6b6 458 size_t len;
edamame22 0:29983394c6b6 459
edamame22 0:29983394c6b6 460 //Create a new thread for BLE
edamame22 0:29983394c6b6 461 Thread BLE_thread;
edamame22 0:29983394c6b6 462
edamame22 0:29983394c6b6 463
edamame22 0:29983394c6b6 464 #ifdef MBEDTLS_ENTROPY_HARDWARE_ALT
edamame22 0:29983394c6b6 465 // Used to randomize source port
edamame22 0:29983394c6b6 466 mbedtls_hardware_poll(NULL, (unsigned char *) &seed, sizeof seed, &len);
edamame22 0:29983394c6b6 467
edamame22 0:29983394c6b6 468 #elif defined MBEDTLS_TEST_NULL_ENTROPY
edamame22 0:29983394c6b6 469
edamame22 0:29983394c6b6 470 #warning "mbedTLS security feature is disabled. Connection will not be secure !! Implement proper hardware entropy for your selected hardware."
edamame22 0:29983394c6b6 471 // Used to randomize source port
edamame22 0:29983394c6b6 472 mbedtls_null_entropy_poll( NULL,(unsigned char *) &seed, sizeof seed, &len);
edamame22 0:29983394c6b6 473
edamame22 0:29983394c6b6 474 #else
edamame22 0:29983394c6b6 475
edamame22 0:29983394c6b6 476 #error "This hardware does not have entropy, endpoint will not register to Connector.\
edamame22 0:29983394c6b6 477 You need to enable NULL ENTROPY for your application, but if this configuration change is made then no security is offered by mbed TLS.\
edamame22 0:29983394c6b6 478 Add MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES and MBEDTLS_TEST_NULL_ENTROPY in mbed_app.json macros to register your endpoint."
edamame22 0:29983394c6b6 479
edamame22 0:29983394c6b6 480 #endif
edamame22 0:29983394c6b6 481
edamame22 0:29983394c6b6 482 srand(seed);
edamame22 0:29983394c6b6 483 red_led = 1;
edamame22 0:29983394c6b6 484 blue_led = 1;
edamame22 0:29983394c6b6 485 status_ticker.attach_us(blinky, 250000);
edamame22 0:29983394c6b6 486 // Keep track of the main thread
edamame22 0:29983394c6b6 487 mainThread = osThreadGetId();
edamame22 0:29983394c6b6 488
edamame22 0:29983394c6b6 489 // Sets the console baud-rate
edamame22 0:29983394c6b6 490 output.baud(9600);
edamame22 0:29983394c6b6 491
edamame22 0:29983394c6b6 492 output.printf("Starting mbed Client example...\r\n");
edamame22 0:29983394c6b6 493
edamame22 0:29983394c6b6 494 mbed_trace_init();
edamame22 0:29983394c6b6 495 mbed_trace_print_function_set(trace_printer);
edamame22 0:29983394c6b6 496 NetworkInterface *network_interface = 0;
edamame22 0:29983394c6b6 497 int connect_success = -1;
edamame22 0:29983394c6b6 498 #if MBED_CONF_APP_NETWORK_INTERFACE == WIFI
edamame22 0:29983394c6b6 499 output.printf("\n\rUsing WiFi \r\n");
edamame22 0:29983394c6b6 500 output.printf("\n\rConnecting to WiFi..\r\n");
edamame22 0:29983394c6b6 501 connect_success = esp.connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD);
edamame22 0:29983394c6b6 502 network_interface = &esp;
edamame22 0:29983394c6b6 503 #elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET
edamame22 0:29983394c6b6 504 output.printf("Using Ethernet\r\n");
edamame22 0:29983394c6b6 505 connect_success = eth.connect();
edamame22 0:29983394c6b6 506 network_interface = &eth;
edamame22 0:29983394c6b6 507 #endif
edamame22 0:29983394c6b6 508 #ifdef MESH
edamame22 0:29983394c6b6 509 output.printf("Using Mesh\r\n");
edamame22 0:29983394c6b6 510 output.printf("\n\rConnecting to Mesh..\r\n");
edamame22 0:29983394c6b6 511 mesh.initialize(&rf_phy);
edamame22 0:29983394c6b6 512 connect_success = mesh.connect();
edamame22 0:29983394c6b6 513 network_interface = &mesh;
edamame22 0:29983394c6b6 514 #endif
edamame22 0:29983394c6b6 515 if(connect_success == 0) {
edamame22 0:29983394c6b6 516 output.printf("\n\rConnected to Network successfully\r\n");
edamame22 0:29983394c6b6 517 } else {
edamame22 0:29983394c6b6 518 output.printf("\n\rConnection to Network Failed %d! Exiting application....\r\n", connect_success);
edamame22 0:29983394c6b6 519 return 0;
edamame22 0:29983394c6b6 520 }
edamame22 0:29983394c6b6 521 const char *ip_addr = network_interface->get_ip_address();
edamame22 0:29983394c6b6 522 if (ip_addr) {
edamame22 0:29983394c6b6 523 output.printf("IP address %s\r\n", ip_addr);
edamame22 0:29983394c6b6 524 } else {
edamame22 0:29983394c6b6 525 output.printf("No IP address\r\n");
edamame22 0:29983394c6b6 526 }
edamame22 0:29983394c6b6 527
edamame22 0:29983394c6b6 528 // create our button resources
edamame22 0:29983394c6b6 529 ButtonResource button_resource;
edamame22 0:29983394c6b6 530 #ifdef TARGET_K64F
edamame22 0:29983394c6b6 531 // On press of SW3 button on K64F board, example application
edamame22 0:29983394c6b6 532 // will call unregister API towards mbed Device Connector
edamame22 0:29983394c6b6 533 //unreg_button.fall(&mbed_client,&MbedClient::test_unregister);
edamame22 0:29983394c6b6 534 unreg_button.fall(&unregister);
edamame22 0:29983394c6b6 535
edamame22 0:29983394c6b6 536 // Observation Button (SW2) press will send update of endpoint resource values to connector
edamame22 0:29983394c6b6 537 obs_button.fall(&button_clicked);
edamame22 0:29983394c6b6 538 #else
edamame22 0:29983394c6b6 539 // Send update of endpoint resource values to connector every 5 seconds periodically
edamame22 0:29983394c6b6 540 timer.attach(&button_clicked, 5.0);
edamame22 0:29983394c6b6 541 #endif
edamame22 0:29983394c6b6 542
edamame22 0:29983394c6b6 543 // Create endpoint interface to manage register and unregister
edamame22 0:29983394c6b6 544 mbed_client.create_interface(MBED_SERVER_ADDRESS, network_interface);
edamame22 0:29983394c6b6 545
edamame22 0:29983394c6b6 546 // Create Objects of varying types, see simpleclient.h for more details on implementation.
edamame22 0:29983394c6b6 547 M2MSecurity* register_object = mbed_client.create_register_object(); // server object specifying connector info
edamame22 0:29983394c6b6 548 M2MDevice* device_object = mbed_client.create_device_object(); // device resources object
edamame22 0:29983394c6b6 549
edamame22 0:29983394c6b6 550 // Create list of Objects to register
edamame22 0:29983394c6b6 551 M2MObjectList object_list;
edamame22 0:29983394c6b6 552
edamame22 0:29983394c6b6 553 // Add objects to list
edamame22 0:29983394c6b6 554 object_list.push_back(device_object);
edamame22 0:29983394c6b6 555 object_list.push_back(button_resource.get_object());
edamame22 0:29983394c6b6 556 // add bme280 data objects
edamame22 0:29983394c6b6 557 if (demo1==NULL) {
edamame22 0:29983394c6b6 558 // Create bme280 instance
edamame22 0:29983394c6b6 559 demo1=new BME280Resource();
edamame22 0:29983394c6b6 560 printf("created bme280 instance now!!\r\n");
edamame22 0:29983394c6b6 561 }
edamame22 0:29983394c6b6 562 object_list.push_back(demo1->get_object(PRESSURE));
edamame22 0:29983394c6b6 563 object_list.push_back(demo1->get_object(TEMPERATURE));
edamame22 0:29983394c6b6 564 object_list.push_back(demo1->get_object(HUMIDITY));
edamame22 0:29983394c6b6 565
edamame22 0:29983394c6b6 566 // Set endpoint registration object
edamame22 0:29983394c6b6 567 mbed_client.set_register_object(register_object);
edamame22 0:29983394c6b6 568
edamame22 0:29983394c6b6 569 // Register with mbed Device Connector
edamame22 0:29983394c6b6 570 mbed_client.test_register(register_object, object_list);
edamame22 0:29983394c6b6 571 registered = true;
edamame22 0:29983394c6b6 572
edamame22 0:29983394c6b6 573 //Start BLE thread after connection is established to device connector. Else, there is conflict.
edamame22 0:29983394c6b6 574 BLE_thread.start(BLE_thread_init);
edamame22 0:29983394c6b6 575 // waiting for completion of BLE_thread_init
edamame22 0:29983394c6b6 576 Thread::wait(2000);
edamame22 0:29983394c6b6 577 while (true) {
edamame22 0:29983394c6b6 578
edamame22 0:29983394c6b6 579 printf("inside main for client\r\n");
edamame22 0:29983394c6b6 580 triggerLedCharacteristic = false;
edamame22 0:29983394c6b6 581
edamame22 0:29983394c6b6 582 updates.wait(25000);
edamame22 0:29983394c6b6 583 if(registered) {
edamame22 0:29983394c6b6 584 if(!clicked) {
edamame22 0:29983394c6b6 585 //printf("Inside registered ... clicked \r\n");
edamame22 0:29983394c6b6 586 mbed_client.test_update_register();
edamame22 0:29983394c6b6 587 }
edamame22 0:29983394c6b6 588 } else { // not registered, then stop;
edamame22 0:29983394c6b6 589 break;
edamame22 0:29983394c6b6 590 }
edamame22 0:29983394c6b6 591 if(clicked) {
edamame22 0:29983394c6b6 592 clicked = false;
edamame22 0:29983394c6b6 593 button_resource.handle_button_click();
edamame22 0:29983394c6b6 594 }
edamame22 0:29983394c6b6 595
edamame22 0:29983394c6b6 596 }
edamame22 0:29983394c6b6 597
edamame22 0:29983394c6b6 598 mbed_client.test_unregister();
edamame22 0:29983394c6b6 599 status_ticker.detach();
edamame22 0:29983394c6b6 600 }