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