An mbed BLE-to-Cloud Gateway using Nucleo-F429ZI+X-Nucleo-IDB05A1 or Nucleo-L476RG+X-Nucleo-IDB05A1+X-Nucleo-IDW01M1.
main.cpp
00001 /* 00002 * Copyright (c) 2015, 2016 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #define __STDC_FORMAT_MACROS 00017 #include <inttypes.h> 00018 #include "simpleclient.h" 00019 #include <string> 00020 #include <sstream> 00021 #include <vector> 00022 #include "mbed-trace/mbed_trace.h" 00023 #include "mbedtls/entropy_poll.h" 00024 #include "BLE.h" 00025 #include "DiscoveredCharacteristic.h" 00026 #include "DiscoveredService.h" 00027 00028 00029 #include "security.h" 00030 00031 #include "mbed.h" 00032 00033 // easy-connect compliancy, it has 2 sets of wifi pins we have only one 00034 #define MBED_CONF_APP_ESP8266_TX MBED_CONF_APP_WIFI_TX 00035 #define MBED_CONF_APP_ESP8266_RX MBED_CONF_APP_WIFI_RX 00036 #define MBED_CFG_SPWF01SA_TX MBED_CONF_APP_WIFI_TX 00037 #define MBED_CFG_SPWF01SA_RX MBED_CONF_APP_WIFI_RX 00038 #include "easy-connect/easy-connect.h" 00039 00040 #ifdef TARGET_STM 00041 #define RED_LED (LED3) 00042 #define GREEN_LED (LED1) 00043 #define BLUE_LED (LED2) 00044 #define LED_ON (1) 00045 #else // !TARGET_STM 00046 #define RED_LED (LED1) 00047 #define GREEN_LED (LED2) 00048 #define BLUE_LED (LED3) 00049 #define LED_ON (0) 00050 #endif // !TARGET_STM 00051 #define LED_OFF (!LED_ON) 00052 00053 // Status indication 00054 DigitalOut red_led(RED_LED); 00055 #ifdef NUCLEO_F429ZI 00056 DigitalOut green_led(NC); // avoid interference with SPI_CLK 00057 #else 00058 DigitalOut green_led(GREEN_LED); 00059 #endif 00060 DigitalOut blue_led(BLUE_LED); 00061 00062 00063 /************************************************************BLE Stuff from here *********************************/ 00064 00065 BLE &ble = BLE::Instance(); 00066 static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE); 00067 Thread BLE_thread; 00068 static bool triggerEnvCharacteristic; 00069 static bool envDataAvailable = false; 00070 static DiscoveredCharacteristic envCharacteristic; 00071 uint16_t payload_length = 0; 00072 uint8_t dataforClient[12]; 00073 00074 void BLEConnect(BLEProtocol::AddressBytes_t address) { 00075 BLE::Instance().gap().connect(address, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL); 00076 } 00077 00078 00079 void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params) { 00080 // parse the advertising payload, looking for data type COMPLETE_LOCAL_NAME 00081 // The advertising payload is a collection of key/value records where 00082 // byte 0: length of the record excluding this byte 00083 // byte 1: The key, it is the type of the data 00084 // byte [2..N] The value. N is equal to byte0 - 1 00085 00086 //printf("Starting advertisementCallback...\r\n"); 00087 00088 for (uint8_t i = 0; i < params->advertisingDataLen; ++i) { 00089 00090 const uint8_t record_length = params->advertisingData[i]; 00091 if (record_length == 0) { 00092 continue; 00093 } 00094 const uint8_t type = params->advertisingData[i + 1]; 00095 const uint8_t* value = params->advertisingData + i + 2; 00096 const uint8_t value_length = record_length - 1; 00097 00098 if(type == GapAdvertisingData::COMPLETE_LOCAL_NAME) { 00099 char devName[16]; 00100 int strLength = value_length > 15 ? 15 : value_length; 00101 memcpy (devName, value, strLength); 00102 devName[strLength] = '\0'; 00103 printf("Found a device with name: %s\n\r", devName); 00104 00105 if (memcmp(value, "MotEnvMbed", 10) == 0) { // search for MotEnvMbedXX devices 00106 printf("Found an mbed device node\n"); 00107 BLEProtocol::AddressBytes_t devAddress; 00108 memcpy (devAddress, params->peerAddr,BLEProtocol::ADDR_LEN); 00109 BLEConnect(devAddress); 00110 break; 00111 } 00112 } 00113 00114 i += record_length; 00115 } 00116 } 00117 00118 void serviceDiscoveryCallback(const DiscoveredService *service) { 00119 00120 if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) { 00121 printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle()); 00122 } else { 00123 printf("S UUID-"); 00124 const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID(); 00125 for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) { 00126 printf("%02x", longUUIDBytes[i]); 00127 } 00128 printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle()); 00129 } 00130 } 00131 00132 //read data from BLE 00133 void updateEnvCharacteristic(void) { 00134 if (!BLE::Instance().gattClient().isServiceDiscoveryActive()) { 00135 //printf("Reading environmental data\n\n"); 00136 envCharacteristic.read(); 00137 envDataAvailable = true; 00138 #ifdef NUCLEO_F429ZI 00139 red_led = LED_ON; 00140 #else 00141 green_led = LED_ON; 00142 #endif 00143 } else { 00144 envDataAvailable = false; 00145 } 00146 } 00147 00148 00149 void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) { 00150 00151 printf("Found environmental data\n"); 00152 envCharacteristic = *characteristicP; 00153 triggerEnvCharacteristic = true; 00154 } 00155 00156 void discoveryTerminationCallback(Gap::Handle_t connectionHandle) { 00157 00158 //printf("terminated SD for handle %u\r\n", connectionHandle); 00159 00160 if (triggerEnvCharacteristic) { 00161 triggerEnvCharacteristic = false; 00162 eventQueue.call_in(500, updateEnvCharacteristic); 00163 } 00164 } 00165 00166 void connectionCallback(const Gap::ConnectionCallbackParams_t *params) { 00167 printf("Connected to ST Node now...\r\n"); 00168 if (params->role == Gap::CENTRAL) { 00169 BLE &ble = BLE::Instance(); 00170 ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback); 00171 const char *servUUIDString = "00000000-0001-11e1-9ab4-0002a5d5c51b"; 00172 UUID servUUID(servUUIDString); 00173 const char *charUUIDString = "001c0000-0001-11e1-ac36-0002a5d5c51b"; 00174 UUID charUUID(charUUIDString); 00175 ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, servUUID, charUUID); 00176 } 00177 } 00178 00179 00180 void triggerRead(const GattReadCallbackParams *response) { 00181 00182 if (response->handle == envCharacteristic.getValueHandle()) { 00183 payload_length = response-> len; 00184 for(int i=0; i< response-> len; i++) { 00185 // printf("%02x", response->data[i]); 00186 dataforClient[i] = response -> data[i]; 00187 // printf("%d", dataforClient[i]); 00188 } 00189 00190 //printf("Temperature: %f\r\n", (uint32_t)((dataforClient[9]<<8) | dataforClient[8])/10.0); 00191 //printf("Humidity: %f\r\n", (uint32_t)((dataforClient[7]<<8) | dataforClient[6])/10.0); 00192 //printf("Pressure: %f\r\n\r\n\r\n", (uint32_t)((dataforClient[5]<<24) |(dataforClient[4]<<16) |(dataforClient[3]<<8) | dataforClient[2])/100.0); 00193 00194 eventQueue.call_in(500, updateEnvCharacteristic); // triggering BLE data read again in 0.5s 00195 } 00196 } 00197 00198 void triggerNotify(const GattHVXCallbackParams *response) { 00199 00200 if (response->handle == envCharacteristic.getValueHandle()) { 00201 payload_length = response-> len; 00202 for(int i=0; i< response-> len; i++) { 00203 // printf("%02x", response->data[i]); 00204 dataforClient[i] = response -> data[i]; 00205 // printf("%d", dataforClient[i]); 00206 } 00207 00208 //printf("Temperature: %f\r\n", (uint32_t)((dataforClient[9]<<8) | dataforClient[8])/10.0); 00209 //printf("Humidity: %f\r\n", (uint32_t)((dataforClient[7]<<8) | dataforClient[6])/10.0); 00210 //printf("Pressure: %f\r\n\r\n\r\n", (uint32_t)((dataforClient[5]<<24) |(dataforClient[4]<<16) |(dataforClient[3]<<8) | dataforClient[2])/100.0); 00211 00212 } 00213 } 00214 00215 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) { 00216 printf("Got disconnected from the device!\r\n"); 00217 /* Start scanning and try to connect again */ 00218 #ifdef NUCLEO_F429ZI 00219 red_led = LED_OFF; 00220 #else 00221 green_led = LED_OFF; 00222 #endif 00223 BLE::Instance().gap().startScan(advertisementCallback); 00224 } 00225 00226 void onBleInitError(BLE &ble, ble_error_t error) 00227 { 00228 /* Initialization error handling should go here */ 00229 printf("BLE Error = %u\r\n", error); 00230 } 00231 00232 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) 00233 { 00234 //printf("I'm inside BLE init\r\n"); 00235 BLE& ble = params->ble; 00236 ble_error_t error = params->error; 00237 ble_error_t error1 = params->error; 00238 00239 if (error != BLE_ERROR_NONE) { 00240 /* In case of error, forward the error handling to onBleInitError */ 00241 onBleInitError(ble, error); 00242 return; 00243 } 00244 00245 /* Ensure that it is the default instance of BLE */ 00246 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { 00247 printf("Not the default instance\r\n"); 00248 return; 00249 } 00250 00251 ble.gap().onDisconnection(disconnectionCallback); 00252 ble.gap().onConnection(connectionCallback); 00253 00254 // On reading data, call triggerRead function. 00255 ble.gattClient().onDataRead(triggerRead); 00256 //ble.gattClient().onHVX(triggerNotify); 00257 // scan interval: 400ms and scan window: 400ms. 00258 // Every 400ms the device will scan for 400ms 00259 // This means that the device will scan continuously. 00260 ble.gap().setScanParams(400, 400); 00261 error = ble.gap().startScan(advertisementCallback); 00262 if (error) { 00263 printf("BLE Error startScan = %u\r\n", error); 00264 } 00265 00266 } 00267 00268 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { 00269 BLE &ble = BLE::Instance(); 00270 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents)); 00271 } 00272 00273 //BLE thread init and further calls to other BLE methods. 00274 void BLE_thread_init(void){ 00275 //printf("I'm inside BLE thread.....\r\n"); 00276 00277 //Schedule events before starting the thread since there might be some missed events while scanning / pairing. 00278 ble.onEventsToProcess(scheduleBleEventsProcessing); 00279 ble.init(bleInitComplete); 00280 //Loop forever the BLE thread 00281 eventQueue.dispatch_forever(); 00282 } 00283 00284 /************************************************************BLE Stuff to here *********************************/ 00285 00286 // These are example resource values for the Device Object 00287 struct MbedClientDevice device = { 00288 "Manufacturer_String", // Manufacturer 00289 "Type_String", // Type 00290 "ModelNumber_String", // ModelNumber 00291 "SerialNumber_String" // SerialNumber 00292 }; 00293 00294 // Instantiate the class which implements LWM2M Client API (from simpleclient.h) 00295 MbedClient mbed_client(device); 00296 00297 00298 class EnvResource { 00299 public: 00300 EnvResource() { 00301 00302 temp_object = M2MInterfaceFactory::create_object("3303"); 00303 temp_inst = temp_object->create_object_instance(); 00304 temp_res = temp_inst->create_dynamic_resource("5700", "Temperature", 00305 M2MResourceInstance::FLOAT, true); // observable 00306 // we can only read this value 00307 temp_res->set_operation(M2MBase::GET_ALLOWED); 00308 temp_res->set_value((uint8_t*)"20.0", 4); 00309 00310 hum_object = M2MInterfaceFactory::create_object("3304"); 00311 hum_inst = hum_object->create_object_instance(); 00312 hum_res = hum_inst->create_dynamic_resource("5700", "Humidity", 00313 M2MResourceInstance::FLOAT, true); // observable 00314 // we can only read this value 00315 hum_res->set_operation(M2MBase::GET_ALLOWED); 00316 hum_res->set_value((uint8_t*)"50.0", 4); 00317 00318 press_object = M2MInterfaceFactory::create_object("3300"); 00319 press_inst = press_object->create_object_instance(); 00320 press_res = press_inst->create_dynamic_resource("5700", "Pressure", 00321 M2MResourceInstance::FLOAT, true); // observable 00322 // we can only read this value 00323 press_res->set_operation(M2MBase::GET_ALLOWED); 00324 press_res->set_value((uint8_t*)"1000", 4); 00325 00326 timer_res = press_inst->create_dynamic_resource("5603", "PollingPeriodMs", // one polling time for all env values, associated to humidity 00327 M2MResourceInstance::INTEGER, false); // not observable 00328 // we can read/wr this value 00329 timer_res->set_operation(M2MBase::GET_PUT_ALLOWED); 00330 timer_res->set_value((uint8_t*)"1000",4); // default 1s polling 00331 00332 } 00333 00334 M2MObject* get_temp_object() { 00335 return temp_object; 00336 } 00337 00338 M2MObject* get_hum_object() { 00339 return hum_object; 00340 } 00341 00342 M2MObject* get_press_object() { 00343 return press_object; 00344 } 00345 00346 int get_polling_period() { 00347 return timer_res->get_value_int(); 00348 } 00349 00350 void update_resources() { 00351 float temp; 00352 float hum; 00353 float press; 00354 00355 if (!envDataAvailable) { 00356 return; 00357 } 00358 00359 temp = (uint32_t)((dataforClient[9]<<8) | dataforClient[8])/10.0; 00360 hum = ((dataforClient[7]<<8) | dataforClient[6])/10.0; 00361 press = (uint32_t)((dataforClient[5]<<24) |(dataforClient[4]<<16) |(dataforClient[3]<<8) | dataforClient[2])/100.0; 00362 00363 stringstream ss_temp; 00364 ss_temp << temp; 00365 std::string stringified = ss_temp.str(); 00366 temp_res->set_value((uint8_t*)stringified.c_str(), stringified.length()); 00367 00368 stringstream ss_hum; 00369 ss_hum << hum; 00370 stringified = ss_hum.str(); 00371 hum_res->set_value((uint8_t*)stringified.c_str(), stringified.length()); 00372 00373 stringstream ss_press; 00374 ss_press << press; 00375 stringified = ss_press.str(); 00376 press_res->set_value((uint8_t*)stringified.c_str(), stringified.length()); 00377 00378 } 00379 00380 private: 00381 00382 M2MObject* temp_object; 00383 M2MObjectInstance* temp_inst; 00384 M2MResource* temp_res; 00385 00386 M2MObject* hum_object; 00387 M2MObjectInstance* hum_inst; 00388 M2MResource* hum_res; 00389 00390 M2MObject* press_object; 00391 M2MObjectInstance* press_inst; 00392 M2MResource* press_res; 00393 00394 M2MResource* timer_res; 00395 00396 }; 00397 00398 00399 osThreadId mainThread; 00400 00401 // Entry point to the program 00402 int main() { 00403 00404 unsigned int seed; 00405 size_t len; 00406 00407 #ifdef MBEDTLS_ENTROPY_HARDWARE_ALT 00408 // Used to randomize source port 00409 mbedtls_hardware_poll(NULL, (unsigned char *) &seed, sizeof seed, &len); 00410 00411 #elif defined MBEDTLS_TEST_NULL_ENTROPY 00412 00413 #warning "mbedTLS security feature is disabled. Connection will not be secure !! Implement proper hardware entropy for your selected hardware." 00414 // Used to randomize source port 00415 mbedtls_null_entropy_poll( NULL,(unsigned char *) &seed, sizeof seed, &len); 00416 00417 #else 00418 00419 #error "This hardware does not have entropy, endpoint will not register to Connector.\ 00420 You need to enable NULL ENTROPY for your application, but if this configuration change is made then no security is offered by mbed TLS.\ 00421 Add MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES and MBEDTLS_TEST_NULL_ENTROPY in mbed_app.json macros to register your endpoint." 00422 00423 #endif 00424 00425 srand(seed); 00426 red_led = LED_OFF; 00427 blue_led = LED_OFF; 00428 green_led = LED_OFF; 00429 00430 // Keep track of the main thread 00431 mainThread = osThreadGetId(); 00432 00433 printf("\nStarting mbed Client example\n"); 00434 00435 //mbed_trace_init(); 00436 00437 NetworkInterface* network = easy_connect(true); 00438 if(network == NULL) { 00439 printf("\nConnection to Network Failed - exiting application...\n"); 00440 return -1; 00441 } 00442 00443 // environmental data 00444 EnvResource env_resource; 00445 00446 00447 // Create endpoint interface to manage register and unregister 00448 mbed_client.create_interface(MBED_SERVER_ADDRESS, network); 00449 00450 // Create Objects of varying types, see simpleclient.h for more details on implementation. 00451 M2MSecurity* register_object = mbed_client.create_register_object(); // server object specifying connector info 00452 M2MDevice* device_object = mbed_client.create_device_object(); // device resources object 00453 00454 // Create list of Objects to register 00455 M2MObjectList object_list; 00456 00457 // Add objects to list 00458 object_list.push_back(device_object); 00459 object_list.push_back(env_resource.get_temp_object()); 00460 object_list.push_back(env_resource.get_hum_object()); 00461 object_list.push_back(env_resource.get_press_object()); 00462 00463 // Set endpoint registration object 00464 mbed_client.set_register_object(register_object); 00465 00466 // Register with mbed Device Connector 00467 mbed_client.test_register(register_object, object_list); 00468 00469 // wait for registration and BLE data started flushing 00470 while (!mbed_client.register_successful()) { 00471 Thread::wait(500); 00472 } 00473 00474 printf("\nNow starting BLE thread\n"); 00475 BLE_thread.start(BLE_thread_init); 00476 00477 while (!envDataAvailable) { 00478 Thread::wait(500); 00479 } 00480 00481 printf ("\nNow pushing data to the mbed device connector.\n"); 00482 00483 while (true) { 00484 00485 env_resource.update_resources(); 00486 int timer_val = env_resource.get_polling_period(); 00487 Thread::wait(timer_val); 00488 } 00489 00490 mbed_client.test_unregister(); 00491 00492 }
Generated on Thu Jul 14 2022 06:48:03 by 1.7.2