mbed Connector Interface simplification API on top of mbed-client
Fork of mbedConnectorInterfaceV3 by
NOTE:
This repo has been replaced with https://github.com/ARMmbed/mbedConnectorInterface. No further updates will occur with this repo. Please use the github repo instead. Thanks!
source/DynamicResource.cpp
- Committer:
- ansond
- Date:
- 2016-06-10
- Revision:
- 21:0bbe9057e7b1
- Parent:
- 17:defb680f8fce
- Child:
- 24:c92984bede9c
File content as of revision 21:0bbe9057e7b1:
/** * @file DynamicResource.cpp * @brief mbed CoAP Endpoint Dynamic Resource class * @author Doug Anson/Chris Paola * @version 1.0 * @see * * Copyright (c) 2014 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mbed-connector-interface/DynamicResource.h" // ResourceObserver help #include "mbed-connector-interface/ResourceObserver.h" // Options enablement #include "mbed-connector-interface/Options.h" // Endpoint #include "mbed-connector-interface/ConnectorEndpoint.h" // GET option that can be used to Start/Stop Observations... #define START_OBS 0 #define STOP_OBS 1 // MaxAge support for each DynamicResource #define DEFAULT_MAXAGE 60 // ContentFormat defaults for each DynamicResource #define DEFAULT_CONTENT_FORMAT 0 // default constructor 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("")) { this->m_res_type = string(res_type); this->m_observable = observable; this->m_res_mask = res_mask; this->m_obs_number = 0; this->m_data_wrapper = NULL; this->m_observer = NULL; this->m_maxage = DEFAULT_MAXAGE; this->m_content_format = DEFAULT_CONTENT_FORMAT; this->m_object = NULL; this->m_op_processor = NULL; } // constructor (input initial value) 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) { this->m_res_type = string(res_type); this->m_observable = observable; this->m_res_mask = res_mask; this->m_obs_number = 0; this->m_data_wrapper = NULL; this->m_observer = NULL; this->m_maxage = DEFAULT_MAXAGE; this->m_content_format = DEFAULT_CONTENT_FORMAT; this->m_object = NULL; this->m_op_processor = NULL; } // constructor (strings) 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) { this->m_res_type = res_type; this->m_observable = observable; this->m_res_mask = res_mask; this->m_obs_number = 0; this->m_data_wrapper = NULL; this->m_observer = NULL; this->m_maxage = DEFAULT_MAXAGE; this->m_content_format = DEFAULT_CONTENT_FORMAT; this->m_object = NULL; this->m_op_processor = NULL; } // copy constructor DynamicResource::DynamicResource(const DynamicResource &resource) : Resource<string>((const Resource<string> &)resource) { this->m_res_type = resource.m_res_type; this->m_observable = resource.m_observable; this->m_res_mask = resource.m_res_mask; this->m_obs_number = resource.m_obs_number; this->m_data_wrapper = resource.m_data_wrapper; this->m_observer = resource.m_observer; this->m_maxage = resource.m_maxage; this->m_content_format = resource.m_content_format; this->m_object = resource.m_object; this->m_op_processor = resource.m_op_processor; } // destructor DynamicResource::~DynamicResource() { } // bind CoAP Resource... M2MObject *DynamicResource::bind(void *p) { if (p != NULL) { this->m_object = M2MInterfaceFactory::create_object(this->getObjName().c_str()); if (this->m_object != NULL) { this->m_obj_instance = this->m_object->create_object_instance(); if (this->m_obj_instance != NULL) { 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); if (this->m_res != NULL) { // perform an initial get() to initialize our data value this->setValue(this->get()); // now record the data value if (this->getDataWrapper() != NULL) { // wrap the data... this->getDataWrapper()->wrap((uint8_t *)this->getValue().c_str(),(int)this->getValue().size()); this->m_res->set_operation((M2MBase::Operation)this->m_res_mask); this->m_res->set_value( this->getDataWrapper()->get(),(uint8_t)this->getDataWrapper()->length()); 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); this->m_op_processor = (void *)p; } else { // do not wrap the data... this->m_res->set_operation((M2MBase::Operation)this->m_res_mask); this->m_res->set_value((uint8_t *)this->getValue().c_str(),(uint8_t)this->getValue().size()); 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); this->m_op_processor = (void *)p; } // For POST-enabled RESOURCES (only...), we must add a callback if ((this->m_res_mask & M2MBase::POST_ALLOWED) != 0) { // add a callback for the execute function...we will just direct through process()... //this->logger()->log("DynamicResource::bind(): Setting up POST execute callback function"); this->m_res->set_execute_function(execute_callback(this, &DynamicResource::process_resource_post)); } // DISABLE for now... #if 0 // For DELETE-enabled RESOURCES (only...), we must add a callback if ((this->m_res_mask & M2MBase::DELETE_ALLOWED) != 0) { // add a callback for the execute function...we will just direct through process()... //this->logger()->log("DynamicResource::bind(): Setting up DELETE execute callback function"); this->m_res->set_execute_function(execute_callback(this, &DynamicResource::process_resource_delete)); } #endif } else { // create_dynamic_resource() failed this->logger()->log("%s: Unable to create dynamic resource...",this->m_res_type.c_str()); delete this->m_object; this->m_object = NULL; } } else { // create_object_instance() failed... this->logger()->log("%s: Unable to create object instance...",this->m_res_type.c_str()); delete this->m_object; this->m_object = NULL; } } else { // create_object() failed this->logger()->log("%s: Unable to create object...",this->m_res_type.c_str()); } } else { this->logger()->log("%s: NULL value parameter in bind() request...",this->m_res_type.c_str()); } return this->m_object; } // get our M2MBase representation M2MBase *DynamicResource::getResource() { return (M2MBase *)this->m_res; } // process inbound mbed-client POST message for a Resource void DynamicResource::process_resource_post(void *args) { // just call process() for POST and Resources... //this->logger()->log("DynamicResource::process_resource_post(): calling process(POST)"); (void)this->process(M2MBase::POST_ALLOWED,this->m_res->base_type(),args); } // process inbound mbed-client DELETE message for a Resource void DynamicResource::process_resource_delete(void *args) { // just call process() for DELETE and Resources... //this->logger()->log("DynamicResource::process_resource_delete(): calling process(DELETE)"); (void)this->process(M2MBase::DELETE_ALLOWED,this->m_res->base_type(),args); } // process inbound mbed-client message uint8_t DynamicResource::process(M2MBase::Operation op,M2MBase::BaseType type,void *args) { #if defined (HAS_EXECUTE_PARAMS) M2MResource::M2MExecuteParameter* param = NULL; // cast args if present... if (args != NULL) { param = (M2MResource::M2MExecuteParameter*)args; } #endif // DEBUG //this->logger()->log("in %s::process() Operation=0x0%x Type=%x%x",this->m_res_type.c_str(),op,type); // PUT() check if ((op & M2MBase::PUT_ALLOWED) != 0) { string value = this->coapDataToString(this->m_res->value(),this->m_res->value_length()); this->logger()->log("%s: Calling resource(PUT) with [%s]=[%s]",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str()); this->put(value.c_str()); return 0; } #if defined (HAS_EXECUTE_PARAMS) // POST() check if ((op & M2MBase::POST_ALLOWED) != 0) { string value; if (param != NULL) { // use parameters String object_name = param->get_argument_object_name(); int instance_id = (int)param->get_argument_object_instance_id(); String resource_name = param->get_argument_resource_name(); value = this->coapDataToString(param->get_argument_value(),param->get_argument_value_length()); 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()); } else { // use the resource value itself value = this->coapDataToString(this->m_res->value(),this->m_res->value_length()); this->logger()->log("%s: post() (resource: [%s] value: [%s] invoked",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str()); } // invoke this->post(args); return 0; } #else // POST() check if ((op & M2MBase::POST_ALLOWED) != 0) { string value = this->coapDataToString(this->m_res->value(),this->m_res->value_length()); this->logger()->log("%s: Calling resource(POST) with [%s]=[%s]",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str()); this->post((void *)value.c_str()); return 0; } #endif #if defined (HAS_EXECUTE_PARAMS) // DELETE() check if ((op & M2MBase::DELETE_ALLOWED) != 0) { if (param != NULL) { // use parameters String object_name = param->get_argument_object_name(); int instance_id = (int)param->get_argument_object_instance_id(); String resource_name = param->get_argument_resource_name(); string value = this->coapDataToString(param->get_argument_value(),param->get_argument_value_length()); 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()); } else { // use the resource value itself string value = this->coapDataToString(this->m_res->value(),this->m_res->value_length()); this->logger()->log("%s: delete() (resource: [%s] value: [%s] invoked",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str()); } // invoke this->del(args); return 0; } #else // DELETE() check if ((op & M2MBase::DELETE_ALLOWED) != 0) { string value = this->coapDataToString(this->m_res->value(),this->m_res->value_length()); this->logger()->log("%s: Calling resource(DELETE) with [%s]=[%s]",this->m_res_type.c_str(),this->getFullName().c_str(),value.c_str()); this->del((void *)value.c_str()); return 0; } #endif // unknown type... 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()); return 1; } // send the notification int DynamicResource::notify(const string data) { return this->notify((uint8_t *)data.c_str(),(int)data.length()); } // send the notification int DynamicResource::notify(uint8_t *data,int data_length) { uint8_t *notify_data = NULL; int notify_data_length = 0; int status = 0; // convert the string from the GET to something suitable for CoAP payloads if (this->getDataWrapper() != NULL) { // wrap the data... this->getDataWrapper()->wrap((uint8_t *)data,data_length); // announce (after wrap) //this->logger()->log("Notify payload [%s]...",this->getDataWrapper()->get()); // fill notify notify_data_length = this->getDataWrapper()->length(); notify_data = this->getDataWrapper()->get(); } else { // announce (no wrap) //this->logger()->log("Notify payload [%s]...",data); // do not wrap the data... notify_data_length = data_length; notify_data = data; } // update the resource this->m_res->set_value((uint8_t *)notify_data,(uint8_t)notify_data_length); // return our status return status; } // default PUT (does nothing) void DynamicResource::put(const string value) { // not used by default this->logger()->log("DynamicResource::put() invoked (NOOP)"); } // default POST (does nothing) void DynamicResource::post(void *args) { // not used by default this->logger()->log("DynamicResource::post() invoked (NOOP)"); } // default DELETE (does nothing) void DynamicResource::del(void *args) { // not used by default this->logger()->log("DynamicResource::del() invoked (NOOP)"); } // default observe behavior void DynamicResource::observe() { if (this->m_observable == true && this->isRegistered() == true) { this->notify(this->get()); } } // set the observer pointer void DynamicResource::setObserver(void *observer) { this->m_observer = observer; } // set the content-format in responses void DynamicResource::setContentFormat(uint8_t content_format) { this->m_content_format = content_format; } // set the max-age of responses void DynamicResource::setMaxAge(uint8_t maxage) { this->m_maxage = maxage; } // convenience method to get the URI from its buffer field... string DynamicResource::coapDataToString(uint8_t *coap_data_ptr,int coap_data_ptr_length) { if (coap_data_ptr != NULL && coap_data_ptr_length > 0) { if (this->getDataWrapper() != NULL) { // unwrap the data... this->getDataWrapper()->unwrap(coap_data_ptr,coap_data_ptr_length); char *buf = (char *)this->getDataWrapper()->get(); // assumes data is null terminated in DataWrapper... return string(buf); } else { // no unwrap of the data... char buf[MAX_VALUE_BUFFER_LENGTH+1]; memset(buf,0,MAX_VALUE_BUFFER_LENGTH+1); memcpy(buf,(char *)coap_data_ptr,coap_data_ptr_length); return string(buf); } } return string(""); } // Determine if we are connected or not bool DynamicResource::isConnected() { bool is_connected = false; // get our Endpoint Connector::Endpoint *ep = (Connector::Endpoint *)this->m_endpoint; if (ep != NULL) { is_connected = ep->isConnected(); if (is_connected) { //this->logger()->log("DynamicResource::isConnected = true"); } else { //this->logger()->log("DynamicResource::isConnected = false"); } } else { this->logger()->log("DynamicResource::isConnected = false (no endpoint)"); } // return our endpoint connection state return is_connected; } // Determine if we are registered or not bool DynamicResource::isRegistered() { bool is_registered = false; if (this->isConnected() == true) { // get our Endpoint Connector::Endpoint *ep = (Connector::Endpoint *)this->m_endpoint; if (ep != NULL) { is_registered = ep->isRegistered(); if (is_registered) { //this->logger()->log("DynamicResource::isRegistered = true"); } else { //this->logger()->log("DynamicResource::isRegistered = false"); } } else { this->logger()->log("DynamicResource::isRegistered = false (no endpoint)"); } } // return our endpoint registration state return is_registered; }