An mbed BLE-to-Cloud Gateway using Nucleo-F429ZI+X-Nucleo-IDB05A1 or Nucleo-L476RG+X-Nucleo-IDB05A1+X-Nucleo-IDW01M1.
Information
Nucleo- F429ZI configuration requires two hardware patches:
- on Nucleo-F429ZI open SB121 and close SB122
- on X-Nucleo-IDB05A1 move R4 to R6
The BLE client searches for and connects to a MotEnv node.
main.cpp@1:d9c0c4889bd2, 2017-10-12 (annotated)
- Committer:
- nikapov
- Date:
- Thu Oct 12 17:28:58 2017 +0200
- Revision:
- 1:d9c0c4889bd2
- Parent:
- 0:c7083010ae49
- Child:
- 3:39c8d17bed52
Update easy-connect to support IDW01M1 Wi-Fi.
Add BLE Client code and environmental data support.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
nikapov | 0:c7083010ae49 | 1 | /* |
nikapov | 0:c7083010ae49 | 2 | * Copyright (c) 2015, 2016 ARM Limited. All rights reserved. |
nikapov | 0:c7083010ae49 | 3 | * SPDX-License-Identifier: Apache-2.0 |
nikapov | 0:c7083010ae49 | 4 | * Licensed under the Apache License, Version 2.0 (the License); you may |
nikapov | 0:c7083010ae49 | 5 | * not use this file except in compliance with the License. |
nikapov | 0:c7083010ae49 | 6 | * You may obtain a copy of the License at |
nikapov | 0:c7083010ae49 | 7 | * |
nikapov | 0:c7083010ae49 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
nikapov | 0:c7083010ae49 | 9 | * |
nikapov | 0:c7083010ae49 | 10 | * Unless required by applicable law or agreed to in writing, software |
nikapov | 0:c7083010ae49 | 11 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT |
nikapov | 0:c7083010ae49 | 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
nikapov | 0:c7083010ae49 | 13 | * See the License for the specific language governing permissions and |
nikapov | 0:c7083010ae49 | 14 | * limitations under the License. |
nikapov | 0:c7083010ae49 | 15 | */ |
nikapov | 0:c7083010ae49 | 16 | #define __STDC_FORMAT_MACROS |
nikapov | 0:c7083010ae49 | 17 | #include <inttypes.h> |
nikapov | 0:c7083010ae49 | 18 | #include "simpleclient.h" |
nikapov | 0:c7083010ae49 | 19 | #include <string> |
nikapov | 0:c7083010ae49 | 20 | #include <sstream> |
nikapov | 0:c7083010ae49 | 21 | #include <vector> |
nikapov | 0:c7083010ae49 | 22 | #include "mbed-trace/mbed_trace.h" |
nikapov | 0:c7083010ae49 | 23 | #include "mbedtls/entropy_poll.h" |
nikapov | 1:d9c0c4889bd2 | 24 | #include "ble\BLE.h" |
nikapov | 1:d9c0c4889bd2 | 25 | #include "ble\DiscoveredCharacteristic.h" |
nikapov | 1:d9c0c4889bd2 | 26 | #include "ble\DiscoveredService.h" |
nikapov | 1:d9c0c4889bd2 | 27 | |
nikapov | 0:c7083010ae49 | 28 | |
nikapov | 0:c7083010ae49 | 29 | #include "security.h" |
nikapov | 0:c7083010ae49 | 30 | |
nikapov | 0:c7083010ae49 | 31 | #include "mbed.h" |
nikapov | 0:c7083010ae49 | 32 | |
nikapov | 0:c7083010ae49 | 33 | // easy-connect compliancy, it has 2 sets of wifi pins we have only one |
nikapov | 0:c7083010ae49 | 34 | #define MBED_CONF_APP_ESP8266_TX MBED_CONF_APP_WIFI_TX |
nikapov | 0:c7083010ae49 | 35 | #define MBED_CONF_APP_ESP8266_RX MBED_CONF_APP_WIFI_RX |
nikapov | 1:d9c0c4889bd2 | 36 | #define MBED_CFG_SPWF01SA_TX MBED_CONF_APP_WIFI_TX |
nikapov | 1:d9c0c4889bd2 | 37 | #define MBED_CFG_SPWF01SA_RX MBED_CONF_APP_WIFI_RX |
nikapov | 0:c7083010ae49 | 38 | #include "easy-connect/easy-connect.h" |
nikapov | 0:c7083010ae49 | 39 | |
nikapov | 0:c7083010ae49 | 40 | #ifdef TARGET_STM |
nikapov | 0:c7083010ae49 | 41 | #define RED_LED (LED3) |
nikapov | 0:c7083010ae49 | 42 | #define GREEN_LED (LED1) |
nikapov | 0:c7083010ae49 | 43 | #define BLUE_LED (LED2) |
nikapov | 0:c7083010ae49 | 44 | #define LED_ON (1) |
nikapov | 0:c7083010ae49 | 45 | #else // !TARGET_STM |
nikapov | 0:c7083010ae49 | 46 | #define RED_LED (LED1) |
nikapov | 0:c7083010ae49 | 47 | #define GREEN_LED (LED2) |
nikapov | 0:c7083010ae49 | 48 | #define BLUE_LED (LED3) |
nikapov | 0:c7083010ae49 | 49 | #define LED_ON (0) |
nikapov | 0:c7083010ae49 | 50 | #endif // !TARGET_STM |
nikapov | 0:c7083010ae49 | 51 | #define LED_OFF (!LED_ON) |
nikapov | 0:c7083010ae49 | 52 | |
nikapov | 0:c7083010ae49 | 53 | // Status indication |
nikapov | 0:c7083010ae49 | 54 | DigitalOut red_led(RED_LED); |
nikapov | 0:c7083010ae49 | 55 | DigitalOut green_led(GREEN_LED); |
nikapov | 0:c7083010ae49 | 56 | DigitalOut blue_led(BLUE_LED); |
nikapov | 0:c7083010ae49 | 57 | |
nikapov | 1:d9c0c4889bd2 | 58 | |
nikapov | 1:d9c0c4889bd2 | 59 | /************************************************************BLE Stuff from here *********************************/ |
nikapov | 1:d9c0c4889bd2 | 60 | |
nikapov | 1:d9c0c4889bd2 | 61 | BLE &ble = BLE::Instance(); |
nikapov | 1:d9c0c4889bd2 | 62 | static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE); |
nikapov | 1:d9c0c4889bd2 | 63 | Thread BLE_thread; |
nikapov | 1:d9c0c4889bd2 | 64 | static bool triggerEnvCharacteristic; |
nikapov | 1:d9c0c4889bd2 | 65 | static bool envDataAvailable = false; |
nikapov | 1:d9c0c4889bd2 | 66 | static DiscoveredCharacteristic envCharacteristic; |
nikapov | 1:d9c0c4889bd2 | 67 | uint16_t payload_length = 0; |
nikapov | 1:d9c0c4889bd2 | 68 | uint8_t dataforClient[12]; |
nikapov | 1:d9c0c4889bd2 | 69 | |
nikapov | 1:d9c0c4889bd2 | 70 | void BLEConnect(BLEProtocol::AddressBytes_t address) { |
nikapov | 1:d9c0c4889bd2 | 71 | BLE::Instance().gap().connect(address, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL); |
nikapov | 1:d9c0c4889bd2 | 72 | } |
nikapov | 1:d9c0c4889bd2 | 73 | |
nikapov | 1:d9c0c4889bd2 | 74 | |
nikapov | 1:d9c0c4889bd2 | 75 | void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) { |
nikapov | 1:d9c0c4889bd2 | 76 | // parse the advertising payload, looking for data type MANUFACTURER_SPECIFIC_DATA |
nikapov | 1:d9c0c4889bd2 | 77 | // The advertising payload is a collection of key/value records where |
nikapov | 1:d9c0c4889bd2 | 78 | // byte 0: length of the record excluding this byte |
nikapov | 1:d9c0c4889bd2 | 79 | // byte 1: The key, it is the type of the data |
nikapov | 1:d9c0c4889bd2 | 80 | // byte [2..N] The value. N is equal to byte0 - 1 |
nikapov | 1:d9c0c4889bd2 | 81 | |
nikapov | 1:d9c0c4889bd2 | 82 | //printf("Starting advertisementCallback...\r\n"); |
nikapov | 1:d9c0c4889bd2 | 83 | |
nikapov | 1:d9c0c4889bd2 | 84 | for (uint8_t i = 0; i < params->advertisingDataLen; ++i) { |
nikapov | 1:d9c0c4889bd2 | 85 | |
nikapov | 1:d9c0c4889bd2 | 86 | const uint8_t record_length = params->advertisingData[i]; |
nikapov | 1:d9c0c4889bd2 | 87 | if (record_length == 0) { |
nikapov | 1:d9c0c4889bd2 | 88 | continue; |
nikapov | 1:d9c0c4889bd2 | 89 | } |
nikapov | 1:d9c0c4889bd2 | 90 | const uint8_t type = params->advertisingData[i + 1]; |
nikapov | 1:d9c0c4889bd2 | 91 | const uint8_t* value = params->advertisingData + i + 2; |
nikapov | 1:d9c0c4889bd2 | 92 | const uint8_t value_length = record_length - 1; |
nikapov | 1:d9c0c4889bd2 | 93 | |
nikapov | 1:d9c0c4889bd2 | 94 | if(type == GapAdvertisingData::COMPLETE_LOCAL_NAME) { |
nikapov | 1:d9c0c4889bd2 | 95 | char devName[16]; |
nikapov | 1:d9c0c4889bd2 | 96 | int strLength = value_length > 15 ? 15 : value_length; |
nikapov | 1:d9c0c4889bd2 | 97 | memcpy (devName, value, strLength); |
nikapov | 1:d9c0c4889bd2 | 98 | devName[strLength] = '\0'; |
nikapov | 1:d9c0c4889bd2 | 99 | printf("Found a device with name: %s\n\r", devName); |
nikapov | 1:d9c0c4889bd2 | 100 | |
nikapov | 1:d9c0c4889bd2 | 101 | if (memcmp(value, "BlueMbedOS", value_length) == 0) { |
nikapov | 1:d9c0c4889bd2 | 102 | printf("Found an mbed device node\n"); |
nikapov | 1:d9c0c4889bd2 | 103 | BLEProtocol::AddressBytes_t devAddress; |
nikapov | 1:d9c0c4889bd2 | 104 | memcpy (devAddress, params->peerAddr,BLEProtocol::ADDR_LEN); |
nikapov | 1:d9c0c4889bd2 | 105 | eventQueue.call(BLEConnect,devAddress); |
nikapov | 1:d9c0c4889bd2 | 106 | break; |
nikapov | 1:d9c0c4889bd2 | 107 | } |
nikapov | 1:d9c0c4889bd2 | 108 | } |
nikapov | 1:d9c0c4889bd2 | 109 | /* |
nikapov | 1:d9c0c4889bd2 | 110 | if(type == GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA) { |
nikapov | 1:d9c0c4889bd2 | 111 | printf("length: %d - mask: 0x%x\n\r", value_length, *((uint32_t*)(value+2))); |
nikapov | 1:d9c0c4889bd2 | 112 | if (((value_length == 6) || (value_length == 12)) && (*((uint32_t*)(value+2)) & 0x00001C00) == 0x00001C00) { |
nikapov | 1:d9c0c4889bd2 | 113 | printf("Found an ST device with environmental data\n"); |
nikapov | 1:d9c0c4889bd2 | 114 | //BLE::Instance().gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL); |
nikapov | 1:d9c0c4889bd2 | 115 | BLEProtocol::AddressBytes_t devAddress; |
nikapov | 1:d9c0c4889bd2 | 116 | memcpy (devAddress, params->peerAddr,BLEProtocol::ADDR_LEN); |
nikapov | 1:d9c0c4889bd2 | 117 | eventQueue.call(BLEConnect,devAddress); |
nikapov | 1:d9c0c4889bd2 | 118 | break; |
nikapov | 1:d9c0c4889bd2 | 119 | } |
nikapov | 1:d9c0c4889bd2 | 120 | } |
nikapov | 1:d9c0c4889bd2 | 121 | */ |
nikapov | 1:d9c0c4889bd2 | 122 | i += record_length; |
nikapov | 1:d9c0c4889bd2 | 123 | } |
nikapov | 1:d9c0c4889bd2 | 124 | } |
nikapov | 1:d9c0c4889bd2 | 125 | |
nikapov | 1:d9c0c4889bd2 | 126 | void serviceDiscoveryCallback(const DiscoveredService *service) { |
nikapov | 1:d9c0c4889bd2 | 127 | |
nikapov | 1:d9c0c4889bd2 | 128 | if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { |
nikapov | 1:d9c0c4889bd2 | 129 | printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle()); |
nikapov | 1:d9c0c4889bd2 | 130 | } else { |
nikapov | 1:d9c0c4889bd2 | 131 | printf("S UUID-"); |
nikapov | 1:d9c0c4889bd2 | 132 | const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID(); |
nikapov | 1:d9c0c4889bd2 | 133 | for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { |
nikapov | 1:d9c0c4889bd2 | 134 | printf("%02x", longUUIDBytes[i]); |
nikapov | 1:d9c0c4889bd2 | 135 | } |
nikapov | 1:d9c0c4889bd2 | 136 | printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle()); |
nikapov | 1:d9c0c4889bd2 | 137 | } |
nikapov | 1:d9c0c4889bd2 | 138 | } |
nikapov | 1:d9c0c4889bd2 | 139 | |
nikapov | 1:d9c0c4889bd2 | 140 | //read data from BLE |
nikapov | 1:d9c0c4889bd2 | 141 | void updateEnvCharacteristic(void) { |
nikapov | 1:d9c0c4889bd2 | 142 | if (!BLE::Instance().gattClient().isServiceDiscoveryActive()) { |
nikapov | 1:d9c0c4889bd2 | 143 | //printf("Reading environmental data\n\n"); |
nikapov | 1:d9c0c4889bd2 | 144 | envCharacteristic.read(); |
nikapov | 1:d9c0c4889bd2 | 145 | envDataAvailable = true; |
nikapov | 1:d9c0c4889bd2 | 146 | } else { |
nikapov | 1:d9c0c4889bd2 | 147 | envDataAvailable = false; |
nikapov | 1:d9c0c4889bd2 | 148 | } |
nikapov | 1:d9c0c4889bd2 | 149 | |
nikapov | 1:d9c0c4889bd2 | 150 | } |
nikapov | 1:d9c0c4889bd2 | 151 | |
nikapov | 1:d9c0c4889bd2 | 152 | |
nikapov | 1:d9c0c4889bd2 | 153 | void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) { |
nikapov | 1:d9c0c4889bd2 | 154 | /* |
nikapov | 1:d9c0c4889bd2 | 155 | printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast()); |
nikapov | 1:d9c0c4889bd2 | 156 | if (characteristicP->getUUID().getShortUUID() == 0xA001) { /* !ALERT! Alter this filter to suit your device. */ |
nikapov | 1:d9c0c4889bd2 | 157 | /* optCharacteristic = *characteristicP; |
nikapov | 1:d9c0c4889bd2 | 158 | triggerLedCharacteristic = true; |
nikapov | 1:d9c0c4889bd2 | 159 | }*/ |
nikapov | 1:d9c0c4889bd2 | 160 | printf("Found environmental data\n"); |
nikapov | 1:d9c0c4889bd2 | 161 | envCharacteristic = *characteristicP; |
nikapov | 1:d9c0c4889bd2 | 162 | triggerEnvCharacteristic = true; |
nikapov | 0:c7083010ae49 | 163 | } |
nikapov | 0:c7083010ae49 | 164 | |
nikapov | 1:d9c0c4889bd2 | 165 | void discoveryTerminationCallback(Gap::Handle_t connectionHandle) { |
nikapov | 1:d9c0c4889bd2 | 166 | |
nikapov | 1:d9c0c4889bd2 | 167 | //printf("terminated SD for handle %u\r\n", connectionHandle); |
nikapov | 1:d9c0c4889bd2 | 168 | |
nikapov | 1:d9c0c4889bd2 | 169 | if (triggerEnvCharacteristic) { |
nikapov | 1:d9c0c4889bd2 | 170 | triggerEnvCharacteristic = false; |
nikapov | 1:d9c0c4889bd2 | 171 | eventQueue.call(updateEnvCharacteristic); |
nikapov | 1:d9c0c4889bd2 | 172 | } |
nikapov | 1:d9c0c4889bd2 | 173 | } |
nikapov | 1:d9c0c4889bd2 | 174 | |
nikapov | 1:d9c0c4889bd2 | 175 | void connectionCallback(const Gap::ConnectionCallbackParams_t *params) { |
nikapov | 1:d9c0c4889bd2 | 176 | printf("Connected to ST Node now...\r\n"); |
nikapov | 1:d9c0c4889bd2 | 177 | if (params->role == Gap::CENTRAL) { |
nikapov | 1:d9c0c4889bd2 | 178 | BLE &ble = BLE::Instance(); |
nikapov | 1:d9c0c4889bd2 | 179 | ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback); |
nikapov | 1:d9c0c4889bd2 | 180 | const char *servUUIDString = "00000000-0001-11e1-9ab4-0002a5d5c51b"; |
nikapov | 1:d9c0c4889bd2 | 181 | UUID servUUID(servUUIDString); |
nikapov | 1:d9c0c4889bd2 | 182 | const char *charUUIDString = "001c0000-0001-11e1-ac36-0002a5d5c51b"; |
nikapov | 1:d9c0c4889bd2 | 183 | UUID charUUID(charUUIDString); |
nikapov | 1:d9c0c4889bd2 | 184 | ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, servUUID, charUUID); |
nikapov | 1:d9c0c4889bd2 | 185 | } |
nikapov | 1:d9c0c4889bd2 | 186 | } |
nikapov | 1:d9c0c4889bd2 | 187 | |
nikapov | 1:d9c0c4889bd2 | 188 | |
nikapov | 1:d9c0c4889bd2 | 189 | void triggerRead(const GattReadCallbackParams *response) { |
nikapov | 1:d9c0c4889bd2 | 190 | |
nikapov | 1:d9c0c4889bd2 | 191 | if (response->handle == envCharacteristic.getValueHandle()) { |
nikapov | 1:d9c0c4889bd2 | 192 | payload_length = response-> len; |
nikapov | 1:d9c0c4889bd2 | 193 | for(int i=0; i< response-> len; i++) { |
nikapov | 1:d9c0c4889bd2 | 194 | // printf("%02x", response->data[i]); |
nikapov | 1:d9c0c4889bd2 | 195 | dataforClient[i] = response -> data[i]; |
nikapov | 1:d9c0c4889bd2 | 196 | // printf("%d", dataforClient[i]); |
nikapov | 1:d9c0c4889bd2 | 197 | } |
nikapov | 1:d9c0c4889bd2 | 198 | |
nikapov | 1:d9c0c4889bd2 | 199 | //printf("Temperature: %f\r\n", (uint32_t)((dataforClient[9]<<8) | dataforClient[8])/10.0); |
nikapov | 1:d9c0c4889bd2 | 200 | //printf("Humidity: %f\r\n", (uint32_t)((dataforClient[7]<<8) | dataforClient[6])/10.0); |
nikapov | 1:d9c0c4889bd2 | 201 | //printf("Pressure: %f\r\n\r\n\r\n", (uint32_t)((dataforClient[5]<<24) |(dataforClient[4]<<16) |(dataforClient[3]<<8) | dataforClient[2])/100.0); |
nikapov | 1:d9c0c4889bd2 | 202 | |
nikapov | 1:d9c0c4889bd2 | 203 | eventQueue.call(updateEnvCharacteristic); // triggering BLE data read again |
nikapov | 1:d9c0c4889bd2 | 204 | } |
nikapov | 1:d9c0c4889bd2 | 205 | } |
nikapov | 1:d9c0c4889bd2 | 206 | |
nikapov | 1:d9c0c4889bd2 | 207 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) { |
nikapov | 1:d9c0c4889bd2 | 208 | printf("Got disconnected from the device!\r\n"); |
nikapov | 1:d9c0c4889bd2 | 209 | /* Start scanning and try to connect again */ |
nikapov | 1:d9c0c4889bd2 | 210 | BLE::Instance().gap().startScan(advertisementCallback); |
nikapov | 1:d9c0c4889bd2 | 211 | } |
nikapov | 1:d9c0c4889bd2 | 212 | |
nikapov | 1:d9c0c4889bd2 | 213 | void onBleInitError(BLE &ble, ble_error_t error) |
nikapov | 1:d9c0c4889bd2 | 214 | { |
nikapov | 1:d9c0c4889bd2 | 215 | /* Initialization error handling should go here */ |
nikapov | 1:d9c0c4889bd2 | 216 | printf("BLE Error = %u\r\n", error); |
nikapov | 1:d9c0c4889bd2 | 217 | } |
nikapov | 1:d9c0c4889bd2 | 218 | |
nikapov | 1:d9c0c4889bd2 | 219 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) |
nikapov | 1:d9c0c4889bd2 | 220 | { |
nikapov | 1:d9c0c4889bd2 | 221 | //printf("I'm inside BLE init\r\n"); |
nikapov | 1:d9c0c4889bd2 | 222 | BLE& ble = params->ble; |
nikapov | 1:d9c0c4889bd2 | 223 | ble_error_t error = params->error; |
nikapov | 1:d9c0c4889bd2 | 224 | ble_error_t error1 = params->error; |
nikapov | 1:d9c0c4889bd2 | 225 | |
nikapov | 1:d9c0c4889bd2 | 226 | if (error != BLE_ERROR_NONE) { |
nikapov | 1:d9c0c4889bd2 | 227 | /* In case of error, forward the error handling to onBleInitError */ |
nikapov | 1:d9c0c4889bd2 | 228 | onBleInitError(ble, error); |
nikapov | 1:d9c0c4889bd2 | 229 | return; |
nikapov | 1:d9c0c4889bd2 | 230 | } |
nikapov | 1:d9c0c4889bd2 | 231 | |
nikapov | 1:d9c0c4889bd2 | 232 | /* Ensure that it is the default instance of BLE */ |
nikapov | 1:d9c0c4889bd2 | 233 | if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { |
nikapov | 1:d9c0c4889bd2 | 234 | printf("Not the default instance\r\n"); |
nikapov | 1:d9c0c4889bd2 | 235 | return; |
nikapov | 1:d9c0c4889bd2 | 236 | } |
nikapov | 1:d9c0c4889bd2 | 237 | |
nikapov | 1:d9c0c4889bd2 | 238 | ble.gap().onDisconnection(disconnectionCallback); |
nikapov | 1:d9c0c4889bd2 | 239 | ble.gap().onConnection(connectionCallback); |
nikapov | 1:d9c0c4889bd2 | 240 | |
nikapov | 1:d9c0c4889bd2 | 241 | // On reading data, call triggerRead function. |
nikapov | 1:d9c0c4889bd2 | 242 | ble.gattClient().onDataRead(triggerRead); |
nikapov | 1:d9c0c4889bd2 | 243 | |
nikapov | 1:d9c0c4889bd2 | 244 | // scan interval: 400ms and scan window: 400ms. |
nikapov | 1:d9c0c4889bd2 | 245 | // Every 400ms the device will scan for 400ms |
nikapov | 1:d9c0c4889bd2 | 246 | // This means that the device will scan continuously. |
nikapov | 1:d9c0c4889bd2 | 247 | ble.gap().setScanParams(400, 400); |
nikapov | 1:d9c0c4889bd2 | 248 | error = ble.gap().startScan(advertisementCallback); |
nikapov | 1:d9c0c4889bd2 | 249 | if (error) { |
nikapov | 1:d9c0c4889bd2 | 250 | printf("BLE Error startScan = %u\r\n", error); |
nikapov | 1:d9c0c4889bd2 | 251 | } |
nikapov | 1:d9c0c4889bd2 | 252 | |
nikapov | 1:d9c0c4889bd2 | 253 | } |
nikapov | 1:d9c0c4889bd2 | 254 | |
nikapov | 1:d9c0c4889bd2 | 255 | void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { |
nikapov | 1:d9c0c4889bd2 | 256 | BLE &ble = BLE::Instance(); |
nikapov | 1:d9c0c4889bd2 | 257 | eventQueue.call(Callback<void()>(&ble, &BLE::processEvents)); |
nikapov | 1:d9c0c4889bd2 | 258 | } |
nikapov | 1:d9c0c4889bd2 | 259 | |
nikapov | 1:d9c0c4889bd2 | 260 | //BLE thread init and further calls to other BLE methods. |
nikapov | 1:d9c0c4889bd2 | 261 | void BLE_thread_init(void){ |
nikapov | 1:d9c0c4889bd2 | 262 | //printf("I'm inside BLE thread.....\r\n"); |
nikapov | 1:d9c0c4889bd2 | 263 | |
nikapov | 1:d9c0c4889bd2 | 264 | //Schedule events before starting the thread since there might be some missed events while scanning / pairing. |
nikapov | 1:d9c0c4889bd2 | 265 | ble.onEventsToProcess(scheduleBleEventsProcessing); |
nikapov | 1:d9c0c4889bd2 | 266 | ble.init(bleInitComplete); |
nikapov | 1:d9c0c4889bd2 | 267 | //Loop forever the BLE thread |
nikapov | 1:d9c0c4889bd2 | 268 | eventQueue.dispatch_forever(); |
nikapov | 1:d9c0c4889bd2 | 269 | } |
nikapov | 1:d9c0c4889bd2 | 270 | |
nikapov | 1:d9c0c4889bd2 | 271 | /************************************************************BLE Stuff to here *********************************/ |
nikapov | 1:d9c0c4889bd2 | 272 | |
nikapov | 0:c7083010ae49 | 273 | // These are example resource values for the Device Object |
nikapov | 0:c7083010ae49 | 274 | struct MbedClientDevice device = { |
nikapov | 0:c7083010ae49 | 275 | "Manufacturer_String", // Manufacturer |
nikapov | 0:c7083010ae49 | 276 | "Type_String", // Type |
nikapov | 0:c7083010ae49 | 277 | "ModelNumber_String", // ModelNumber |
nikapov | 0:c7083010ae49 | 278 | "SerialNumber_String" // SerialNumber |
nikapov | 0:c7083010ae49 | 279 | }; |
nikapov | 0:c7083010ae49 | 280 | |
nikapov | 0:c7083010ae49 | 281 | // Instantiate the class which implements LWM2M Client API (from simpleclient.h) |
nikapov | 0:c7083010ae49 | 282 | MbedClient mbed_client(device); |
nikapov | 0:c7083010ae49 | 283 | |
nikapov | 0:c7083010ae49 | 284 | |
nikapov | 1:d9c0c4889bd2 | 285 | class EnvResource { |
nikapov | 1:d9c0c4889bd2 | 286 | public: |
nikapov | 1:d9c0c4889bd2 | 287 | EnvResource() { |
nikapov | 1:d9c0c4889bd2 | 288 | |
nikapov | 1:d9c0c4889bd2 | 289 | temp_object = M2MInterfaceFactory::create_object("3303"); |
nikapov | 1:d9c0c4889bd2 | 290 | temp_inst = temp_object->create_object_instance(); |
nikapov | 1:d9c0c4889bd2 | 291 | temp_res = temp_inst->create_dynamic_resource("5700", "Temperature", |
nikapov | 1:d9c0c4889bd2 | 292 | M2MResourceInstance::FLOAT, true); // observable |
nikapov | 1:d9c0c4889bd2 | 293 | // we can only read this value |
nikapov | 1:d9c0c4889bd2 | 294 | temp_res->set_operation(M2MBase::GET_ALLOWED); |
nikapov | 1:d9c0c4889bd2 | 295 | temp_res->set_value((uint8_t*)"20.0", 4); |
nikapov | 1:d9c0c4889bd2 | 296 | |
nikapov | 1:d9c0c4889bd2 | 297 | hum_object = M2MInterfaceFactory::create_object("3304"); |
nikapov | 1:d9c0c4889bd2 | 298 | hum_inst = hum_object->create_object_instance(); |
nikapov | 1:d9c0c4889bd2 | 299 | hum_res = hum_inst->create_dynamic_resource("5700", "Humidity", |
nikapov | 1:d9c0c4889bd2 | 300 | M2MResourceInstance::FLOAT, true); // observable |
nikapov | 1:d9c0c4889bd2 | 301 | // we can only read this value |
nikapov | 1:d9c0c4889bd2 | 302 | hum_res->set_operation(M2MBase::GET_ALLOWED); |
nikapov | 1:d9c0c4889bd2 | 303 | hum_res->set_value((uint8_t*)"50.0", 4); |
nikapov | 1:d9c0c4889bd2 | 304 | |
nikapov | 1:d9c0c4889bd2 | 305 | press_object = M2MInterfaceFactory::create_object("3300"); |
nikapov | 1:d9c0c4889bd2 | 306 | press_inst = press_object->create_object_instance(); |
nikapov | 1:d9c0c4889bd2 | 307 | press_res = press_inst->create_dynamic_resource("5700", "Pressure", |
nikapov | 1:d9c0c4889bd2 | 308 | M2MResourceInstance::FLOAT, true); // observable |
nikapov | 1:d9c0c4889bd2 | 309 | // we can only read this value |
nikapov | 1:d9c0c4889bd2 | 310 | press_res->set_operation(M2MBase::GET_ALLOWED); |
nikapov | 1:d9c0c4889bd2 | 311 | press_res->set_value((uint8_t*)"1000", 4); |
nikapov | 1:d9c0c4889bd2 | 312 | |
nikapov | 1:d9c0c4889bd2 | 313 | timer_res = press_inst->create_dynamic_resource("5603", "PollingPeriodMs", // one polling time for all env values, associated to humidity |
nikapov | 1:d9c0c4889bd2 | 314 | M2MResourceInstance::INTEGER, false); // not observable |
nikapov | 1:d9c0c4889bd2 | 315 | // we can read/wr this value |
nikapov | 1:d9c0c4889bd2 | 316 | timer_res->set_operation(M2MBase::GET_PUT_ALLOWED); |
nikapov | 1:d9c0c4889bd2 | 317 | timer_res->set_value((uint8_t*)"1000",4); // default 1s polling |
nikapov | 1:d9c0c4889bd2 | 318 | |
nikapov | 1:d9c0c4889bd2 | 319 | } |
nikapov | 1:d9c0c4889bd2 | 320 | |
nikapov | 1:d9c0c4889bd2 | 321 | M2MObject* get_temp_object() { |
nikapov | 1:d9c0c4889bd2 | 322 | return temp_object; |
nikapov | 1:d9c0c4889bd2 | 323 | } |
nikapov | 1:d9c0c4889bd2 | 324 | |
nikapov | 1:d9c0c4889bd2 | 325 | M2MObject* get_hum_object() { |
nikapov | 1:d9c0c4889bd2 | 326 | return hum_object; |
nikapov | 1:d9c0c4889bd2 | 327 | } |
nikapov | 1:d9c0c4889bd2 | 328 | |
nikapov | 1:d9c0c4889bd2 | 329 | M2MObject* get_press_object() { |
nikapov | 1:d9c0c4889bd2 | 330 | return press_object; |
nikapov | 1:d9c0c4889bd2 | 331 | } |
nikapov | 1:d9c0c4889bd2 | 332 | |
nikapov | 1:d9c0c4889bd2 | 333 | int get_polling_period() { |
nikapov | 1:d9c0c4889bd2 | 334 | return timer_res->get_value_int(); |
nikapov | 1:d9c0c4889bd2 | 335 | } |
nikapov | 0:c7083010ae49 | 336 | |
nikapov | 1:d9c0c4889bd2 | 337 | void update_resources() { |
nikapov | 1:d9c0c4889bd2 | 338 | float temp; |
nikapov | 1:d9c0c4889bd2 | 339 | float hum; |
nikapov | 1:d9c0c4889bd2 | 340 | float press; |
nikapov | 1:d9c0c4889bd2 | 341 | |
nikapov | 1:d9c0c4889bd2 | 342 | if (!envDataAvailable) { |
nikapov | 1:d9c0c4889bd2 | 343 | return; |
nikapov | 1:d9c0c4889bd2 | 344 | } |
nikapov | 1:d9c0c4889bd2 | 345 | |
nikapov | 1:d9c0c4889bd2 | 346 | temp = (uint32_t)((dataforClient[9]<<8) | dataforClient[8])/10.0; |
nikapov | 1:d9c0c4889bd2 | 347 | hum = ((dataforClient[7]<<8) | dataforClient[6])/10.0; |
nikapov | 1:d9c0c4889bd2 | 348 | press = (uint32_t)((dataforClient[5]<<24) |(dataforClient[4]<<16) |(dataforClient[3]<<8) | dataforClient[2])/100.0; |
nikapov | 1:d9c0c4889bd2 | 349 | |
nikapov | 1:d9c0c4889bd2 | 350 | stringstream ss_temp; |
nikapov | 1:d9c0c4889bd2 | 351 | ss_temp << temp; |
nikapov | 1:d9c0c4889bd2 | 352 | std::string stringified = ss_temp.str(); |
nikapov | 1:d9c0c4889bd2 | 353 | temp_res->set_value((uint8_t*)stringified.c_str(), stringified.length()); |
nikapov | 1:d9c0c4889bd2 | 354 | |
nikapov | 1:d9c0c4889bd2 | 355 | stringstream ss_hum; |
nikapov | 1:d9c0c4889bd2 | 356 | ss_hum << hum; |
nikapov | 1:d9c0c4889bd2 | 357 | stringified = ss_hum.str(); |
nikapov | 1:d9c0c4889bd2 | 358 | hum_res->set_value((uint8_t*)stringified.c_str(), stringified.length()); |
nikapov | 1:d9c0c4889bd2 | 359 | |
nikapov | 1:d9c0c4889bd2 | 360 | stringstream ss_press; |
nikapov | 1:d9c0c4889bd2 | 361 | ss_press << press; |
nikapov | 1:d9c0c4889bd2 | 362 | stringified = ss_press.str(); |
nikapov | 1:d9c0c4889bd2 | 363 | press_res->set_value((uint8_t*)stringified.c_str(), stringified.length()); |
nikapov | 1:d9c0c4889bd2 | 364 | |
nikapov | 1:d9c0c4889bd2 | 365 | } |
nikapov | 1:d9c0c4889bd2 | 366 | |
nikapov | 1:d9c0c4889bd2 | 367 | private: |
nikapov | 1:d9c0c4889bd2 | 368 | |
nikapov | 1:d9c0c4889bd2 | 369 | M2MObject* temp_object; |
nikapov | 1:d9c0c4889bd2 | 370 | M2MObjectInstance* temp_inst; |
nikapov | 1:d9c0c4889bd2 | 371 | M2MResource* temp_res; |
nikapov | 1:d9c0c4889bd2 | 372 | |
nikapov | 1:d9c0c4889bd2 | 373 | M2MObject* hum_object; |
nikapov | 1:d9c0c4889bd2 | 374 | M2MObjectInstance* hum_inst; |
nikapov | 1:d9c0c4889bd2 | 375 | M2MResource* hum_res; |
nikapov | 1:d9c0c4889bd2 | 376 | |
nikapov | 1:d9c0c4889bd2 | 377 | M2MObject* press_object; |
nikapov | 1:d9c0c4889bd2 | 378 | M2MObjectInstance* press_inst; |
nikapov | 1:d9c0c4889bd2 | 379 | M2MResource* press_res; |
nikapov | 1:d9c0c4889bd2 | 380 | |
nikapov | 1:d9c0c4889bd2 | 381 | M2MResource* timer_res; |
nikapov | 1:d9c0c4889bd2 | 382 | |
nikapov | 0:c7083010ae49 | 383 | }; |
nikapov | 0:c7083010ae49 | 384 | |
nikapov | 0:c7083010ae49 | 385 | |
nikapov | 0:c7083010ae49 | 386 | osThreadId mainThread; |
nikapov | 0:c7083010ae49 | 387 | |
nikapov | 0:c7083010ae49 | 388 | // Entry point to the program |
nikapov | 0:c7083010ae49 | 389 | int main() { |
nikapov | 0:c7083010ae49 | 390 | |
nikapov | 0:c7083010ae49 | 391 | unsigned int seed; |
nikapov | 0:c7083010ae49 | 392 | size_t len; |
nikapov | 0:c7083010ae49 | 393 | |
nikapov | 0:c7083010ae49 | 394 | #ifdef MBEDTLS_ENTROPY_HARDWARE_ALT |
nikapov | 0:c7083010ae49 | 395 | // Used to randomize source port |
nikapov | 0:c7083010ae49 | 396 | mbedtls_hardware_poll(NULL, (unsigned char *) &seed, sizeof seed, &len); |
nikapov | 0:c7083010ae49 | 397 | |
nikapov | 0:c7083010ae49 | 398 | #elif defined MBEDTLS_TEST_NULL_ENTROPY |
nikapov | 0:c7083010ae49 | 399 | |
nikapov | 0:c7083010ae49 | 400 | #warning "mbedTLS security feature is disabled. Connection will not be secure !! Implement proper hardware entropy for your selected hardware." |
nikapov | 0:c7083010ae49 | 401 | // Used to randomize source port |
nikapov | 0:c7083010ae49 | 402 | mbedtls_null_entropy_poll( NULL,(unsigned char *) &seed, sizeof seed, &len); |
nikapov | 0:c7083010ae49 | 403 | |
nikapov | 0:c7083010ae49 | 404 | #else |
nikapov | 0:c7083010ae49 | 405 | |
nikapov | 0:c7083010ae49 | 406 | #error "This hardware does not have entropy, endpoint will not register to Connector.\ |
nikapov | 0:c7083010ae49 | 407 | You need to enable NULL ENTROPY for your application, but if this configuration change is made then no security is offered by mbed TLS.\ |
nikapov | 0:c7083010ae49 | 408 | Add MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES and MBEDTLS_TEST_NULL_ENTROPY in mbed_app.json macros to register your endpoint." |
nikapov | 0:c7083010ae49 | 409 | |
nikapov | 0:c7083010ae49 | 410 | #endif |
nikapov | 0:c7083010ae49 | 411 | |
nikapov | 0:c7083010ae49 | 412 | srand(seed); |
nikapov | 0:c7083010ae49 | 413 | red_led = LED_OFF; |
nikapov | 0:c7083010ae49 | 414 | blue_led = LED_OFF; |
nikapov | 0:c7083010ae49 | 415 | |
nikapov | 0:c7083010ae49 | 416 | // Keep track of the main thread |
nikapov | 0:c7083010ae49 | 417 | mainThread = osThreadGetId(); |
nikapov | 0:c7083010ae49 | 418 | |
nikapov | 0:c7083010ae49 | 419 | printf("\nStarting mbed Client example\n"); |
nikapov | 0:c7083010ae49 | 420 | |
nikapov | 1:d9c0c4889bd2 | 421 | //mbed_trace_init(); |
nikapov | 0:c7083010ae49 | 422 | |
nikapov | 0:c7083010ae49 | 423 | NetworkInterface* network = easy_connect(true); |
nikapov | 0:c7083010ae49 | 424 | if(network == NULL) { |
nikapov | 0:c7083010ae49 | 425 | printf("\nConnection to Network Failed - exiting application...\n"); |
nikapov | 0:c7083010ae49 | 426 | return -1; |
nikapov | 0:c7083010ae49 | 427 | } |
nikapov | 1:d9c0c4889bd2 | 428 | |
nikapov | 1:d9c0c4889bd2 | 429 | // environmental data |
nikapov | 1:d9c0c4889bd2 | 430 | EnvResource env_resource; |
nikapov | 1:d9c0c4889bd2 | 431 | |
nikapov | 0:c7083010ae49 | 432 | |
nikapov | 0:c7083010ae49 | 433 | // Create endpoint interface to manage register and unregister |
nikapov | 0:c7083010ae49 | 434 | mbed_client.create_interface(MBED_SERVER_ADDRESS, network); |
nikapov | 0:c7083010ae49 | 435 | |
nikapov | 0:c7083010ae49 | 436 | // Create Objects of varying types, see simpleclient.h for more details on implementation. |
nikapov | 0:c7083010ae49 | 437 | M2MSecurity* register_object = mbed_client.create_register_object(); // server object specifying connector info |
nikapov | 0:c7083010ae49 | 438 | M2MDevice* device_object = mbed_client.create_device_object(); // device resources object |
nikapov | 0:c7083010ae49 | 439 | |
nikapov | 0:c7083010ae49 | 440 | // Create list of Objects to register |
nikapov | 0:c7083010ae49 | 441 | M2MObjectList object_list; |
nikapov | 0:c7083010ae49 | 442 | |
nikapov | 0:c7083010ae49 | 443 | // Add objects to list |
nikapov | 0:c7083010ae49 | 444 | object_list.push_back(device_object); |
nikapov | 1:d9c0c4889bd2 | 445 | object_list.push_back(env_resource.get_temp_object()); |
nikapov | 1:d9c0c4889bd2 | 446 | object_list.push_back(env_resource.get_hum_object()); |
nikapov | 1:d9c0c4889bd2 | 447 | object_list.push_back(env_resource.get_press_object()); |
nikapov | 1:d9c0c4889bd2 | 448 | |
nikapov | 0:c7083010ae49 | 449 | // Set endpoint registration object |
nikapov | 0:c7083010ae49 | 450 | mbed_client.set_register_object(register_object); |
nikapov | 0:c7083010ae49 | 451 | |
nikapov | 0:c7083010ae49 | 452 | // Register with mbed Device Connector |
nikapov | 0:c7083010ae49 | 453 | mbed_client.test_register(register_object, object_list); |
nikapov | 0:c7083010ae49 | 454 | |
nikapov | 1:d9c0c4889bd2 | 455 | // wait for registration and BLE data started flushing |
nikapov | 1:d9c0c4889bd2 | 456 | while (!mbed_client.register_successful()) { |
nikapov | 1:d9c0c4889bd2 | 457 | Thread::wait(500); |
nikapov | 1:d9c0c4889bd2 | 458 | } |
nikapov | 1:d9c0c4889bd2 | 459 | |
nikapov | 1:d9c0c4889bd2 | 460 | printf("\nNow starting BLE thread\n"); |
nikapov | 1:d9c0c4889bd2 | 461 | BLE_thread.start(BLE_thread_init); |
nikapov | 1:d9c0c4889bd2 | 462 | |
nikapov | 1:d9c0c4889bd2 | 463 | while (!envDataAvailable) { |
nikapov | 1:d9c0c4889bd2 | 464 | Thread::wait(500); |
nikapov | 1:d9c0c4889bd2 | 465 | } |
nikapov | 1:d9c0c4889bd2 | 466 | |
nikapov | 1:d9c0c4889bd2 | 467 | printf ("\nNow pushing data to the mbed device connector.\n"); |
nikapov | 1:d9c0c4889bd2 | 468 | |
nikapov | 0:c7083010ae49 | 469 | while (true) { |
nikapov | 1:d9c0c4889bd2 | 470 | |
nikapov | 1:d9c0c4889bd2 | 471 | env_resource.update_resources(); |
nikapov | 1:d9c0c4889bd2 | 472 | int timer_val = env_resource.get_polling_period(); |
nikapov | 1:d9c0c4889bd2 | 473 | Thread::wait(timer_val); |
nikapov | 0:c7083010ae49 | 474 | } |
nikapov | 0:c7083010ae49 | 475 | |
nikapov | 0:c7083010ae49 | 476 | mbed_client.test_unregister(); |
nikapov | 1:d9c0c4889bd2 | 477 | |
nikapov | 0:c7083010ae49 | 478 | } |