Embed client working with Cell network.

Dependencies:   C027Interface

Fork of U_Blox_DeviceConnector by Sarah Marsh

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