Suraj Pal
/
U_Blox_DeviceConnector
U_Blox device connector
Fork of mbed-os-example-client by
Embed:
(wiki syntax)
Show/hide line numbers
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 #include "simpleclient.h" 00017 #include <string> 00018 #include <sstream> 00019 #include <vector> 00020 #include "mbed-trace/mbed_trace.h" 00021 #include "mbedtls/entropy_poll.h" 00022 00023 #include "security.h" 00024 00025 #include "mbed.h" 00026 #include "rtos.h" 00027 00028 #if MBED_CONF_APP_NETWORK_INTERFACE == WIFI 00029 #if TARGET_UBLOX_EVK_ODIN_W2 00030 #include "OdinWiFiInterface.h" 00031 OdinWiFiInterface wifi; 00032 #else 00033 #include "ESP8266Interface.h" 00034 ESP8266Interface wifi(MBED_CONF_APP_WIFI_TX, MBED_CONF_APP_WIFI_RX); 00035 #endif 00036 #elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET 00037 #include "EthernetInterface.h" 00038 EthernetInterface eth; 00039 #elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_LOWPAN_ND 00040 #define MESH 00041 #include "NanostackInterface.h" 00042 LoWPANNDInterface mesh; 00043 #elif MBED_CONF_APP_NETWORK_INTERFACE == MESH_THREAD 00044 #define MESH 00045 #include "NanostackInterface.h" 00046 ThreadInterface mesh; 00047 #endif 00048 00049 #if defined(MESH) 00050 #if MBED_CONF_APP_MESH_RADIO_TYPE == ATMEL 00051 #include "NanostackRfPhyAtmel.h" 00052 NanostackRfPhyAtmel rf_phy(ATMEL_SPI_MOSI, ATMEL_SPI_MISO, ATMEL_SPI_SCLK, ATMEL_SPI_CS, 00053 ATMEL_SPI_RST, ATMEL_SPI_SLP, ATMEL_SPI_IRQ, ATMEL_I2C_SDA, ATMEL_I2C_SCL); 00054 #elif MBED_CONF_APP_MESH_RADIO_TYPE == MCR20 00055 #include "NanostackRfPhyMcr20a.h" 00056 NanostackRfPhyMcr20a rf_phy(MCR20A_SPI_MOSI, MCR20A_SPI_MISO, MCR20A_SPI_SCLK, MCR20A_SPI_CS, MCR20A_SPI_RST, MCR20A_SPI_IRQ); 00057 #endif //MBED_CONF_APP_RADIO_TYPE 00058 #endif //MESH 00059 00060 #ifdef MESH 00061 // Mesh does not have DNS, so must use direct IPV6 address 00062 #define MBED_SERVER_ADDRESS "coaps://[2607:f0d0:2601:52::20]:5684" 00063 #else 00064 // This is address to mbed Device Connector, name based 00065 // assume all other stacks support DNS properly 00066 #define MBED_SERVER_ADDRESS "coap://api.connector.mbed.com:5684" 00067 #endif 00068 00069 RawSerial output(USBTX, USBRX); 00070 00071 // Status indication 00072 DigitalOut red_led(LED1); 00073 DigitalOut green_led(LED2); 00074 DigitalOut blue_led(LED3); 00075 Ticker status_ticker; 00076 void blinky() { 00077 green_led = !green_led; 00078 00079 } 00080 00081 // These are example resource values for the Device Object 00082 struct MbedClientDevice device = { 00083 "Manufacturer_String", // Manufacturer 00084 "Type_String", // Type 00085 "ModelNumber_String", // ModelNumber 00086 "SerialNumber_String" // SerialNumber 00087 }; 00088 00089 // Instantiate the class which implements LWM2M Client API (from simpleclient.h) 00090 MbedClient mbed_client(device); 00091 00092 00093 // In case of K64F board , there is button resource available 00094 // to change resource value and unregister 00095 #ifdef TARGET_K64F 00096 // Set up Hardware interrupt button. 00097 InterruptIn obs_button(SW2); 00098 InterruptIn unreg_button(SW3); 00099 #else 00100 //In non K64F boards , set up a timer to simulate updating resource, 00101 // there is no functionality to unregister. 00102 Ticker timer; 00103 #endif 00104 00105 /* 00106 * Arguments for running "blink" in it's own thread. 00107 */ 00108 class BlinkArgs { 00109 public: 00110 BlinkArgs() { 00111 clear(); 00112 } 00113 void clear() { 00114 position = 0; 00115 blink_pattern.clear(); 00116 } 00117 uint16_t position; 00118 std::vector<uint32_t> blink_pattern; 00119 }; 00120 00121 /* 00122 * The Led contains one property (pattern) and a function (blink). 00123 * When the function blink is executed, the pattern is read, and the LED 00124 * will blink based on the pattern. 00125 */ 00126 class LedResource { 00127 public: 00128 LedResource() { 00129 // create ObjectID with metadata tag of '3201', which is 'digital output' 00130 led_object = M2MInterfaceFactory::create_object("3201"); 00131 M2MObjectInstance* led_inst = led_object->create_object_instance(); 00132 00133 // 5853 = Multi-state output 00134 M2MResource* pattern_res = led_inst->create_dynamic_resource("5853", "Pattern", 00135 M2MResourceInstance::STRING, false); 00136 // read and write 00137 pattern_res->set_operation(M2MBase::GET_PUT_ALLOWED); 00138 // set initial pattern (toggle every 200ms. 7 toggles in total) 00139 pattern_res->set_value((const uint8_t*)"500:500:500:500:500:500:500", 27); 00140 00141 // there's not really an execute LWM2M ID that matches... hmm... 00142 M2MResource* led_res = led_inst->create_dynamic_resource("5850", "Blink", 00143 M2MResourceInstance::OPAQUE, false); 00144 // we allow executing a function here... 00145 led_res->set_operation(M2MBase::POST_ALLOWED); 00146 // when a POST comes in, we want to execute the led_execute_callback 00147 led_res->set_execute_function(execute_callback(this, &LedResource::blink)); 00148 // Completion of execute function can take a time, that's why delayed response is used 00149 led_res->set_delayed_response(true); 00150 blink_args = new BlinkArgs(); 00151 } 00152 00153 ~LedResource() { 00154 delete blink_args; 00155 } 00156 00157 M2MObject* get_object() { 00158 return led_object; 00159 } 00160 00161 void blink(void *argument) { 00162 // read the value of 'Pattern' 00163 status_ticker.detach(); 00164 green_led = 1; 00165 00166 M2MObjectInstance* inst = led_object->object_instance(); 00167 M2MResource* res = inst->resource("5853"); 00168 // Clear previous blink data 00169 blink_args->clear(); 00170 00171 // values in mbed Client are all buffers, and we need a vector of int's 00172 uint8_t* buffIn = NULL; 00173 uint32_t sizeIn; 00174 res->get_value(buffIn, sizeIn); 00175 00176 // turn the buffer into a string, and initialize a vector<int> on the heap 00177 std::string s((char*)buffIn, sizeIn); 00178 free(buffIn); 00179 output.printf("led_execute_callback pattern=%s\r\n", s.c_str()); 00180 00181 // our pattern is something like 500:200:500, so parse that 00182 std::size_t found = s.find_first_of(":"); 00183 while (found!=std::string::npos) { 00184 blink_args->blink_pattern.push_back(atoi((const char*)s.substr(0,found).c_str())); 00185 s = s.substr(found+1); 00186 found=s.find_first_of(":"); 00187 if(found == std::string::npos) { 00188 blink_args->blink_pattern.push_back(atoi((const char*)s.c_str())); 00189 } 00190 } 00191 // check if POST contains payload 00192 if (argument) { 00193 M2MResource::M2MExecuteParameter* param = (M2MResource::M2MExecuteParameter*)argument; 00194 String object_name = param->get_argument_object_name(); 00195 uint16_t object_instance_id = param->get_argument_object_instance_id(); 00196 String resource_name = param->get_argument_resource_name(); 00197 int payload_length = param->get_argument_value_length(); 00198 uint8_t* payload = param->get_argument_value(); 00199 output.printf("Resource: %s/%d/%s executed\r\n", object_name.c_str(), object_instance_id, resource_name.c_str()); 00200 output.printf("Payload: %.*s\r\n", payload_length, payload); 00201 } 00202 // do_blink is called with the vector, and starting at -1 00203 blinky_thread.start(this, &LedResource::do_blink); 00204 } 00205 00206 private: 00207 M2MObject* led_object; 00208 Thread blinky_thread; 00209 BlinkArgs *blink_args; 00210 void do_blink() { 00211 for (;;) { 00212 // blink the LED 00213 red_led = !red_led; 00214 // up the position, if we reached the end of the vector 00215 if (blink_args->position >= blink_args->blink_pattern.size()) { 00216 // send delayed response after blink is done 00217 M2MObjectInstance* inst = led_object->object_instance(); 00218 M2MResource* led_res = inst->resource("5850"); 00219 led_res->send_delayed_post_response(); 00220 red_led = 1; 00221 status_ticker.attach_us(blinky, 250000); 00222 return; 00223 } 00224 // Wait requested time, then continue prosessing the blink pattern from next position. 00225 Thread::wait(blink_args->blink_pattern.at(blink_args->position)); 00226 blink_args->position++; 00227 } 00228 } 00229 }; 00230 00231 /* 00232 * The button contains one property (click count). 00233 * When `handle_button_click` is executed, the counter updates. 00234 */ 00235 class ButtonResource { 00236 public: 00237 ButtonResource(): counter(0) { 00238 // create ObjectID with metadata tag of '3200', which is 'digital input' 00239 btn_object = M2MInterfaceFactory::create_object("3200"); 00240 M2MObjectInstance* btn_inst = btn_object->create_object_instance(); 00241 // create resource with ID '5501', which is digital input counter 00242 M2MResource* btn_res = btn_inst->create_dynamic_resource("5501", "Button", 00243 M2MResourceInstance::INTEGER, true /* observable */); 00244 // we can read this value 00245 btn_res->set_operation(M2MBase::GET_ALLOWED); 00246 // set initial value (all values in mbed Client are buffers) 00247 // to be able to read this data easily in the Connector console, we'll use a string 00248 btn_res->set_value((uint8_t*)"0", 1); 00249 } 00250 00251 ~ButtonResource() { 00252 } 00253 00254 M2MObject* get_object() { 00255 return btn_object; 00256 } 00257 00258 /* 00259 * When you press the button, we read the current value of the click counter 00260 * from mbed Device Connector, then up the value with one. 00261 */ 00262 void handle_button_click() { 00263 M2MObjectInstance* inst = btn_object->object_instance(); 00264 M2MResource* res = inst->resource("5501"); 00265 00266 // up counter 00267 counter++; 00268 #ifdef TARGET_K64F 00269 printf("handle_button_click, new value of counter is %d\r\n", counter); 00270 #else 00271 printf("simulate button_click, new value of counter is %d\r\n", counter); 00272 #endif 00273 // serialize the value of counter as a string, and tell connector 00274 char buffer[20]; 00275 int size = sprintf(buffer,"%d",counter); 00276 res->set_value((uint8_t*)buffer, size); 00277 } 00278 00279 private: 00280 M2MObject* btn_object; 00281 uint16_t counter; 00282 }; 00283 00284 class BigPayloadResource { 00285 public: 00286 BigPayloadResource() { 00287 big_payload = M2MInterfaceFactory::create_object("1000"); 00288 M2MObjectInstance* payload_inst = big_payload->create_object_instance(); 00289 M2MResource* payload_res = payload_inst->create_dynamic_resource("1", "BigData", 00290 M2MResourceInstance::STRING, true /* observable */); 00291 payload_res->set_operation(M2MBase::GET_PUT_ALLOWED); 00292 payload_res->set_value((uint8_t*)"0", 1); 00293 payload_res->set_incoming_block_message_callback( 00294 incoming_block_message_callback(this, &BigPayloadResource::block_message_received)); 00295 payload_res->set_outgoing_block_message_callback( 00296 outgoing_block_message_callback(this, &BigPayloadResource::block_message_requested)); 00297 } 00298 00299 M2MObject* get_object() { 00300 return big_payload; 00301 } 00302 00303 void block_message_received(M2MBlockMessage *argument) { 00304 if (argument) { 00305 if (M2MBlockMessage::ErrorNone == argument->error_code()) { 00306 if (argument->is_last_block()) { 00307 output.printf("Last block received\r\n"); 00308 } 00309 output.printf("Block number: %d\r\n", argument->block_number()); 00310 // First block received 00311 if (argument->block_number() == 0) { 00312 // Store block 00313 // More blocks coming 00314 } else { 00315 // Store blocks 00316 } 00317 } else { 00318 output.printf("Error when receiving block message! - EntityTooLarge\r\n"); 00319 } 00320 output.printf("Total message size: %d\r\n", argument->total_message_size()); 00321 } 00322 } 00323 00324 void block_message_requested(const String& resource, uint8_t *&/*data*/, uint32_t &/*len*/) { 00325 output.printf("GET request received for resource: %s\r\n", resource.c_str()); 00326 // Copy data and length to coap response 00327 } 00328 00329 private: 00330 M2MObject* big_payload; 00331 }; 00332 00333 // Network interaction must be performed outside of interrupt context 00334 Semaphore updates(0); 00335 volatile bool registered = false; 00336 volatile bool clicked = false; 00337 osThreadId mainThread; 00338 00339 void unregister() { 00340 registered = false; 00341 updates.release(); 00342 } 00343 00344 void button_clicked() { 00345 clicked = true; 00346 updates.release(); 00347 } 00348 00349 // debug printf function 00350 void trace_printer(const char* str) { 00351 printf("%s\r\n", str); 00352 } 00353 00354 // Entry point to the program 00355 int main() { 00356 00357 unsigned int seed; 00358 size_t len; 00359 00360 #ifdef MBEDTLS_ENTROPY_HARDWARE_ALT 00361 // Used to randomize source port 00362 mbedtls_hardware_poll(NULL, (unsigned char *) &seed, sizeof seed, &len); 00363 00364 #elif defined MBEDTLS_TEST_NULL_ENTROPY 00365 00366 #warning "mbedTLS security feature is disabled. Connection will not be secure !! Implement proper hardware entropy for your selected hardware." 00367 // Used to randomize source port 00368 mbedtls_null_entropy_poll( NULL,(unsigned char *) &seed, sizeof seed, &len); 00369 00370 #else 00371 00372 #error "This hardware does not have entropy, endpoint will not register to Connector.\ 00373 You need to enable NULL ENTROPY for your application, but if this configuration change is made then no security is offered by mbed TLS.\ 00374 Add MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES and MBEDTLS_TEST_NULL_ENTROPY in mbed_app.json macros to register your endpoint." 00375 00376 #endif 00377 00378 srand(seed); 00379 red_led = 1; 00380 blue_led = 1; 00381 status_ticker.attach_us(blinky, 250000); 00382 // Keep track of the main thread 00383 mainThread = osThreadGetId(); 00384 00385 // Sets the console baud-rate 00386 output.baud(115200); 00387 00388 output.printf("\r\nStarting mbed Client example in "); 00389 #if defined (MESH) || (MBED_CONF_LWIP_IPV6_ENABLED==true) 00390 output.printf("IPv6 mode\r\n"); 00391 #else 00392 output.printf("IPv4 mode\r\n"); 00393 #endif 00394 00395 mbed_trace_init(); 00396 mbed_trace_print_function_set(trace_printer); 00397 00398 NetworkInterface *network_interface = 0; 00399 int connect_success = -1; 00400 #if MBED_CONF_APP_NETWORK_INTERFACE == WIFI 00401 output.printf("\n\rConnecting to WiFi...\r\n"); 00402 connect_success = wifi.connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2); 00403 network_interface = &wifi; 00404 #elif MBED_CONF_APP_NETWORK_INTERFACE == ETHERNET 00405 output.printf("\n\rConnecting to ethernet...\r\n"); 00406 connect_success = eth.connect(); 00407 network_interface = ð 00408 #endif 00409 #ifdef MESH 00410 output.printf("\n\rConnecting to Mesh...\r\n"); 00411 mesh.initialize(&rf_phy); 00412 connect_success = mesh.connect(); 00413 network_interface = &mesh; 00414 #endif 00415 if(connect_success == 0) { 00416 output.printf("\n\rConnected to Network successfully\r\n"); 00417 } else { 00418 output.printf("\n\rConnection to Network Failed %d! Exiting application....\r\n", connect_success); 00419 return 0; 00420 } 00421 const char *ip_addr = network_interface->get_ip_address(); 00422 if (ip_addr) { 00423 output.printf("IP address %s\r\n", ip_addr); 00424 } else { 00425 output.printf("No IP address\r\n"); 00426 } 00427 00428 // we create our button and LED resources 00429 ButtonResource button_resource; 00430 LedResource led_resource; 00431 BigPayloadResource big_payload_resource; 00432 00433 #ifdef TARGET_K64F 00434 // On press of SW3 button on K64F board, example application 00435 // will call unregister API towards mbed Device Connector 00436 //unreg_button.fall(&mbed_client,&MbedClient::test_unregister); 00437 unreg_button.fall(&unregister); 00438 00439 // Observation Button (SW2) press will send update of endpoint resource values to connector 00440 obs_button.fall(&button_clicked); 00441 #else 00442 // Send update of endpoint resource values to connector every 15 seconds periodically 00443 timer.attach(&button_clicked, 15.0); 00444 #endif 00445 00446 // Create endpoint interface to manage register and unregister 00447 mbed_client.create_interface(MBED_SERVER_ADDRESS, network_interface); 00448 00449 // Create Objects of varying types, see simpleclient.h for more details on implementation. 00450 M2MSecurity* register_object = mbed_client.create_register_object(); // server object specifying connector info 00451 M2MDevice* device_object = mbed_client.create_device_object(); // device resources object 00452 00453 // Create list of Objects to register 00454 M2MObjectList object_list; 00455 00456 // Add objects to list 00457 object_list.push_back(device_object); 00458 object_list.push_back(button_resource.get_object()); 00459 object_list.push_back(led_resource.get_object()); 00460 object_list.push_back(big_payload_resource.get_object()); 00461 00462 // Set endpoint registration object 00463 mbed_client.set_register_object(register_object); 00464 00465 // Register with mbed Device Connector 00466 mbed_client.test_register(register_object, object_list); 00467 registered = true; 00468 00469 while (true) { 00470 updates.wait(25000); 00471 if(registered) { 00472 if(!clicked) { 00473 mbed_client.test_update_register(); 00474 } 00475 }else { 00476 break; 00477 } 00478 if(clicked) { 00479 clicked = false; 00480 button_resource.handle_button_click(); 00481 } 00482 } 00483 00484 mbed_client.test_unregister(); 00485 status_ticker.detach(); 00486 }
Generated on Tue Jul 12 2022 18:36:52 by 1.7.2