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/

Revision:
0:29983394c6b6
Child:
1:8950e6a891df
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Apr 13 04:48:11 2017 +0000
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2015 ARM Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "simpleclient.h"
+#include <string>
+#include <sstream>
+#include <vector>
+#include "mbed-trace/mbed_trace.h"
+#include "mbedtls/entropy_poll.h"
+
+#include <events/mbed_events.h>
+#include <mbed.h>
+#include "ble/BLE.h"
+#include "ble/DiscoveredCharacteristic.h"
+#include "ble/DiscoveredService.h"
+
+#include "security.h"
+
+#include "mbed.h"
+#include "rtos.h"
+
+#if MBED_CONF_APP_NETWORK_INTERFACE == WIFI
+#include "ESP8266Interface.h"
+ESP8266Interface esp(MBED_CONF_APP_WIFI_TX, MBED_CONF_APP_WIFI_RX);
+#elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET
+#include "EthernetInterface.h"
+EthernetInterface eth;
+#elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_LOWPAN_ND
+#define MESH
+#include "NanostackInterface.h"
+LoWPANNDInterface mesh;
+#elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_THREAD
+#define MESH
+#include "NanostackInterface.h"
+ThreadInterface mesh;
+#endif
+
+#if defined(MESH)
+#if MBED_CONF_APP_MESH_RADIO_TYPE == ATMEL
+#include "NanostackRfPhyAtmel.h"
+NanostackRfPhyAtmel rf_phy(ATMEL_SPI_MOSI, ATMEL_SPI_MISO, ATMEL_SPI_SCLK, ATMEL_SPI_CS,
+                           ATMEL_SPI_RST, ATMEL_SPI_SLP, ATMEL_SPI_IRQ, ATMEL_I2C_SDA, ATMEL_I2C_SCL);
+#elif MBED_CONF_APP_MESH_RADIO_TYPE == MCR20
+#include "NanostackRfPhyMcr20a.h"
+NanostackRfPhyMcr20a rf_phy(MCR20A_SPI_MOSI, MCR20A_SPI_MISO, MCR20A_SPI_SCLK, MCR20A_SPI_CS, MCR20A_SPI_RST, MCR20A_SPI_IRQ);
+#endif //MBED_CONF_APP_RADIO_TYPE
+#endif //MESH
+
+#ifndef MESH
+// This is address to mbed Device Connector
+#define MBED_SERVER_ADDRESS "coap://api.connector.mbed.com:5684"
+#else
+// This is address to mbed Device Connector
+#define MBED_SERVER_ADDRESS "coaps://[2607:f0d0:2601:52::20]:5684"
+#endif
+
+Serial output(USBTX, USBRX);
+
+// Status indication
+DigitalOut red_led(LED1);
+DigitalOut green_led(LED2);
+DigitalOut blue_led(LED3);
+Ticker status_ticker;
+// Ren, begin
+enum charType {
+	PRESSURE,
+	TEMPERATURE,
+	HUMIDITY
+};
+const char * dbg_CharType[HUMIDITY+1]={"Pressure","Temperature","Humidity"};
+const char * objName[HUMIDITY+1]={"3323","3303","3304"};
+static bool is_active[HUMIDITY+1];
+static float dataprint[HUMIDITY+1]={0,0,0};
+/*
+ * The BME280 sensor contains 3 float properties.
+ * Those are updated once BLE Gatt client read the values.
+ */
+class BME280Resource {
+public:
+    BME280Resource() {
+    	// create Pressure object '3323'.
+        for(int m=0; m<HUMIDITY+1; m++) {
+            bme280[m] = M2MInterfaceFactory::create_object(objName[m]);
+            tmp_inst[m] = bme280[m] ->create_object_instance();
+            tmp_res[m] = tmp_inst[m]->create_dynamic_resource("5700", dbg_CharType[m],
+                    M2MResourceInstance::STRING, true /* observable */);
+            tmp_res[m]->set_operation(M2MBase::GET_ALLOWED);
+            tmp_res[m]->set_value((uint8_t*)"0.0", 3);
+        }
+    }
+
+    void set_bme280_value(float val, int h){
+        char tmp_buf[50];
+        int len;
+        if (h<PRESSURE || h>HUMIDITY) {
+            printf("data type h (input) is wrong!!");
+            return;
+        }
+        if (h==HUMIDITY)
+            len=sprintf(tmp_buf,"%0.2f%%",val);
+        else if (h==PRESSURE)
+            len=sprintf(tmp_buf,"%0.1f hPa",val);
+        else
+            len=sprintf(tmp_buf,"%0.2f degC",val);
+
+        tmp_res[h]->set_value((uint8_t*)tmp_buf, len);
+        //printf("set_value(tmp_bug=%s\r\n", tmp_buf);
+    }
+
+
+    M2MObject* get_object(int idx) {
+        if (idx<PRESSURE || idx>HUMIDITY)    return NULL;
+        return bme280[idx];
+    }
+private:
+    M2MObject*  bme280[HUMIDITY+1];
+    M2MObjectInstance* tmp_inst[HUMIDITY+1];
+    M2MResource* tmp_res[HUMIDITY+1];
+};
+
+static BME280Resource *demo1;
+// Ren, end
+
+/************************************************************BLE Stuff from here *********************************/
+BLE &ble = BLE::Instance();
+static DiscoveredCharacteristic bme280Characteristic[HUMIDITY+1];
+static bool triggerLedCharacteristic;
+static const char PEER_NAME[] = "BME280";
+uint16_t payload_length = 0;
+uint8_t dataforClient[] = {0};
+uint32_t final_dataforClient = 0;
+
+static EventQueue eventQueue(
+    /* event count */ 16 * /* event size */ 32
+);
+
+void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) {
+    // parse the advertising payload, looking for data type COMPLETE_LOCAL_NAME
+    // The advertising payload is a collection of key/value records where
+    // byte 0: length of the record excluding this byte
+    // byte 1: The key, it is the type of the data
+    // byte [2..N] The value. N is equal to byte0 - 1
+
+  	//printf("Starting advertisementCallback...\r\n");
+    for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
+
+        const uint8_t record_length = params->advertisingData[i];
+        if (record_length == 0) {
+            continue;
+        }
+        const uint8_t type = params->advertisingData[i + 1];
+        const uint8_t* value = params->advertisingData + i + 2;
+        const uint8_t value_length = record_length - 1;
+
+        if (type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
+            if ((value_length == sizeof(PEER_NAME)) && (memcmp(value, PEER_NAME, value_length) == 0)) {
+                printf(
+                    "adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
+                    params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2],
+                    params->peerAddr[1], params->peerAddr[0], params->rssi, params->isScanResponse, params->type
+                );
+                BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
+                break;
+            }
+        }
+        i += record_length;
+    }
+}
+
+void serviceDiscoveryCallback(const DiscoveredService *service) {
+    if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
+        printf("S type short UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
+    } else {
+        printf("S type long UUID-");
+        const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
+        for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
+            printf("%02x", longUUIDBytes[i]);
+        }
+        printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
+    }
+}
+
+/***
+    This function called read() initially, following read() calls
+    are repeated inside triggerRead function
+***/
+void updateLedCharacteristic(void) {
+    if (!BLE::Instance().gattClient().isServiceDiscoveryActive()) {
+        //printf("02  updateLedCharacteristic\n");
+        for(int g=0; g<HUMIDITY+1; g++) {
+            if (is_active[g])    bme280Characteristic[g].read();
+        }
+    }
+}
+
+
+void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
+    int tmp_uuid;
+    tmp_uuid=characteristicP->getUUID().getShortUUID();
+    printf("  C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
+    if ((tmp_uuid < GattCharacteristic::UUID_PRESSURE_CHAR) ||
+        (tmp_uuid > GattCharacteristic::UUID_HUMIDITY_CHAR))     return;
+    triggerLedCharacteristic = true;
+    if (tmp_uuid == GattCharacteristic::UUID_PRESSURE_CHAR) {
+        bme280Characteristic[PRESSURE] = *characteristicP;    is_active[PRESSURE] = true;
+        printf(" is_active[PRESSURE] = true\r\n");
+    }
+    else if (tmp_uuid == GattCharacteristic::UUID_TEMPERATURE_CHAR) {
+    	  bme280Characteristic[TEMPERATURE] = *characteristicP;    is_active[TEMPERATURE] = true;
+    	  printf(" is_active[TEMPERATURE] = true\r\n");
+   } else {
+        bme280Characteristic[HUMIDITY] = *characteristicP;    is_active[HUMIDITY] = true;
+        printf(" is_active[HUMIDITY] = true\r\n");
+   }
+}
+
+void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
+    printf("terminated SD for handle %u\r\n", connectionHandle);
+    if (triggerLedCharacteristic) {
+        triggerLedCharacteristic = false;
+        eventQueue.call(updateLedCharacteristic);
+    }
+}
+
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
+    int ret;
+    printf("Connected to BME280 now...\r\n");
+    if (params->role == Gap::CENTRAL) {
+        BLE &ble = BLE::Instance();
+        ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
+        // Ren, connect to ENVIRONMENT service
+        ret=ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, GattService::UUID_ENVIRONMENTAL_SERVICE);
+        printf("ble.gattClient().launchServiceDiscovery = %d\r\n", ret);
+    }
+}
+
+//ASHOK's triggerRead function
+
+void triggerRead(const GattReadCallbackParams *response) {
+    int k;
+    for(int j=0; j<HUMIDITY+1; j++) {
+        if (is_active[j]) {
+            if (response->handle == bme280Characteristic[j].getValueHandle()){
+                payload_length = response-> len;
+                for(int i=0; i< response-> len; i++) {
+                    dataforClient[i] = response -> data[i];
+                }
+                //BLE packet contains 4 bytes of 8 bit int's each. Combine all of them to form a single 32-bit int.
+                final_dataforClient = ((uint32_t)dataforClient[3]<<24) | (dataforClient[2]<<16) | (dataforClient[1] << 8) | (dataforClient[0]);
+                //Ren debug
+                dataprint[j] = ( j==PRESSURE)?   (float) final_dataforClient/10 : (float) final_dataforClient/100;
+                demo1->set_bme280_value(dataprint[j], j);
+                if (j==HUMIDITY) {
+                    k=0;   printf("%s  = %0.2f%%   ", dbg_CharType[j], dataprint[j]);
+                } else
+                {
+                    k=j+1;
+                    if(j==PRESSURE)    printf("%s  = %0.1f hPa   ", dbg_CharType[j], dataprint[j]);
+                    else   printf("%s  = %0.2f degC   ", dbg_CharType[j], dataprint[j]);
+                }
+                break;
+            }
+        }
+    }
+    printf("\r\n");
+    bme280Characteristic[k].read();
+}
+
+// BLE disconnected
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) {
+    printf("BLE disconnected\r\n");
+    /* Start scanning and try to connect again */
+    BLE::Instance().gap().startScan(advertisementCallback);
+}
+
+void onBleInitError(BLE &ble, ble_error_t error)
+{
+    /* Initialization error handling should go here */
+    printf("BLE Error = %u\r\n", error);
+}
+
+void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
+{
+    printf("I'm inside BLE init Complete\r\n");
+    BLE&        ble   = params->ble;
+    ble_error_t error = params->error;
+
+    if (error != BLE_ERROR_NONE) {
+        /* In case of error, forward the error handling to onBleInitError */
+        onBleInitError(ble, error);
+        return;
+    }
+
+    /* Ensure that it is the default instance of BLE */
+    if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
+        printf("Not the default instance\r\n");
+        return;
+    }
+
+    // Ren, clear discovered Characteristic at beginning
+    for(int i=0; i<HUMIDITY+1; i++)   {
+    	  dataprint[i]=0.0;     is_active[i]=false;
+    }
+
+    ble.gap().onDisconnection(disconnectionCallback);
+    ble.gap().onConnection(connectionCallback);
+
+    // On reading data, call triggerRead function.
+    ble.gattClient().onDataRead(triggerRead);
+
+    // scan interval: 400ms and scan window: 400ms.
+    // Every 400ms the device will scan for 400ms
+    // This means that the device will scan continuously.
+    ble.gap().setScanParams(400, 400);
+    error =   ble.gap().startScan(advertisementCallback);
+    printf("BLE Error startScan = %u\r\n", error);
+
+}
+
+void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
+    BLE &ble = BLE::Instance();
+    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
+}
+
+/************************************************************BLE Stuff to here *********************************/
+
+void blinky() {
+    green_led = !green_led;
+}
+
+// These are example resource values for the Device Object
+struct MbedClientDevice device = {
+    "Manufacturer_String",      // Manufacturer
+    "Type_String",              // Type
+    "ModelNumber_String",       // ModelNumber
+    "SerialNumber_String"       // SerialNumber
+};
+
+// Instantiate the class which implements LWM2M Client API (from simpleclient.h)
+MbedClient mbed_client(device);
+
+// Network interaction must be performed outside of interrupt context
+Semaphore updates(0);
+volatile bool registered = false;
+volatile bool clicked = false;
+osThreadId mainThread;
+
+#ifdef TARGET_K64F
+// Set up Hardware interrupt button.
+InterruptIn obs_button(SW2);
+InterruptIn unreg_button(SW3);
+#else
+//In non K64F boards , set up a timer to simulate updating resource,
+// there is no functionality to unregister.
+Ticker timer;
+#endif
+
+/*
+ * The button contains one property (click count).
+ * When `handle_button_click` is executed, the counter updates.
+ */
+class ButtonResource {
+public:
+    ButtonResource(): counter(0) {
+        // create ObjectID with metadata tag of 'BTN_SW2', which is 'digital input'
+        btn_object = M2MInterfaceFactory::create_object("BTN_SW2");
+        M2MObjectInstance* btn_inst = btn_object->create_object_instance();
+        // create resource with ID '5501', which is digital input counter
+        M2MResource* btn_res = btn_inst->create_dynamic_resource("5501", "Button",
+            M2MResourceInstance::INTEGER, true /* observable */);
+        // we can read this value
+        btn_res->set_operation(M2MBase::GET_ALLOWED);
+        // set initial value (all values in mbed Client are buffers)
+        // to be able to read this data easily in the Connector console, we'll use a string
+        btn_res->set_value((uint8_t*)"0", 1);
+    }
+
+    ~ButtonResource() {
+    }
+
+    M2MObject* get_object() {
+        return btn_object;
+    }
+
+    /*
+     * When you press the button, we read the current value of the click counter
+     * from mbed Device Connector, then up the value with one.
+     */
+    void handle_button_click() {
+        M2MObjectInstance* inst = btn_object->object_instance();
+        M2MResource* res = inst->resource("5501");
+
+        // up counter
+        counter++;
+        printf("handle_button_click, new value of counter is %d\r\n", counter);
+        // serialize the value of counter as a string, and tell connector
+        char buffer[20];
+        int size = sprintf(buffer,"%d",counter);
+        res->set_value((uint8_t*)buffer, size);
+    }
+
+private:
+    M2MObject* btn_object;
+    uint16_t counter;
+};
+
+
+void unregister() {
+    registered = false;
+    updates.release();
+}
+
+void button_clicked() {
+    clicked = true;
+    updates.release();
+}
+
+// debug printf function
+void trace_printer(const char* str) {
+    printf("%s\r\n", str);
+}
+
+/****************************************************************More BLE Stuff from here****************/
+//BLE thread init and further calls to other BLE methods.
+void BLE_thread_init(void){
+    printf("I'm inside BLE thread_init.....\r\n");
+    eventQueue.call_every(500, blinky);
+    //Schedule events before starting the thread since there might be some missed events while scanning / pairing.
+    ble.onEventsToProcess(scheduleBleEventsProcessing);
+    ble.init(bleInitComplete);
+    //Loop forever the BLE thread
+    eventQueue.dispatch_forever();
+}
+
+/****************************************************************More BLE Stuff  to here****************/
+
+// Entry point to the program
+int main() {
+
+    unsigned int seed;
+    size_t len;
+
+    //Create a new thread for BLE
+    Thread BLE_thread;
+
+
+#ifdef MBEDTLS_ENTROPY_HARDWARE_ALT
+    // Used to randomize source port
+    mbedtls_hardware_poll(NULL, (unsigned char *) &seed, sizeof seed, &len);
+
+#elif defined MBEDTLS_TEST_NULL_ENTROPY
+
+#warning "mbedTLS security feature is disabled. Connection will not be secure !! Implement proper hardware entropy for your selected hardware."
+    // Used to randomize source port
+    mbedtls_null_entropy_poll( NULL,(unsigned char *) &seed, sizeof seed, &len);
+
+#else
+
+#error "This hardware does not have entropy, endpoint will not register to Connector.\
+You need to enable NULL ENTROPY for your application, but if this configuration change is made then no security is offered by mbed TLS.\
+Add MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES and MBEDTLS_TEST_NULL_ENTROPY in mbed_app.json macros to register your endpoint."
+
+#endif
+
+    srand(seed);
+    red_led = 1;
+    blue_led = 1;
+    status_ticker.attach_us(blinky, 250000);
+    // Keep track of the main thread
+    mainThread = osThreadGetId();
+
+    // Sets the console baud-rate
+    output.baud(9600);
+
+    output.printf("Starting mbed Client example...\r\n");
+
+    mbed_trace_init();
+    mbed_trace_print_function_set(trace_printer);
+    NetworkInterface *network_interface = 0;
+    int connect_success = -1;
+#if MBED_CONF_APP_NETWORK_INTERFACE == WIFI
+    output.printf("\n\rUsing WiFi \r\n");
+    output.printf("\n\rConnecting to WiFi..\r\n");
+    connect_success = esp.connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD);
+    network_interface = &esp;
+#elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET
+    output.printf("Using Ethernet\r\n");
+    connect_success = eth.connect();
+    network_interface = &eth;
+#endif
+#ifdef MESH
+    output.printf("Using Mesh\r\n");
+    output.printf("\n\rConnecting to Mesh..\r\n");
+    mesh.initialize(&rf_phy);
+    connect_success = mesh.connect();
+    network_interface = &mesh;
+#endif
+    if(connect_success == 0) {
+        output.printf("\n\rConnected to Network successfully\r\n");
+    } else {
+        output.printf("\n\rConnection to Network Failed %d! Exiting application....\r\n", connect_success);
+        return 0;
+    }
+    const char *ip_addr = network_interface->get_ip_address();
+    if (ip_addr) {
+        output.printf("IP address %s\r\n", ip_addr);
+    } else {
+        output.printf("No IP address\r\n");
+    }
+
+    // create our button resources
+    ButtonResource button_resource;
+#ifdef TARGET_K64F
+    // On press of SW3 button on K64F board, example application
+    // will call unregister API towards mbed Device Connector
+    //unreg_button.fall(&mbed_client,&MbedClient::test_unregister);
+    unreg_button.fall(&unregister);
+
+    // Observation Button (SW2) press will send update of endpoint resource values to connector
+    obs_button.fall(&button_clicked);
+#else
+    // Send update of endpoint resource values to connector every 5 seconds periodically
+    timer.attach(&button_clicked, 5.0);
+#endif
+
+    // Create endpoint interface to manage register and unregister
+    mbed_client.create_interface(MBED_SERVER_ADDRESS, network_interface);
+
+    // Create Objects of varying types, see simpleclient.h for more details on implementation.
+    M2MSecurity* register_object = mbed_client.create_register_object(); // server object specifying connector info
+    M2MDevice*   device_object   = mbed_client.create_device_object();   // device resources object
+
+    // Create list of Objects to register
+    M2MObjectList object_list;
+
+    // Add objects to list
+    object_list.push_back(device_object);
+    object_list.push_back(button_resource.get_object());
+    // add bme280 data objects
+    if (demo1==NULL)   {
+        //	Create bme280 instance
+        demo1=new BME280Resource();
+    	  printf("created bme280 instance now!!\r\n");
+    }
+    object_list.push_back(demo1->get_object(PRESSURE));
+    object_list.push_back(demo1->get_object(TEMPERATURE));
+    object_list.push_back(demo1->get_object(HUMIDITY));
+
+    // Set endpoint registration object
+    mbed_client.set_register_object(register_object);
+
+    // Register with mbed Device Connector
+    mbed_client.test_register(register_object, object_list);
+    registered = true;
+
+    //Start BLE thread after connection is established to device connector. Else, there is conflict.
+	  BLE_thread.start(BLE_thread_init);
+    // waiting for completion of BLE_thread_init
+    Thread::wait(2000);
+    while (true) {
+
+	      printf("inside main for client\r\n");
+        triggerLedCharacteristic = false;
+
+        updates.wait(25000);
+        if(registered) {
+            if(!clicked) {
+                //printf("Inside registered ... clicked \r\n");
+                mbed_client.test_update_register();
+            }
+        } else {   // not registered, then stop;
+            break;
+        }
+        if(clicked) {
+           clicked = false;
+           button_resource.handle_button_click();
+        }
+
+    }
+
+    mbed_client.test_unregister();
+    status_ticker.detach();
+}