Michael Koster / mbedConnectorInterface_custom

Fork of mbedConnectorInterface by Doug Anson

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 "DynamicResource.h"
00024 
00025 // InstancePointerTable Helper
00026 #include "InstancePointerTableHelper.h"
00027 
00028 // ResourceObserver help
00029 #include "ResourceObserver.h"
00030 
00031 // Options enablement
00032 #include "Options.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 *name,const char *res_type,uint8_t res_mask,const bool observable) : Resource<string>(logger,string(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_obs_token_ptr = NULL;
00052     this->m_obs_token_len = 0;
00053     this->m_data_wrapper = NULL;
00054     this->m_observer = NULL;
00055     this->m_maxage = DEFAULT_MAXAGE;
00056     this->m_content_format = DEFAULT_CONTENT_FORMAT;
00057 }
00058 
00059 // constructor (input initial value)
00060 DynamicResource::DynamicResource(const Logger *logger,const char *name,const char *res_type,const string value,uint8_t res_mask,const bool observable) : Resource<string>(logger,string(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_obs_token_ptr = NULL;
00067     this->m_obs_token_len = 0;
00068     this->m_data_wrapper = NULL;
00069     this->m_observer = NULL;
00070     this->m_maxage = DEFAULT_MAXAGE;
00071     this->m_content_format = DEFAULT_CONTENT_FORMAT;
00072 }
00073 
00074 // constructor (strings)
00075 DynamicResource::DynamicResource(const Logger *logger,const string name,const string res_type,const string value,uint8_t res_mask,const bool observable) : Resource<string>(logger,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_obs_token_ptr = NULL;
00082     this->m_obs_token_len = 0;
00083     this->m_data_wrapper = NULL;
00084     this->m_observer = NULL;
00085     this->m_maxage = DEFAULT_MAXAGE;
00086     this->m_content_format = DEFAULT_CONTENT_FORMAT;
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_obs_token_ptr = resource.m_obs_token_ptr;
00097     this->m_obs_token_len = resource.m_obs_token_len;
00098     this->m_data_wrapper = resource.m_data_wrapper;
00099     this->m_observer = resource.m_observer;
00100     this->m_maxage = resource.m_maxage;
00101     this->m_content_format = resource.m_content_format;
00102 }
00103 
00104 // destructor
00105 DynamicResource::~DynamicResource()
00106 {
00107     if(this->m_obs_token_ptr) free(this->m_obs_token_ptr);
00108 }
00109 
00110 // bind resource to NSDL
00111 void DynamicResource::bind(void *p)
00112 {
00113     if (p != NULL) {
00114         sn_nsdl_resource_info_s *resource_ptr = (sn_nsdl_resource_info_s *)p;
00115         const uint8_t *name = (const uint8_t *)(this->getName().c_str());
00116         const uint8_t *res_type = (const uint8_t *)this->m_res_type.c_str();
00117         int name_length = this->getName().size();
00118         int res_type_length = this->m_res_type.size();
00119         int is_observable = 0;
00120         if (this->m_observable == true) is_observable = 1;
00121         const string *key = new string(this->getName());
00122         ipt_helper_add_instance_pointer(key,this);
00123         nsdl_create_dynamic_resource(resource_ptr,name_length,(uint8_t *)name,res_type_length,(uint8_t *)res_type,is_observable,&ipt_helper_nsdl_callback_stub,this->m_res_mask);
00124         this->logger()->log("DynamicResource: [%s] type: [%s] bound (observable: %d)",name,res_type,is_observable);
00125     } else {
00126         this->logger()->log("DynamicResource: NULL parameter in bind()");
00127     }
00128 }
00129 
00130 // process NSDL message
00131 uint8_t DynamicResource::process(sn_coap_hdr_s *received_coap_ptr, sn_nsdl_addr_s *address, sn_proto_info_s *proto)
00132 {
00133     sn_coap_hdr_s *coap_res_ptr = 0;
00134     
00135     // create our key for debugging output...
00136     DataWrapper *hold = this->getDataWrapper();
00137     this->setDataWrapper(NULL);
00138     string key = this->coapDataToString(received_coap_ptr->uri_path_ptr,received_coap_ptr->uri_path_len);
00139     this->setDataWrapper(hold);
00140 
00141     if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET) {
00142         coap_res_ptr = sn_coap_build_response(received_coap_ptr, COAP_MSG_CODE_RESPONSE_CONTENT);
00143 
00144         // process the GET if we have registered a callback for it...
00145         if ((this->m_res_mask&SN_GRS_GET_ALLOWED) != 0) {
00146             // call the resource get() to get the resource value
00147             this->logger()->log("Calling resource(GET) for [%s]...",key.c_str());
00148             string value = this->get();
00149 
00150             // convert the string from the GET to something suitable for CoAP payloads          
00151             if (this->getDataWrapper() != NULL) {
00152                 // wrap the data...
00153                 this->getDataWrapper()->wrap((uint8_t *)value.c_str(),(int)value.size());
00154                 
00155                 // announce (after wrap)
00156                 this->logger()->log("Building payload for [%s]=[%s]...",key.c_str(),this->getDataWrapper()->get());
00157                 
00158                 // fill in the CoAP response payload
00159                 coap_res_ptr->payload_len = this->getDataWrapper()->length();
00160                 coap_res_ptr->payload_ptr = this->getDataWrapper()->get();
00161             }
00162             else {
00163                 // announce (no wrap)
00164                 this->logger()->log("Building payload for [%s]=[%s]...",key.c_str(),value.c_str());
00165                 
00166                 // do not wrap the data...
00167                 coap_res_ptr->payload_len = value.size();
00168                 coap_res_ptr->payload_ptr = (uint8_t *)value.c_str();
00169             }
00170             
00171             // CoAP Content-Format
00172             coap_res_ptr->content_type_ptr = &this->m_content_format;                       
00173             coap_res_ptr->content_type_len = sizeof(this->m_content_format);
00174             
00175             // max-age cache control
00176             coap_res_ptr->options_list_ptr = (sn_coap_options_list_s*)nsdl_alloc(sizeof(sn_coap_options_list_s));
00177             if(!coap_res_ptr->options_list_ptr){
00178                 this->logger()->log("Cant alloc options list");
00179                 coap_res_ptr->options_list_ptr = NULL;
00180             }
00181             else{
00182                 memset(coap_res_ptr->options_list_ptr, 0, sizeof(sn_coap_options_list_s));
00183                 coap_res_ptr->options_list_ptr->max_age_ptr = &this->m_maxage;              
00184                 coap_res_ptr->options_list_ptr->max_age_len = sizeof(this->m_maxage);
00185             }
00186             
00187             // Observation handling... 
00188             if(received_coap_ptr->token_ptr) {
00189                 if(this->m_obs_token_ptr) {
00190                     free(this->m_obs_token_ptr);
00191                     this->m_obs_token_ptr = NULL;
00192                     this->m_obs_token_len = 0;
00193                 }
00194                 
00195                 this->m_obs_token_ptr = (uint8_t*)malloc(received_coap_ptr->token_len);
00196                 if(this->m_obs_token_ptr) {
00197                     memcpy(this->m_obs_token_ptr, received_coap_ptr->token_ptr,received_coap_ptr->token_len);
00198                     this->m_obs_token_len = received_coap_ptr->token_len;
00199                 }
00200             }
00201             
00202             // Observation handling...
00203             if(received_coap_ptr->options_list_ptr && received_coap_ptr->options_list_ptr->observe) {                
00204                 // create the options list pointer
00205                 coap_res_ptr->options_list_ptr = (sn_coap_options_list_s*)malloc(sizeof(sn_coap_options_list_s));
00206                 memset(coap_res_ptr->options_list_ptr, 0, sizeof(sn_coap_options_list_s));
00207 
00208                 // if GET controlled observation is enabled, perform it here...
00209                 if (((Connector::Options *)this->getOptions())->enableGETObservationControl()) {  
00210                     // ResourceObserver
00211                     ResourceObserver *observer = (ResourceObserver *)this->m_observer;
00212                     
00213                     // I think we have to check for a NULl reference first... then process possibly..
00214                     if (received_coap_ptr->options_list_ptr->observe_ptr != NULL) {
00215                         // get observe start/stop value from received options list pointer
00216                         uint8_t OBS_command = *received_coap_ptr->options_list_ptr->observe_ptr;
00217                         if (OBS_command == START_OBS) {
00218                             coap_res_ptr->options_list_ptr->observe_ptr = &this->m_obs_number;      // see nullify note below...
00219                             coap_res_ptr->options_list_ptr->observe_len = 1;
00220                             this->m_obs_number++;
00221                             if (observer != NULL) observer->beginObservation();
00222                         }
00223                         if (OBS_command == STOP_OBS) {
00224                             if (observer != NULL) observer->stopObservation();
00225                         }
00226                     }
00227                     else {
00228                         // non-GET controlled observationing: simply fill in the observation requirements...
00229                         coap_res_ptr->options_list_ptr->observe_ptr = &this->m_obs_number;          // see nullify note below...
00230                         coap_res_ptr->options_list_ptr->observe_len = 1;
00231                         this->m_obs_number++;
00232                     }
00233                 }
00234                 else {
00235                     // non-GET controlled observationing: simply fill in the observation requirements...
00236                     coap_res_ptr->options_list_ptr->observe_ptr = &this->m_obs_number;          // see nullify note below...
00237                     coap_res_ptr->options_list_ptr->observe_len = 1;
00238                     this->m_obs_number++;
00239                 }
00240             }
00241 
00242             // build out the response and send...
00243             sn_nsdl_send_coap_message(address,coap_res_ptr);
00244             
00245             // freeing up the options_list_ptr and clearing the content_type pointer
00246             nsdl_free(coap_res_ptr->options_list_ptr);
00247             coap_res_ptr->options_list_ptr = NULL;
00248             coap_res_ptr->content_type_ptr = NULL;
00249             
00250             //
00251             // nullify note: 
00252             //
00253             // because our obs_number (assigned to observe_ptr) is part of this object instance, we dont 
00254             // want to have the underlying free() try to free it... to just nullify here
00255             //
00256             if (coap_res_ptr->options_list_ptr) coap_res_ptr->options_list_ptr->observe_ptr = 0;        
00257         } 
00258         else {
00259             this->logger()->log("ERROR: resource(GET) mask is munged (mask: 0x%x)",this->m_res_mask);
00260         }
00261     } else if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT) {
00262         if(received_coap_ptr->payload_len > 0) {
00263             // process the PUT if we have registered a callback for it...
00264             if ((this->m_res_mask&SN_GRS_PUT_ALLOWED) != 0) {
00265                 // put() delivers values as std::string
00266                 string value = this->coapDataToString(received_coap_ptr->payload_ptr,received_coap_ptr->payload_len);
00267 
00268                 // call the resource put() to set the resource value
00269                 this->logger()->log("Calling resource(PUT) with [%s]=[%s]...",key.c_str(),value.c_str());
00270                 this->put(value);
00271 
00272                 // build out the response and send...
00273                 this->logger()->log("resource(PUT) completed for [%s]...",key.c_str());
00274                 coap_res_ptr = sn_coap_build_response(received_coap_ptr,COAP_MSG_CODE_RESPONSE_CHANGED);
00275                 sn_nsdl_send_coap_message(address,coap_res_ptr);
00276             } else {
00277                 this->logger()->log("ERROR: resource(PUT) mask is munged (mask: 0x%x)",this->m_res_mask);
00278             }
00279         } else {
00280             this->logger()->log("ERROR: Binder(PUT) payload is NULL...");
00281         }
00282     } else if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_POST) {
00283         if(received_coap_ptr->payload_len > 0) {
00284             // process the POST if we have registered a callback for it...
00285             if ((this->m_res_mask&SN_GRS_POST_ALLOWED) != 0) {
00286                 // post() delivers values as std::string
00287                 string value = this->coapDataToString(received_coap_ptr->payload_ptr,received_coap_ptr->payload_len);
00288 
00289                 // call the resource post() to set the resource value
00290                 this->logger()->log("Calling resource(POST) with [%s]=[%s]...",key.c_str(),value.c_str());
00291                 this->post(value);
00292 
00293                 // build out the response and send...
00294                 this->logger()->log("resource(POST) completed for [%s]...",key.c_str());
00295                 coap_res_ptr = sn_coap_build_response(received_coap_ptr,COAP_MSG_CODE_RESPONSE_CHANGED);
00296                 sn_nsdl_send_coap_message(address,coap_res_ptr);
00297             } else {
00298                 this->logger()->log("ERROR: resource(POST) mask is munged (mask: 0x%x)",this->m_res_mask);
00299             }
00300         } else {
00301             this->logger()->log("ERROR: Binder(POST) payload is NULL...");
00302         }
00303     } else if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_DELETE) {
00304         if(received_coap_ptr->payload_len > 0) {
00305             // process the DELETE if we have registered a callback for it...
00306             if ((this->m_res_mask&SN_GRS_DELETE_ALLOWED) != 0) {
00307                 // del() delivers values as std::string
00308                 string value = this->coapDataToString(received_coap_ptr->payload_ptr,received_coap_ptr->payload_len);
00309 
00310                 // call the resource del() to set the resource value
00311                 this->logger()->log("Calling resource(DELETE) with [%s]=[%s]...",key.c_str(),value.c_str());
00312                 this->del(value);
00313 
00314                 // build out the response and send...
00315                 this->logger()->log("resource(DELETE) completed for [%s]...",key.c_str());
00316                 coap_res_ptr = sn_coap_build_response(received_coap_ptr,COAP_MSG_CODE_RESPONSE_CHANGED);
00317                 sn_nsdl_send_coap_message(address,coap_res_ptr);
00318             } else {
00319                 this->logger()->log("ERROR: resource(DELETE) mask is munged (mask: 0x%x)",this->m_res_mask);
00320             }
00321         } else {
00322             this->logger()->log("ERROR: Binder(DELETE) payload is NULL...");
00323         }
00324     }
00325 
00326     sn_coap_parser_release_allocated_coap_msg_mem(coap_res_ptr);
00327     
00328     return 0;
00329 }
00330 
00331 // send the notification
00332 int DynamicResource::notify(const string data) {
00333     return this->notify((uint8_t *)data.c_str(),(int)data.length());
00334 }
00335 
00336 // send the notification
00337 int DynamicResource::notify(uint8_t *data,int data_length) {
00338     uint8_t *notify_data = NULL;
00339     int notify_data_length = 0;
00340     
00341     // convert the string from the GET to something suitable for CoAP payloads          
00342     if (this->getDataWrapper() != NULL) {
00343         // wrap the data...
00344         this->getDataWrapper()->wrap((uint8_t *)data,data_length);
00345         
00346         // announce (after wrap)
00347         //this->logger()->log("Notify payload [%s]...",this->getDataWrapper()->get());
00348         
00349         // fill notify 
00350         notify_data_length = this->getDataWrapper()->length();
00351         notify_data = this->getDataWrapper()->get();
00352     }
00353     else {
00354         // announce (no wrap)
00355         //this->logger()->log("Notify payload [%s]...",data);
00356         
00357         // do not wrap the data...
00358         notify_data_length = data_length;
00359         notify_data = data;
00360     }
00361     
00362     // send the observation...
00363     int status = sn_nsdl_send_observation_notification(this->m_obs_token_ptr,this->m_obs_token_len,notify_data,notify_data_length,&this->m_obs_number,1,COAP_MSG_TYPE_NON_CONFIRMABLE,0);
00364     if (status == 0) {
00365         this->logger()->log("ERROR: resource(NOTIFY) send failed...");
00366     }
00367     else {
00368         ++(this->m_obs_number);
00369     }
00370     
00371     // return our status
00372     return status;
00373 }
00374 
00375 // default PUT (does nothing)
00376 void DynamicResource::put(const string value)
00377 {
00378     // not used by default
00379     ;
00380 }
00381 
00382 // default POST (does nothing)
00383 void DynamicResource::post(const string value)
00384 {
00385     // not used by default
00386     ;
00387 }
00388 
00389 // default DELETE (does nothing)
00390 void DynamicResource::del(const string value)
00391 {
00392     // not used by default
00393     ;
00394 }
00395 
00396 // default observe behavior
00397 void DynamicResource::observe() {
00398     if (this->m_observable == true) {
00399         this->notify(this->get());
00400     }
00401 }
00402 
00403 // set the observer pointer
00404 void DynamicResource::setObserver(void *observer) {
00405     this->m_observer = observer;
00406 }
00407 
00408 // set the content-format in responses
00409 void DynamicResource::setContentFormat(uint8_t content_format) {
00410     this->m_content_format = content_format;
00411 }
00412 
00413 // set the max-age of responses
00414 void DynamicResource::setMaxAge(uint8_t maxage) {
00415     this->m_maxage = maxage;
00416 }
00417 
00418 // convenience method to get the URI from its buffer field...
00419 string DynamicResource::coapDataToString(uint8_t *coap_data_ptr,int coap_data_ptr_length)
00420 {
00421     if (coap_data_ptr != NULL && coap_data_ptr_length > 0) {
00422         if (this->getDataWrapper() != NULL) {
00423             // unwrap the data...
00424             this->getDataWrapper()->unwrap(coap_data_ptr,coap_data_ptr_length);
00425             char *buf = (char *)this->getDataWrapper()->get();                  // assumes data is null terminated in DataWrapper...
00426             return string(buf);
00427         }
00428         else {
00429             // no unwrap of the data...
00430             char buf[MAX_VALUE_BUFFER_LENGTH+1];
00431             memset(buf,0,MAX_VALUE_BUFFER_LENGTH+1);
00432             memcpy(buf,(char *)coap_data_ptr,coap_data_ptr_length);
00433             return string(buf);
00434         }
00435     }
00436     return string("");
00437 }