Doug Anson / mbedConnectorInterfaceV3
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DynamicResource.cpp Source File

DynamicResource.cpp

Go to the documentation of this file.
00001 /**
00002  * @file    DynamicResource.cpp
00003  * @brief   mbed CoAP Endpoint Dynamic Resource class
00004  * @author  Doug Anson/Chris Paola
00005  * @version 1.0
00006  * @see
00007  *
00008  * Copyright (c) 2014
00009  *
00010  * Licensed under the Apache License, Version 2.0 (the "License");
00011  * you may not use this file except in compliance with the License.
00012  * You may obtain a copy of the License at
00013  *
00014  *     http://www.apache.org/licenses/LICENSE-2.0
00015  *
00016  * Unless required by applicable law or agreed to in writing, software
00017  * distributed under the License is distributed on an "AS IS" BASIS,
00018  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00019  * See the License for the specific language governing permissions and
00020  * limitations under the License.
00021  */
00022 
00023 #include "mbed-connector-interface/DynamicResource.h"
00024 
00025 // ResourceObserver help
00026 #include "mbed-connector-interface/ResourceObserver.h"
00027 
00028 // Options enablement
00029 #include "mbed-connector-interface/Options.h"
00030 
00031 // Endpoint 
00032 #include "mbed-connector-interface/ConnectorEndpoint.h"
00033 
00034 // GET option that can be used to Start/Stop Observations...
00035 #define START_OBS 0
00036 #define STOP_OBS  1
00037 
00038 // MaxAge support for each DynamicResource
00039 #define DEFAULT_MAXAGE 60
00040 
00041 // ContentFormat defaults for each DynamicResource
00042 #define DEFAULT_CONTENT_FORMAT 0
00043 
00044 // default constructor
00045 DynamicResource::DynamicResource(const Logger *logger,const char *obj_name,const char *res_name,const char *res_type,uint8_t res_mask,const bool observable) : Resource<string>(logger,string(obj_name),string(res_name),string(""))
00046 {
00047     this->m_res_type = string(res_type);
00048     this->m_observable = observable;
00049     this->m_res_mask = res_mask;
00050     this->m_obs_number = 0;
00051     this->m_data_wrapper = NULL;
00052     this->m_observer = NULL;
00053     this->m_maxage = DEFAULT_MAXAGE;
00054     this->m_content_format = DEFAULT_CONTENT_FORMAT;
00055     this->m_object = NULL;
00056     this->m_op_processor = NULL;
00057 }
00058 
00059 // constructor (input initial value)
00060 DynamicResource::DynamicResource(const Logger *logger,const char *obj_name,const char *res_name,const char *res_type,const string value,uint8_t res_mask,const bool observable) : Resource<string>(logger,string(obj_name),string(res_name),value)
00061 {
00062     this->m_res_type = string(res_type);
00063     this->m_observable = observable;
00064     this->m_res_mask = res_mask;
00065     this->m_obs_number = 0;
00066     this->m_data_wrapper = NULL;
00067     this->m_observer = NULL;
00068     this->m_maxage = DEFAULT_MAXAGE;
00069     this->m_content_format = DEFAULT_CONTENT_FORMAT;
00070     this->m_object = NULL;
00071     this->m_op_processor = NULL;
00072 }
00073 
00074 // constructor (strings)
00075 DynamicResource::DynamicResource(const Logger *logger,const string obj_name,const string res_name,const string res_type,const string value,uint8_t res_mask,const bool observable) : Resource<string>(logger,obj_name,res_name,value)
00076 {
00077     this->m_res_type = res_type;
00078     this->m_observable = observable;
00079     this->m_res_mask = res_mask;
00080     this->m_obs_number = 0;
00081     this->m_data_wrapper = NULL;
00082     this->m_observer = NULL;
00083     this->m_maxage = DEFAULT_MAXAGE;
00084     this->m_content_format = DEFAULT_CONTENT_FORMAT;
00085     this->m_object = NULL;
00086     this->m_op_processor = NULL;
00087 }
00088 
00089 // copy constructor
00090 DynamicResource::DynamicResource(const DynamicResource &resource) : Resource<string>((const Resource<string> &)resource)
00091 {
00092     this->m_res_type = resource.m_res_type;
00093     this->m_observable = resource.m_observable;
00094     this->m_res_mask = resource.m_res_mask;
00095     this->m_obs_number = resource.m_obs_number;
00096     this->m_data_wrapper = resource.m_data_wrapper;
00097     this->m_observer = resource.m_observer;
00098     this->m_maxage = resource.m_maxage;
00099     this->m_content_format = resource.m_content_format;
00100     this->m_object = resource.m_object;
00101     this->m_op_processor = resource.m_op_processor;
00102 }
00103 
00104 // destructor
00105 DynamicResource::~DynamicResource() {
00106 }
00107 
00108 // bind CoAP Resource...
00109 M2MObject *DynamicResource::bind(void *p) {
00110     if (p != NULL) {
00111         this->m_object = M2MInterfaceFactory::create_object(this->getObjName().c_str());
00112         if (this->m_object != NULL) {
00113             this->m_obj_instance = this->m_object->create_object_instance();
00114             if (this->m_obj_instance != NULL) {
00115                     this->m_res = this->m_obj_instance->create_dynamic_resource(this->getResName().c_str(),this->m_res_type.c_str(),M2MResourceInstance::STRING,this->m_observable);
00116                     if (this->m_res != NULL) {   
00117                         // perform an initial get() to initialize our data value
00118                         this->setValue(this->get());
00119                         
00120                         // now record the data value                    
00121                         if (this->getDataWrapper() != NULL) {
00122                             // wrap the data...
00123                             this->getDataWrapper()->wrap((uint8_t *)this->getValue().c_str(),(int)this->getValue().size());
00124                             this->m_res->set_operation((M2MBase::Operation)this->m_res_mask);
00125                             this->m_res->set_value( this->getDataWrapper()->get(),(uint8_t)this->getDataWrapper()->length());
00126                             this->logger()->log("%s: [%s] value: [%s] bound (observable: %d)",this->m_res_type.c_str(),this->getFullName().c_str(),this->getDataWrapper()->get(),this->m_observable);
00127                             this->m_op_processor = (void *)p;
00128                         }
00129                         else {
00130                             // do not wrap the data...
00131                             this->m_res->set_operation((M2MBase::Operation)this->m_res_mask);
00132                             this->m_res->set_value((uint8_t *)this->getValue().c_str(),(uint8_t)this->getValue().size());
00133                             this->logger()->log("%s: [%s] value: [%s] bound (observable: %d)",this->m_res_type.c_str(),this->getFullName().c_str(),this->getValue().c_str(),this->m_observable);
00134                             this->m_op_processor = (void *)p;
00135                         }
00136                         
00137                         // For POST-enabled  RESOURCES (only...), we must add a callback
00138                         if ((this->m_res_mask & M2MBase::POST_ALLOWED)  != 0) { 
00139                             // add a callback for the execute function...we will just direct through process()...
00140                             //this->logger()->log("DynamicResource::bind(): Setting up POST execute callback function");
00141                             this->m_res->set_execute_function(execute_callback(this, &DynamicResource::process_resource_post));
00142                         }
00143 
00144 // DISABLE for now...
00145 #if 0                        
00146                         // For DELETE-enabled  RESOURCES (only...), we must add a callback
00147                         if ((this->m_res_mask & M2MBase::DELETE_ALLOWED)  != 0) { 
00148                             // add a callback for the execute function...we will just direct through process()...
00149                             //this->logger()->log("DynamicResource::bind(): Setting up DELETE execute callback function");
00150                             this->m_res->set_execute_function(execute_callback(this, &DynamicResource::process_resource_delete));
00151                         }
00152 #endif              
00153                     }
00154                     else {
00155                         // create_dynamic_resource() failed
00156                         this->logger()->log("%s: Unable to create dynamic resource...",this->m_res_type.c_str());
00157                         delete this->m_object;
00158                         this->m_object = NULL;
00159                     }
00160              }
00161              else {
00162                     // create_object_instance() failed...
00163                     this->logger()->log("%s: Unable to create object instance...",this->m_res_type.c_str());
00164                     delete this->m_object;
00165                     this->m_object = NULL;
00166              }
00167        }
00168        else {
00169             // create_object() failed
00170             this->logger()->log("%s: Unable to create object...",this->m_res_type.c_str());
00171        }
00172     }
00173     else {
00174          this->logger()->log("%s: NULL value parameter in bind() request...",this->m_res_type.c_str());
00175     }
00176     return this->m_object;
00177 }
00178 
00179 // get our M2MBase representation
00180 M2MBase *DynamicResource::getResource() {
00181     return (M2MBase *)this->m_res;
00182 }
00183 
00184 // process inbound mbed-client POST message for a Resource
00185 void DynamicResource::process_resource_post(void *args) {
00186         // just call process() for POST and Resources...
00187         //this->logger()->log("DynamicResource::process_resource_post(): calling process(POST)");
00188         (void)this->process(M2MBase::POST_ALLOWED,this->m_res->base_type(),args);
00189 }
00190 
00191 // process inbound mbed-client DELETE message for a Resource
00192 void DynamicResource::process_resource_delete(void *args) {
00193         // just call process() for DELETE and Resources...
00194         //this->logger()->log("DynamicResource::process_resource_delete(): calling process(DELETE)");
00195         (void)this->process(M2MBase::DELETE_ALLOWED,this->m_res->base_type(),args);
00196 }
00197 
00198 // process inbound mbed-client message
00199 uint8_t DynamicResource::process(M2MBase::Operation op,M2MBase::BaseType type,void *args) {
00200 #if defined (HAS_EXECUTE_PARAMS)
00201      M2MResource::M2MExecuteParameter* param = NULL;
00202      
00203      // cast args if present...
00204      if (args != NULL) {
00205         param = (M2MResource::M2MExecuteParameter*)args;
00206      }
00207 #endif  
00208     // DEBUG
00209     //this->logger()->log("in %s::process()  Operation=0x0%x Type=%x%x",this->m_res_type.c_str(),op,type);
00210     
00211     // PUT() check
00212     if ((op & M2MBase::PUT_ALLOWED) != 0) {
00213         string value = this->coapDataToString(this->m_res->value(),this->m_res->value_length());
00214         this->logger()->log("%s: Calling resource(PUT) with [%s]=[%s]",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str());
00215         this->put(value.c_str());
00216         return 0;
00217     }
00218  
00219 #if defined (HAS_EXECUTE_PARAMS)   
00220     // POST() check
00221     if ((op & M2MBase::POST_ALLOWED) != 0) {
00222         string value;
00223         if (param != NULL) {
00224             // use parameters
00225             String object_name = param->get_argument_object_name();
00226             int instance_id = (int)param->get_argument_object_instance_id();
00227             String resource_name = param->get_argument_resource_name();
00228             value = this->coapDataToString(param->get_argument_value(),param->get_argument_value_length());
00229             this->logger()->log("%s:  post() (resource: [%s/%d/%s] value: [%s]) invoked",this->m_res_type.c_str(),object_name.c_str(),instance_id,resource_name.c_str(),value.c_str());
00230         }
00231         else {
00232             // use the resource value itself
00233             value = this->coapDataToString(this->m_res->value(),this->m_res->value_length());
00234             this->logger()->log("%s:  post() (resource: [%s]  value: [%s] invoked",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str());
00235         }
00236         
00237         // invoke
00238         this->post(args);
00239         return 0;
00240     }
00241 #else  
00242     // POST() check
00243     if ((op & M2MBase::POST_ALLOWED) != 0) {
00244         if (args != NULL) {
00245             this->logger()->log("%s: Calling resource(POST) with [%s]=[%s]",this->m_res_type.c_str(),this->getFullName().c_str(),(char *)args);
00246             this->post(args);
00247         }
00248         else {
00249             string value = this->coapDataToString(this->m_res->value(),this->m_res->value_length());
00250             this->logger()->log("%s: Calling resource(POST) with [%s]=[%s]",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str());
00251             this->post((void *)value.c_str());
00252         }
00253         return 0;
00254     }
00255 #endif
00256 
00257 #if defined (HAS_EXECUTE_PARAMS)
00258     // DELETE() check
00259     if ((op & M2MBase::DELETE_ALLOWED) != 0) {
00260         if (param != NULL) {
00261             // use parameters
00262             String object_name = param->get_argument_object_name();
00263             int instance_id = (int)param->get_argument_object_instance_id();
00264             String resource_name = param->get_argument_resource_name();
00265             string value = this->coapDataToString(param->get_argument_value(),param->get_argument_value_length());
00266             this->logger()->log("%s:  delete() (resource: [%s/%d/%s] value: [%s]) invoked",this->m_res_type.c_str(),object_name.c_str(),instance_id,resource_name.c_str(),value.c_str());
00267         }
00268         else {
00269             // use the resource value itself
00270             string value = this->coapDataToString(this->m_res->value(),this->m_res->value_length());
00271             this->logger()->log("%s:  delete() (resource: [%s]  value: [%s] invoked",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str());
00272         }
00273         
00274         // invoke
00275         this->del(args);
00276         return 0;
00277     }
00278 #else     
00279     // DELETE() check
00280     if ((op & M2MBase::DELETE_ALLOWED) != 0) {
00281         if (args != NULL) {
00282             this->logger()->log("%s: Calling resource(DELETE) with [%s]=[%s]",this->m_res_type.c_str(),this->getFullName().c_str(),(char *)args);
00283             this->del(args);
00284         }
00285         else {
00286             string value = this->coapDataToString(this->m_res->value(),this->m_res->value_length());
00287             this->logger()->log("%s: Calling resource(DELETE) with [%s]=[%s]",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str());
00288             this->del((void *)value.c_str());
00289         }
00290      }
00291 #endif
00292      
00293      // unknown type...
00294      this->logger()->log("%s: Unknown Operation (0x%x) for [%s]=[%s]... FAILED.",op,this->m_res_type.c_str(),this->getFullName().c_str(),this->m_res->value());
00295      return 1;
00296 }
00297 
00298 // send the notification
00299 int DynamicResource::notify(const string data) {
00300     return this->notify((uint8_t *)data.c_str(),(int)data.length());
00301 }
00302 
00303 // send the notification
00304 int DynamicResource::notify(uint8_t *data,int data_length) {
00305     uint8_t *notify_data = NULL;
00306     int notify_data_length = 0;
00307     int status = 0;
00308 
00309     // convert the string from the GET to something suitable for CoAP payloads
00310     if (this->getDataWrapper() != NULL) {
00311         // wrap the data...
00312         this->getDataWrapper()->wrap((uint8_t *)data,data_length);
00313 
00314         // announce (after wrap)
00315         //this->logger()->log("Notify payload [%s]...",this->getDataWrapper()->get());
00316 
00317         // fill notify
00318         notify_data_length = this->getDataWrapper()->length();
00319         notify_data = this->getDataWrapper()->get();
00320     }
00321     else {
00322         // announce (no wrap)
00323         //this->logger()->log("Notify payload [%s]...",data);
00324 
00325         // do not wrap the data...
00326         notify_data_length = data_length;
00327         notify_data = data;
00328     }
00329     
00330     // update the resource
00331     this->m_res->set_value((uint8_t *)notify_data,(uint8_t)notify_data_length);
00332 
00333     // return our status
00334     return status;
00335 }
00336 
00337 // default PUT (does nothing)
00338 void DynamicResource::put(const string value)
00339 {
00340     // not used by default
00341     this->logger()->log("DynamicResource::put() invoked (NOOP)");
00342 }
00343 
00344 // default POST (does nothing)
00345 void DynamicResource::post(void *args)
00346 {
00347     // not used by default
00348     this->logger()->log("DynamicResource::post() invoked (NOOP)");
00349 }
00350 
00351 // default DELETE (does nothing)
00352 void DynamicResource::del(void *args)
00353 {
00354     // not used by default
00355     this->logger()->log("DynamicResource::del() invoked (NOOP)");
00356 }
00357 
00358 // default observe behavior
00359 void DynamicResource::observe() {
00360     if (this->m_observable == true && this->isRegistered() == true) {
00361         this->notify(this->get());
00362     }
00363 }
00364 
00365 // set the observer pointer
00366 void DynamicResource::setObserver(void *observer) {
00367     this->m_observer = observer;
00368 }
00369 
00370 // set the content-format in responses
00371 void DynamicResource::setContentFormat(uint8_t content_format) {
00372     this->m_content_format = content_format;
00373 }
00374 
00375 // set the max-age of responses
00376 void DynamicResource::setMaxAge(uint8_t maxage) {
00377     this->m_maxage = maxage;
00378 }
00379 
00380 // convenience method to get the URI from its buffer field...
00381 string DynamicResource::coapDataToString(uint8_t *coap_data_ptr,int coap_data_ptr_length)
00382 {
00383     if (coap_data_ptr != NULL && coap_data_ptr_length > 0) {
00384         if (this->getDataWrapper() != NULL) {
00385             // unwrap the data...
00386             this->getDataWrapper()->unwrap(coap_data_ptr,coap_data_ptr_length);
00387             char *buf = (char *)this->getDataWrapper()->get();                  // assumes data is null terminated in DataWrapper...
00388             return string(buf);
00389         }
00390         else {
00391             // no unwrap of the data...
00392             char buf[MAX_VALUE_BUFFER_LENGTH+1];
00393             memset(buf,0,MAX_VALUE_BUFFER_LENGTH+1);
00394             memcpy(buf,(char *)coap_data_ptr,coap_data_ptr_length);
00395             return string(buf);
00396         }
00397     }
00398     return string("");
00399 }
00400 
00401 // Determine if we are connected or not
00402 bool DynamicResource::isConnected() {
00403     bool is_connected = false;
00404     
00405     // get our Endpoint
00406     Connector::Endpoint *ep = (Connector::Endpoint *)this->m_endpoint;
00407     if (ep != NULL)  {
00408         is_connected = ep->isConnected();
00409         if (is_connected) {
00410             //this->logger()->log("DynamicResource::isConnected = true");
00411         }
00412         else { 
00413             //this->logger()->log("DynamicResource::isConnected = false");
00414         }
00415     }
00416     else {
00417         this->logger()->log("DynamicResource::isConnected = false (no endpoint)");
00418     }
00419     
00420     // return our endpoint connection state
00421     return is_connected;
00422 }
00423 
00424 // Determine if we are registered or not
00425 bool DynamicResource::isRegistered() {
00426     bool is_registered = false;
00427     
00428     if (this->isConnected() == true) {
00429         // get our Endpoint
00430         Connector::Endpoint *ep = (Connector::Endpoint *)this->m_endpoint;
00431         if (ep != NULL)  {
00432             is_registered = ep->isRegistered();
00433             if (is_registered) {
00434                 //this->logger()->log("DynamicResource::isRegistered = true");
00435             }
00436             else { 
00437                 //this->logger()->log("DynamicResource::isRegistered = false");
00438             }
00439         }
00440         else {
00441             this->logger()->log("DynamicResource::isRegistered = false (no endpoint)");
00442         }
00443     }
00444     
00445     // return our endpoint registration state
00446     return is_registered;
00447 }