U_Blox device connector

Dependencies:   mbed

Fork of mbed-os-example-client by mbed-os-examples

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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 = &eth;
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 }