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