observe updates

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 // Leaving this disabled until the CoAP draft spec is further along...
00032 #define GET_ENABLE_DISABLE_OBS
00033 #ifdef GET_ENABLE_DISABLE_OBS 
00034     // GET verb can Start/Stop Observations...
00035     #define START_OBS 0
00036     #define STOP_OBS  1
00037 #endif
00038 
00039 // default constructor
00040 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(""))
00041 {
00042     this->m_res_type = string(res_type);
00043     this->m_observable = observable;
00044     this->m_res_mask = res_mask;
00045     this->m_obs_number = 0;
00046     this->m_obs_token_ptr = NULL;
00047     this->m_obs_token_len = 0;
00048     this->m_data_wrapper = NULL;
00049     this->m_observer = NULL;
00050 }
00051 
00052 // constructor (input initial value)
00053 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)
00054 {
00055     this->m_res_type = string(res_type);
00056     this->m_observable = observable;
00057     this->m_res_mask = res_mask;
00058     this->m_obs_number = 0;
00059     this->m_obs_token_ptr = NULL;
00060     this->m_obs_token_len = 0;
00061     this->m_data_wrapper = NULL;
00062     this->m_observer = NULL;
00063 }
00064 
00065 // constructor (strings)
00066 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)
00067 {
00068     this->m_res_type = res_type;
00069     this->m_observable = observable;
00070     this->m_res_mask = res_mask;
00071     this->m_obs_number = 0;
00072     this->m_obs_token_ptr = NULL;
00073     this->m_obs_token_len = 0;
00074     this->m_data_wrapper = NULL;
00075     this->m_observer = NULL;
00076 }
00077 
00078 // copy constructor
00079 DynamicResource::DynamicResource(const DynamicResource &resource) : Resource<string>((const Resource<string> &)resource)
00080 {
00081     this->m_res_type = resource.m_res_type;
00082     this->m_observable = resource.m_observable;
00083     this->m_res_mask = resource.m_res_mask;
00084     this->m_obs_number = resource.m_obs_number;
00085     this->m_obs_token_ptr = resource.m_obs_token_ptr;
00086     this->m_obs_token_len = resource.m_obs_token_len;
00087     this->m_data_wrapper = resource.m_data_wrapper;
00088     this->m_observer = resource.m_observer;
00089 }
00090 
00091 // destructor
00092 DynamicResource::~DynamicResource()
00093 {
00094     if(this->m_obs_token_ptr) free(this->m_obs_token_ptr);
00095 }
00096 
00097 // bind resource to NSDL
00098 void DynamicResource::bind(void *p)
00099 {
00100     if (p != NULL) {
00101         sn_nsdl_resource_info_s *resource_ptr = (sn_nsdl_resource_info_s *)p;
00102         const uint8_t *name = (const uint8_t *)(this->getName().c_str());
00103         const uint8_t *res_type = (const uint8_t *)this->m_res_type.c_str();
00104         int name_length = this->getName().size();
00105         int res_type_length = this->m_res_type.size();
00106         int is_observable = 0;
00107         if (this->m_observable == true) is_observable = 1;
00108         const string *key = new string(this->getName());
00109         ipt_helper_add_instance_pointer(key,this);
00110         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);
00111         this->logger()->log("DynamicResource: [%s] type: [%s] bound (observable: %d)",name,res_type,is_observable);
00112     } else {
00113         this->logger()->log("DynamicResource: NULL parameter in bind()");
00114     }
00115 }
00116 
00117 // process NSDL message
00118 uint8_t DynamicResource::process(sn_coap_hdr_s *received_coap_ptr, sn_nsdl_addr_s *address, sn_proto_info_s *proto)
00119 {
00120     sn_coap_hdr_s *coap_res_ptr = 0;
00121     
00122     // create our key for debugging output...
00123     DataWrapper *hold = this->getDataWrapper();
00124     this->setDataWrapper(NULL);
00125     string key = this->coapDataToString(received_coap_ptr->uri_path_ptr,received_coap_ptr->uri_path_len);
00126     this->setDataWrapper(hold);
00127 
00128     if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET) {
00129         coap_res_ptr = sn_coap_build_response(received_coap_ptr, COAP_MSG_CODE_RESPONSE_CONTENT);
00130 
00131         // process the GET if we have registered a callback for it...
00132         if ((this->m_res_mask&SN_GRS_GET_ALLOWED) != 0) {
00133             // call the resource get() to get the resource value
00134             this->logger()->log("Calling resource(GET) for [%s]...",key.c_str());
00135             string value = this->get();
00136 
00137             // convert the string from the GET to something suitable for CoAP payloads          
00138             if (this->getDataWrapper() != NULL) {
00139                 // wrap the data...
00140                 this->getDataWrapper()->wrap((uint8_t *)value.c_str(),(int)value.size());
00141                 
00142                 // announce (after wrap)
00143                 this->logger()->log("Building payload for [%s]=[%s]...",key.c_str(),this->getDataWrapper()->get());
00144                 
00145                 // fill in the CoAP response payload
00146                 coap_res_ptr->payload_len = this->getDataWrapper()->length();
00147                 coap_res_ptr->payload_ptr = this->getDataWrapper()->get();
00148             }
00149             else {
00150                 // announce (no wrap)
00151                 this->logger()->log("Building payload for [%s]=[%s]...",key.c_str(),value.c_str());
00152                 
00153                 // do not wrap the data...
00154                 coap_res_ptr->payload_len = value.size();
00155                 coap_res_ptr->payload_ptr = (uint8_t *)value.c_str();
00156             }
00157             
00158             // Observation handling... 
00159             if(received_coap_ptr->token_ptr) {
00160                 if(this->m_obs_token_ptr) {
00161                     free(this->m_obs_token_ptr);
00162                     this->m_obs_token_ptr = NULL;
00163                     this->m_obs_token_len = 0;
00164                 }
00165                 
00166                 this->m_obs_token_ptr = (uint8_t*)malloc(received_coap_ptr->token_len);
00167                 if(this->m_obs_token_ptr) {
00168                     memcpy(this->m_obs_token_ptr, received_coap_ptr->token_ptr,received_coap_ptr->token_len);
00169                     this->m_obs_token_len = received_coap_ptr->token_len;
00170                 }
00171             }
00172             
00173             // Observation handling...
00174             if(received_coap_ptr->options_list_ptr && received_coap_ptr->options_list_ptr->observe) {                
00175                 // create the options list pointer
00176                 coap_res_ptr->options_list_ptr = (sn_coap_options_list_s*)malloc(sizeof(sn_coap_options_list_s));
00177                 memset(coap_res_ptr->options_list_ptr, 0, sizeof(sn_coap_options_list_s));
00178 
00179                 // Leaving this disabled until the CoAP draft spec is further along...
00180 #ifdef GET_ENABLE_DISABLE_OBS   
00181                 // ResourceObserver
00182                 ResourceObserver *observer = (ResourceObserver *)this->m_observer;
00183            
00184                 // get observe start/stop value from received options list pointer
00185                 uint8_t OBS_command = *received_coap_ptr->options_list_ptr->observe_ptr;
00186                 if (OBS_command == START_OBS) {
00187                     coap_res_ptr->options_list_ptr->observe_ptr = &this->m_obs_number;      // see nullify note below...
00188                     coap_res_ptr->options_list_ptr->observe_len = 1;
00189                     this->m_obs_number++;
00190                     if (observer != NULL) observer->beginObservation();
00191                 }
00192                 if (OBS_command == STOP_OBS) {
00193                     if (observer != NULL) observer->stopObservation();
00194                 }
00195 #else
00196                 // simply fill in the observation requirements...
00197                 coap_res_ptr->options_list_ptr->observe_ptr = &this->m_obs_number;          // see nullify note below...
00198                 coap_res_ptr->options_list_ptr->observe_len = 1;
00199                 this->m_obs_number++;
00200 #endif
00201             }
00202 
00203             // build out the response and send...
00204             sn_nsdl_send_coap_message(address,coap_res_ptr);
00205             
00206             //
00207             // nullify note: 
00208             //
00209             // because our obs_number (assigned to observe_ptr) is part of this object instance, we dont 
00210             // want to have the underlying free() try to free it... to just nullify here
00211             //
00212             if (coap_res_ptr->options_list_ptr) coap_res_ptr->options_list_ptr->observe_ptr = 0;
00213         } 
00214         else {
00215             this->logger()->log("ERROR: resource(GET) mask is munged (mask: 0x%x)",this->m_res_mask);
00216         }
00217     } else if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT) {
00218         if(received_coap_ptr->payload_len > 0) {
00219             // process the PUT if we have registered a callback for it...
00220             if ((this->m_res_mask&SN_GRS_PUT_ALLOWED) != 0) {
00221                 // put() delivers values as std::string
00222                 string value = this->coapDataToString(received_coap_ptr->payload_ptr,received_coap_ptr->payload_len);
00223 
00224                 // call the resource put() to set the resource value
00225                 this->logger()->log("Calling resource(PUT) with [%s]=[%s]...",key.c_str(),value.c_str());
00226                 this->put(value);
00227 
00228                 // build out the response and send...
00229                 this->logger()->log("resource(PUT) completed for [%s]...",key.c_str());
00230                 coap_res_ptr = sn_coap_build_response(received_coap_ptr,COAP_MSG_CODE_RESPONSE_CHANGED);
00231                 sn_nsdl_send_coap_message(address,coap_res_ptr);
00232             } else {
00233                 this->logger()->log("ERROR: resource(PUT) mask is munged (mask: 0x%x)",this->m_res_mask);
00234             }
00235         } else {
00236             this->logger()->log("ERROR: Binder(PUT) payload is NULL...");
00237         }
00238     } else if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_POST) {
00239         if(received_coap_ptr->payload_len > 0) {
00240             // process the POST if we have registered a callback for it...
00241             if ((this->m_res_mask&SN_GRS_POST_ALLOWED) != 0) {
00242                 // post() delivers values as std::string
00243                 string value = this->coapDataToString(received_coap_ptr->payload_ptr,received_coap_ptr->payload_len);
00244 
00245                 // call the resource post() to set the resource value
00246                 this->logger()->log("Calling resource(POST) with [%s]=[%s]...",key.c_str(),value.c_str());
00247                 this->post(value);
00248 
00249                 // build out the response and send...
00250                 this->logger()->log("resource(POST) completed for [%s]...",key.c_str());
00251                 coap_res_ptr = sn_coap_build_response(received_coap_ptr,COAP_MSG_CODE_RESPONSE_CHANGED);
00252                 sn_nsdl_send_coap_message(address,coap_res_ptr);
00253             } else {
00254                 this->logger()->log("ERROR: resource(POST) mask is munged (mask: 0x%x)",this->m_res_mask);
00255             }
00256         } else {
00257             this->logger()->log("ERROR: Binder(POST) payload is NULL...");
00258         }
00259     } else if(received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_DELETE) {
00260         if(received_coap_ptr->payload_len > 0) {
00261             // process the DELETE if we have registered a callback for it...
00262             if ((this->m_res_mask&SN_GRS_DELETE_ALLOWED) != 0) {
00263                 // del() delivers values as std::string
00264                 string value = this->coapDataToString(received_coap_ptr->payload_ptr,received_coap_ptr->payload_len);
00265 
00266                 // call the resource del() to set the resource value
00267                 this->logger()->log("Calling resource(DELETE) with [%s]=[%s]...",key.c_str(),value.c_str());
00268                 this->del(value);
00269 
00270                 // build out the response and send...
00271                 this->logger()->log("resource(DELETE) completed for [%s]...",key.c_str());
00272                 coap_res_ptr = sn_coap_build_response(received_coap_ptr,COAP_MSG_CODE_RESPONSE_CHANGED);
00273                 sn_nsdl_send_coap_message(address,coap_res_ptr);
00274             } else {
00275                 this->logger()->log("ERROR: resource(DELETE) mask is munged (mask: 0x%x)",this->m_res_mask);
00276             }
00277         } else {
00278             this->logger()->log("ERROR: Binder(DELETE) payload is NULL...");
00279         }
00280     }
00281 
00282     sn_coap_parser_release_allocated_coap_msg_mem(coap_res_ptr);
00283     
00284     return 0;
00285 }
00286 
00287 // send the notification
00288 int DynamicResource::notify(const string data) {
00289     return this->notify((uint8_t *)data.c_str(),(int)data.length());
00290 }
00291 
00292 // send the notification
00293 int DynamicResource::notify(uint8_t *data,int data_length) {
00294     uint8_t *notify_data = NULL;
00295     int notify_data_length = 0;
00296     
00297     // convert the string from the GET to something suitable for CoAP payloads          
00298     if (this->getDataWrapper() != NULL) {
00299         // wrap the data...
00300         this->getDataWrapper()->wrap((uint8_t *)data,data_length);
00301         
00302         // announce (after wrap)
00303         //this->logger()->log("Notify payload [%s]...",this->getDataWrapper()->get());
00304         
00305         // fill notify 
00306         notify_data_length = this->getDataWrapper()->length();
00307         notify_data = this->getDataWrapper()->get();
00308     }
00309     else {
00310         // announce (no wrap)
00311         //this->logger()->log("Notify payload [%s]...",data);
00312         
00313         // do not wrap the data...
00314         notify_data_length = data_length;
00315         notify_data = data;
00316     }
00317     
00318     // send the observation...
00319     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);
00320     if (status == 0) {
00321         this->logger()->log("ERROR: resource(NOTIFY) send failed...");
00322     }
00323     else{
00324         this->m_obs_number++;
00325     }
00326     
00327     // return our status
00328     return status;
00329 }
00330 
00331 // default PUT (does nothing)
00332 void DynamicResource::put(const string value)
00333 {
00334     // not used by default
00335     ;
00336 }
00337 
00338 // default POST (does nothing)
00339 void DynamicResource::post(const string value)
00340 {
00341     // not used by default
00342     ;
00343 }
00344 
00345 // default DELETE (does nothing)
00346 void DynamicResource::del(const string value)
00347 {
00348     // not used by default
00349     ;
00350 }
00351 
00352 // default observe behavior
00353 void DynamicResource::observe() {
00354     if (this->m_observable == true) {
00355         this->notify(this->get());
00356     }
00357 }
00358 
00359 // set the observer pointer
00360 void DynamicResource::setObserver(void *observer) {
00361     this->m_observer = observer;
00362 }
00363 
00364 // convenience method to get the URI from its buffer field...
00365 string DynamicResource::coapDataToString(uint8_t *coap_data_ptr,int coap_data_ptr_length)
00366 {
00367     if (coap_data_ptr != NULL && coap_data_ptr_length > 0) {
00368         if (this->getDataWrapper() != NULL) {
00369             // unwrap the data...
00370             this->getDataWrapper()->unwrap(coap_data_ptr,coap_data_ptr_length);
00371             char *buf = (char *)this->getDataWrapper()->get();                  // assumes data is null terminated in DataWrapper...
00372             return string(buf);
00373         }
00374         else {
00375             // no unwrap of the data...
00376             char buf[MAX_VALUE_BUFFER_LENGTH+1];
00377             memset(buf,0,MAX_VALUE_BUFFER_LENGTH+1);
00378             memcpy(buf,(char *)coap_data_ptr,coap_data_ptr_length);
00379             return string(buf);
00380         }
00381     }
00382     return string("");
00383 }