ST / Mbed OS mbed-os-example-client-Sensors_6LowPan

Dependencies:   X_NUCLEO_IKS01A2

Fork of mbed-os-example-client-Sensors_6LowPan by Nicola Capovilla

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  
00017  /* 
00018   * Modified by STMicroelectronics to support X-NUCLEO-IKS01A1/2 environmental 
00019   * sensors on top of Nucleo-F429ZI/Nucleo-L476RG.
00020  */
00021  
00022 
00023 #define __STDC_FORMAT_MACROS
00024 #include <inttypes.h>
00025 #include "simpleclient.h"
00026 #include <string>
00027 #include <sstream>
00028 #include <vector>
00029 #include "mbed-trace/mbed_trace.h"
00030 #include "mbedtls/entropy_poll.h"
00031 
00032 #include "security.h"
00033 
00034 #include "mbed.h"
00035 
00036 // easy-connect compliancy, it has 2 sets of wifi pins we have only one
00037 #define MBED_CONF_APP_ESP8266_TX MBED_CONF_APP_WIFI_TX
00038 #define MBED_CONF_APP_ESP8266_RX MBED_CONF_APP_WIFI_RX
00039 #include "easy-connect/easy-connect.h"
00040 
00041 #ifdef TARGET_STM
00042 #define RED_LED (LED3)
00043 #define GREEN_LED (LED1)
00044 #define BLUE_LED (LED2)
00045 #define LED_ON (1)           
00046 #else // !TARGET_STM
00047 #define RED_LED (LED1)
00048 #define GREEN_LED (LED2)
00049 #define BLUE_LED (LED3)              
00050 #define LED_ON (0) 
00051 #endif // !TARGET_STM
00052 #define LED_OFF (!LED_ON)
00053 
00054 // Status indication
00055 DigitalOut red_led(RED_LED);
00056 DigitalOut green_led(GREEN_LED);
00057 DigitalOut blue_led(BLUE_LED);
00058 
00059 Ticker status_ticker;
00060 void blinky() {
00061     green_led = !green_led;
00062 }
00063 
00064 // These are example resource values for the Device Object
00065 struct MbedClientDevice device = {
00066     "Manufacturer_String",      // Manufacturer
00067     "Type_String",              // Type
00068     "ModelNumber_String",       // ModelNumber
00069     "SerialNumber_String"       // SerialNumber
00070 };
00071 
00072 // Instantiate the class which implements LWM2M Client API (from simpleclient.h)
00073 MbedClient mbed_client(device);
00074 
00075 
00076 // In case of K64F board , there is button resource available
00077 // to change resource value and unregister
00078 #ifdef TARGET_K64F
00079 // Set up Hardware interrupt button.
00080 InterruptIn obs_button(SW2);
00081 InterruptIn unreg_button(SW3);
00082 #else
00083 //In non K64F boards , set up a timer to simulate updating resource,
00084 // there is no functionality to unregister.
00085 Ticker timer;
00086 #endif
00087 
00088 /*
00089  * Arguments for running "blink" in it's own thread.
00090  */
00091 class BlinkArgs {
00092 public:
00093     BlinkArgs() {
00094         clear();
00095     }
00096     void clear() {
00097         position = 0;
00098         blink_pattern.clear();
00099     }
00100     uint16_t position;
00101     std::vector<uint32_t> blink_pattern;
00102 };
00103 
00104 /*
00105  * The Led contains one property (pattern) and a function (blink).
00106  * When the function blink is executed, the pattern is read, and the LED
00107  * will blink based on the pattern.
00108  */
00109 class LedResource {
00110 public:
00111     LedResource() {
00112         // create ObjectID with metadata tag of '3201', which is 'digital output'
00113         led_object = M2MInterfaceFactory::create_object("3201");
00114         M2MObjectInstance* led_inst = led_object->create_object_instance();
00115 
00116         // 5853 = Multi-state output
00117         M2MResource* pattern_res = led_inst->create_dynamic_resource("5853", "Pattern",
00118             M2MResourceInstance::STRING, false);
00119         // read and write
00120         pattern_res->set_operation(M2MBase::GET_PUT_ALLOWED);
00121         // set initial pattern (toggle every 200ms. 7 toggles in total)
00122         pattern_res->set_value((const uint8_t*)"500:500:500:500:500:500:500", 27);
00123 
00124         // there's not really an execute LWM2M ID that matches... hmm...
00125         M2MResource* led_res = led_inst->create_dynamic_resource("5850", "Blink",
00126             M2MResourceInstance::OPAQUE, false);
00127         // we allow executing a function here...
00128         led_res->set_operation(M2MBase::POST_ALLOWED);
00129         // when a POST comes in, we want to execute the led_execute_callback
00130         led_res->set_execute_function(execute_callback(this, &LedResource::blink));
00131         // Completion of execute function can take a time, that's why delayed response is used
00132         led_res->set_delayed_response(true);
00133         blink_args = new BlinkArgs();
00134 
00135         // betzw: Start blinky thread
00136         blinky_thread.start(callback(this, &LedResource::do_blink)); // betzw - NOTE: threads can only be started once!
00137     }
00138 
00139     ~LedResource() {
00140         delete blink_args;
00141     }
00142 
00143     M2MObject* get_object() {
00144         return led_object;
00145     }
00146 
00147     void blink(void *argument) {
00148         // read the value of 'Pattern'
00149         status_ticker.detach();
00150         green_led = LED_OFF;
00151 
00152         M2MObjectInstance* inst = led_object->object_instance();
00153         M2MResource* res = inst->resource("5853");
00154         // Clear previous blink data
00155         blink_args->clear();
00156 
00157         // values in mbed Client are all buffers, and we need a vector of int's
00158         uint8_t* buffIn = NULL;
00159         uint32_t sizeIn;
00160         res->get_value(buffIn, sizeIn);
00161 
00162         // turn the buffer into a string, and initialize a vector<int> on the heap
00163         std::string s((char*)buffIn, sizeIn);
00164         free(buffIn);
00165         printf("led_execute_callback pattern=%s\n", s.c_str());
00166 
00167         // our pattern is something like 500:200:500, so parse that
00168         std::size_t found = s.find_first_of(":");
00169         while (found!=std::string::npos) {
00170             blink_args->blink_pattern.push_back(atoi((const char*)s.substr(0,found).c_str()));
00171             s = s.substr(found+1);
00172             found=s.find_first_of(":");
00173             if(found == std::string::npos) {
00174                 blink_args->blink_pattern.push_back(atoi((const char*)s.c_str()));
00175             }
00176         }
00177         // check if POST contains payload
00178         if (argument) {
00179             M2MResource::M2MExecuteParameter* param = (M2MResource::M2MExecuteParameter*)argument;
00180             String object_name = param->get_argument_object_name();
00181             uint16_t object_instance_id = param->get_argument_object_instance_id();
00182             String resource_name = param->get_argument_resource_name();
00183             int payload_length = param->get_argument_value_length();
00184             uint8_t* payload = param->get_argument_value();
00185             printf("Resource: %s/%d/%s executed\n", object_name.c_str(), object_instance_id, resource_name.c_str());
00186             printf("Payload: %.*s\n", payload_length, payload);
00187         }
00188         // do_blink is called with the vector, and starting at -1
00189         // blinky_thread.start(callback(this, &LedResource::do_blink)); // betzw - NOTE: threads can only be started once!
00190         blinky_thread.signal_set(1);
00191     }
00192 
00193 private:
00194     M2MObject* led_object;
00195     Thread blinky_thread;
00196     BlinkArgs *blink_args;
00197     void do_blink() {
00198         blinky_thread.signal_wait(0);
00199         for (;;) {
00200             // blink the LED
00201             red_led = !red_led;
00202             // up the position, if we reached the end of the vector
00203             if (blink_args->position >= blink_args->blink_pattern.size()) {
00204                 // send delayed response after blink is done
00205                 M2MObjectInstance* inst = led_object->object_instance();
00206                 M2MResource* led_res = inst->resource("5850");
00207                 led_res->send_delayed_post_response();
00208                 red_led = LED_OFF;
00209                 status_ticker.attach_us(blinky, 250000);
00210                 // betzw - WAS: return;
00211                 blinky_thread.signal_wait(0);
00212                 continue;
00213             }
00214             // Wait requested time, then continue processing the blink pattern from next position.
00215             Thread::wait(blink_args->blink_pattern.at(blink_args->position));
00216             blink_args->position++;
00217         }
00218     }
00219 };
00220 
00221 /*
00222  * The button contains one property (click count).
00223  * When `handle_button_click` is executed, the counter updates.
00224  */
00225 class ButtonResource {
00226 public:
00227     ButtonResource(): counter(0) {
00228         // create ObjectID with metadata tag of '3200', which is 'digital input'
00229         btn_object = M2MInterfaceFactory::create_object("3200");
00230         M2MObjectInstance* btn_inst = btn_object->create_object_instance();
00231         // create resource with ID '5501', which is digital input counter
00232         M2MResource* btn_res = btn_inst->create_dynamic_resource("5501", "Button",
00233             M2MResourceInstance::INTEGER, true /* observable */);
00234         // we can read this value
00235         btn_res->set_operation(M2MBase::GET_ALLOWED);
00236         // set initial value (all values in mbed Client are buffers)
00237         // to be able to read this data easily in the Connector console, we'll use a string
00238         btn_res->set_value((uint8_t*)"0", 1);
00239     }
00240 
00241     ~ButtonResource() {
00242     }
00243 
00244     M2MObject* get_object() {
00245         return btn_object;
00246     }
00247 
00248     /*
00249      * When you press the button, we read the current value of the click counter
00250      * from mbed Device Connector, then up the value with one.
00251      */
00252     void handle_button_click() {
00253         if (mbed_client.register_successful()) {
00254             M2MObjectInstance* inst = btn_object->object_instance();
00255             M2MResource* res = inst->resource("5501");
00256 
00257             // up counter
00258             counter++;
00259     #if defined(TARGET_K64F) || defined(TARGET_NUCLEO_F429ZI) || defined(TARGET_NUCLEO_L476RG)
00260             printf("handle_button_click, new value of counter is %d\r\n", counter);
00261     #else
00262             printf("simulate button_click, new value of counter is %d\n", counter);
00263     #endif
00264             // serialize the value of counter as a string, and tell connector
00265             char buffer[20];
00266             int size = sprintf(buffer,"%d",counter);
00267             res->set_value((uint8_t*)buffer, size);
00268         } else {
00269             printf("simulate button_click, device not registered\n");
00270         }
00271     }
00272 
00273 private:
00274     M2MObject* btn_object;
00275     uint16_t counter;
00276 };
00277 
00278 class BigPayloadResource {
00279 public:
00280     BigPayloadResource() {
00281         big_payload = M2MInterfaceFactory::create_object("1000");
00282         M2MObjectInstance* payload_inst = big_payload->create_object_instance();
00283         M2MResource* payload_res = payload_inst->create_dynamic_resource("1", "BigData",
00284             M2MResourceInstance::STRING, true /* observable */);
00285         payload_res->set_operation(M2MBase::GET_PUT_ALLOWED);
00286         payload_res->set_value((uint8_t*)"0", 1);
00287         payload_res->set_incoming_block_message_callback(
00288                     incoming_block_message_callback(this, &BigPayloadResource::block_message_received));
00289         payload_res->set_outgoing_block_message_callback(
00290                     outgoing_block_message_callback(this, &BigPayloadResource::block_message_requested));
00291     }
00292 
00293     M2MObject* get_object() {
00294         return big_payload;
00295     }
00296 
00297     void block_message_received(M2MBlockMessage *argument) {
00298         if (argument) {
00299             if (M2MBlockMessage::ErrorNone == argument->error_code()) {
00300                 if (argument->is_last_block()) {
00301                     printf("Last block received\n");
00302                 }
00303                 printf("Block number: %d\n", argument->block_number());
00304                 // First block received
00305                 if (argument->block_number() == 0) {
00306                     // Store block
00307                 // More blocks coming
00308                 } else {
00309                     // Store blocks
00310                 }
00311             } else {
00312                 printf("Error when receiving block message!  - EntityTooLarge\n");
00313             }
00314             printf("Total message size: %" PRIu32 "\n", argument->total_message_size());
00315         }
00316     }
00317 
00318     void block_message_requested(const String& resource, uint8_t *&/*data*/, uint32_t &/*len*/) {
00319         printf("GET request received for resource: %s\n", resource.c_str());
00320         // Copy data and length to coap response
00321     }
00322 
00323 private:
00324     M2MObject*  big_payload;
00325 };
00326 
00327 /* STMicroelectronics IKS01A1/2 code  - BEGIN */
00328 
00329 #define IKS01A2  // comment out for IKS01A1
00330 
00331 #ifdef IKS01A2
00332 #define __ARCHDEP__TYPES  // fix to a typedef redefinition with LWIP stack
00333 typedef unsigned char u8_t;
00334 typedef unsigned short int u16_t;
00335 //typedef unsigned int u32_t;  // conflictiong definition
00336 typedef int i32_t;
00337 typedef short int i16_t;
00338 typedef signed char i8_t;
00339 #include "XNucleoIKS01A2.h"
00340 #else
00341 #include "XNucleoIKS01A1.h"
00342 #endif
00343 
00344 #define SENSOR_OK   0
00345 #define DEFAULT_ENV_POLLING_PERIOD_MS   5000   // default polling time 
00346 
00347 class EnvResource {
00348 public:
00349     EnvResource() {
00350 #ifdef IKS01A2
00351         p_mems_expansion_board = XNucleoIKS01A2::instance(IKS01A2_PIN_I2C_SDA,IKS01A2_PIN_I2C_SCL);
00352 #else
00353         p_mems_expansion_board = XNucleoIKS01A1::instance(IKS01A1_PIN_I2C_SDA,IKS01A1_PIN_I2C_SCL);
00354 #endif
00355         
00356         temp_object = M2MInterfaceFactory::create_object("3303");
00357         temp_inst = temp_object->create_object_instance();
00358         temp_res = temp_inst->create_dynamic_resource("5700", "Temperature",
00359             M2MResourceInstance::FLOAT, true);  // observable
00360         // we can only read this value
00361         temp_res->set_operation(M2MBase::GET_ALLOWED);
00362         temp_res->set_value((uint8_t*)"20.0", 4);
00363         
00364         hum_object = M2MInterfaceFactory::create_object("3304");
00365         hum_inst = hum_object->create_object_instance();
00366         hum_res = hum_inst->create_dynamic_resource("5700", "Humidity",
00367             M2MResourceInstance::FLOAT, true);  // observable
00368         // we can only read this value
00369         hum_res->set_operation(M2MBase::GET_ALLOWED);
00370         hum_res->set_value((uint8_t*)"50.0", 4);
00371         
00372 #ifdef IKS01A2 // need to explicitly enable the sensor with IKS01A2
00373         HTS221Sensor *hum_temp = p_mems_expansion_board->ht_sensor;
00374         hum_temp->enable();
00375 #endif
00376         
00377         press_object = M2MInterfaceFactory::create_object("3300");
00378         press_inst = press_object->create_object_instance();
00379         press_res = press_inst->create_dynamic_resource("5700", "Pressure",
00380             M2MResourceInstance::FLOAT, true);  // observable
00381         // we can only read this value
00382         press_res->set_operation(M2MBase::GET_ALLOWED);
00383         press_res->set_value((uint8_t*)"5000", 4);
00384 
00385 #ifdef IKS01A2 // need to explicitly enable the sensor with IKS01A2
00386         LPS22HBSensor *press_temp = p_mems_expansion_board->pt_sensor;
00387         press_temp->enable();
00388 #endif
00389         
00390         timer_res = press_inst->create_dynamic_resource("5603", "PollingPeriodMs",  // one polling time for all env values, associated to humidity
00391             M2MResourceInstance::INTEGER, false);   // not observable
00392         // we can read/wr this value
00393         timer_res->set_operation(M2MBase::GET_PUT_ALLOWED);
00394         timer_res->set_value((uint8_t*)"1000",4); // default 1s polling
00395         
00396     }
00397     
00398     M2MObject* get_temp_object() {
00399         return temp_object;
00400     }
00401     
00402     M2MObject* get_hum_object() {
00403         return hum_object;
00404     }
00405     
00406     M2MObject* get_press_object() {
00407         return press_object;
00408     }
00409     
00410     int get_polling_period() {
00411         return timer_res->get_value_int();
00412     }
00413 
00414     void update_resources() {
00415        float temp;
00416        float hum;
00417        float press;
00418        int err;
00419        
00420         err = p_mems_expansion_board->ht_sensor->get_temperature(&temp);
00421        if ( err != SENSOR_OK) {  
00422             printf ("= * ERROR %d get_temperature\n\r", err);
00423             temp = 20.0;
00424             red_led = 1;
00425         } else {
00426             printf ("Temp C: %f\n\r", temp);
00427             red_led = 0;
00428         }
00429         
00430         err = p_mems_expansion_board->ht_sensor->get_humidity(&hum);
00431         if ( err != SENSOR_OK) {  
00432            printf ("= * ERROR %d get_humidity\n\r", err);
00433            hum= 50.0;
00434            red_led = 1;
00435         } else {
00436            printf ("Humidity %: %f\n\r", hum);
00437            red_led = 0;
00438         }
00439         
00440         err = p_mems_expansion_board->pt_sensor->get_pressure(&press);
00441         if ( err != SENSOR_OK) {  
00442           printf ("= * ERROR %d get_pressure\n\r", err);
00443           red_led = 1;
00444           return;
00445         } else {
00446           printf ("Pressure mBar: %f\n\r", press); 
00447           red_led = 0;
00448         }
00449         
00450         stringstream ss_temp;
00451         ss_temp << temp;
00452         std::string stringified = ss_temp.str();
00453         temp_res->set_value((uint8_t*)stringified.c_str(), stringified.length());
00454       
00455         stringstream ss_hum;
00456         ss_hum << hum;
00457         stringified = ss_hum.str();
00458         hum_res->set_value((uint8_t*)stringified.c_str(), stringified.length());
00459       
00460         stringstream ss_press;
00461         ss_press << press;
00462         stringified = ss_press.str();
00463         press_res->set_value((uint8_t*)stringified.c_str(), stringified.length()); 
00464     }
00465     
00466 private:
00467  
00468    M2MObject* temp_object;
00469    M2MObjectInstance* temp_inst;
00470    M2MResource* temp_res;
00471    
00472    M2MObject* hum_object;
00473    M2MObjectInstance* hum_inst;
00474    M2MResource* hum_res;
00475    
00476    M2MObject* press_object;
00477    M2MObjectInstance* press_inst;
00478    M2MResource* press_res;
00479    
00480    M2MResource* timer_res;
00481     
00482 #ifdef IKS01A2
00483    XNucleoIKS01A2 *p_mems_expansion_board;
00484 #else
00485    XNucleoIKS01A1 *p_mems_expansion_board; 
00486 #endif
00487 
00488 };
00489 
00490 
00491 /* STMicroelectronics IKS01A1/2 code  - END */
00492 
00493 // Network interaction must be performed outside of interrupt context
00494 Semaphore updates(0);
00495 volatile bool registered = false;
00496 volatile bool clicked = false;
00497 osThreadId mainThread;
00498 
00499 void unregister() {
00500     registered = false;
00501     blue_led = 0;
00502     updates.release();
00503 }
00504 
00505 void button_clicked() {
00506     clicked = true;
00507 }
00508 
00509 // debug printf function
00510 void trace_printer(const char* str) {
00511     printf("%s\r\n", str);
00512 }
00513 
00514 // Entry point to the program
00515 int main() {
00516 
00517     unsigned int seed;
00518     size_t len;
00519 
00520 #ifdef MBEDTLS_ENTROPY_HARDWARE_ALT
00521     // Used to randomize source port
00522     mbedtls_hardware_poll(NULL, (unsigned char *) &seed, sizeof seed, &len);
00523 
00524 #elif defined MBEDTLS_TEST_NULL_ENTROPY
00525 
00526 #warning "mbedTLS security feature is disabled. Connection will not be secure !! Implement proper hardware entropy for your selected hardware."
00527     // Used to randomize source port
00528     mbedtls_null_entropy_poll( NULL,(unsigned char *) &seed, sizeof seed, &len);
00529 
00530 #else
00531 
00532 #error "This hardware does not have entropy, endpoint will not register to Connector.\
00533 You need to enable NULL ENTROPY for your application, but if this configuration change is made then no security is offered by mbed TLS.\
00534 Add MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES and MBEDTLS_TEST_NULL_ENTROPY in mbed_app.json macros to register your endpoint."
00535 
00536 #endif
00537 
00538     srand(seed);
00539     red_led = LED_OFF;
00540     blue_led = LED_OFF;
00541 
00542     status_ticker.attach_us(blinky, 250000);
00543     // Keep track of the main thread
00544     mainThread = osThreadGetId();
00545 
00546     printf("\nStarting mbed Client example\n");
00547 
00548     mbed_trace_init();
00549     mbed_trace_print_function_set(trace_printer);
00550     mbed_trace_config_set(TRACE_MODE_COLOR | TRACE_ACTIVE_LEVEL_INFO | TRACE_CARRIAGE_RETURN);
00551 
00552     NetworkInterface* network = easy_connect(true);
00553     if(network == NULL) {
00554         printf("\nConnection to Network Failed - exiting application...\n");
00555         return -1;
00556     }
00557 
00558     // we create our button and LED resources
00559     ButtonResource button_resource;
00560     LedResource led_resource;
00561     BigPayloadResource big_payload_resource;
00562     
00563     // STMicroelectronics IKS01A1/2
00564     EnvResource env_resource;
00565 
00566     
00567 #ifdef TARGET_K64F
00568     // On press of SW3 button on K64F board, example application
00569     // will call unregister API towards mbed Device Connector
00570     //unreg_button.fall(&mbed_client,&MbedClient::test_unregister);
00571     unreg_button.fall(&unregister);
00572 
00573     // Observation Button (SW2) press will send update of endpoint resource values to connector
00574     obs_button.fall(&button_clicked);
00575 #elif defined(TARGET_NUCLEO_F429ZI) || defined (TARGET_NUCLEO_L476RG)
00576     InterruptIn user_button(USER_BUTTON);
00577     user_button.fall(&button_clicked);
00578 #else
00579     // Send update of endpoint resource values to connector every 15 seconds periodically
00580     timer.attach(&button_clicked, 15.0);
00581 #endif
00582 
00583     // Create endpoint interface to manage register and unregister
00584     mbed_client.create_interface(MBED_SERVER_ADDRESS, network);
00585 
00586     // Create Objects of varying types, see simpleclient.h for more details on implementation.
00587     M2MSecurity* register_object = mbed_client.create_register_object(); // server object specifying connector info
00588     M2MDevice*   device_object   = mbed_client.create_device_object();   // device resources object
00589 
00590     // Create list of Objects to register
00591     M2MObjectList object_list;
00592 
00593     // Add objects to list
00594     object_list.push_back(device_object);
00595     object_list.push_back(button_resource.get_object());
00596     object_list.push_back(led_resource.get_object());
00597     object_list.push_back(big_payload_resource.get_object());
00598     
00599     // STMicroelectronics IKS01A1/2
00600     object_list.push_back(env_resource.get_temp_object());
00601     object_list.push_back(env_resource.get_hum_object());
00602     object_list.push_back(env_resource.get_press_object());
00603     
00604     // Set endpoint registration object
00605     mbed_client.set_register_object(register_object);
00606 
00607     // Register with mbed Device Connector
00608     mbed_client.test_register(register_object, object_list);
00609 
00610 
00611     // STMicroelectronics IKS01A1/2
00612     // wait for registration before getting data
00613     while (!mbed_client.register_successful())  {
00614         Thread::wait(500);
00615     }
00616     registered = true;
00617     blue_led = 1;
00618     printf ("\r\nRegistered! Now getting sensor data\r\n\n");
00619         
00620     while (true) {
00621               
00622         int timer_val = env_resource.get_polling_period();
00623         env_resource.update_resources();
00624 
00625         if(clicked) {
00626             clicked = false;
00627             button_resource.handle_button_click();
00628         }
00629         Thread::wait(timer_val);
00630     }
00631 
00632     mbed_client.test_unregister();
00633     status_ticker.detach();
00634 }