Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: IoT_LED_demo ServoTest uWater_Project hackathon ... more
DynamicResource.cpp
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 int status = 0; 00341 00342 // convert the string from the GET to something suitable for CoAP payloads 00343 if (this->getDataWrapper() != NULL) { 00344 // wrap the data... 00345 this->getDataWrapper()->wrap((uint8_t *)data,data_length); 00346 00347 // announce (after wrap) 00348 //this->logger()->log("Notify payload [%s]...",this->getDataWrapper()->get()); 00349 00350 // fill notify 00351 notify_data_length = this->getDataWrapper()->length(); 00352 notify_data = this->getDataWrapper()->get(); 00353 } 00354 else { 00355 // announce (no wrap) 00356 //this->logger()->log("Notify payload [%s]...",data); 00357 00358 // do not wrap the data... 00359 notify_data_length = data_length; 00360 notify_data = data; 00361 } 00362 00363 // check if we have something to send... if we do, then send it... 00364 if (notify_data != NULL && notify_data_length > 0) { 00365 // send the observation... 00366 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); 00367 if (status == 0) { 00368 this->logger()->log("ERROR: resource(NOTIFY) send failed..."); 00369 } 00370 else { 00371 ++(this->m_obs_number); 00372 } 00373 } 00374 else { 00375 // nothing to send... so ignore silently 00376 //this->logger()->log("resource(NOTIFY): nothing to notify (OK)..."); 00377 status = 1; 00378 } 00379 00380 // return our status 00381 return status; 00382 } 00383 00384 // default PUT (does nothing) 00385 void DynamicResource::put(const string value) 00386 { 00387 // not used by default 00388 ; 00389 } 00390 00391 // default POST (does nothing) 00392 void DynamicResource::post(const string value) 00393 { 00394 // not used by default 00395 ; 00396 } 00397 00398 // default DELETE (does nothing) 00399 void DynamicResource::del(const string value) 00400 { 00401 // not used by default 00402 ; 00403 } 00404 00405 // default observe behavior 00406 void DynamicResource::observe() { 00407 this->observe(true); 00408 } 00409 00410 // behavior controlled observe behavior 00411 void DynamicResource::observe(bool do_notify) { 00412 if (this->m_observable == true) { 00413 if (do_notify) { 00414 // get() and notify() --> time-based observationing 00415 this->notify(this->get()); 00416 } 00417 else { 00418 // get() only (resource controls whether each iteration results in an observation or not...) 00419 this->get(); 00420 } 00421 } 00422 } 00423 00424 // set the observer pointer 00425 void DynamicResource::setObserver(void *observer) { 00426 this->m_observer = observer; 00427 } 00428 00429 // set the content-format in responses 00430 void DynamicResource::setContentFormat(uint8_t content_format) { 00431 this->m_content_format = content_format; 00432 } 00433 00434 // set the max-age of responses 00435 void DynamicResource::setMaxAge(uint8_t maxage) { 00436 this->m_maxage = maxage; 00437 } 00438 00439 // convenience method to get the URI from its buffer field... 00440 string DynamicResource::coapDataToString(uint8_t *coap_data_ptr,int coap_data_ptr_length) 00441 { 00442 if (coap_data_ptr != NULL && coap_data_ptr_length > 0) { 00443 if (this->getDataWrapper() != NULL) { 00444 // unwrap the data... 00445 this->getDataWrapper()->unwrap(coap_data_ptr,coap_data_ptr_length); 00446 char *buf = (char *)this->getDataWrapper()->get(); // assumes data is null terminated in DataWrapper... 00447 return string(buf); 00448 } 00449 else { 00450 // no unwrap of the data... 00451 char buf[MAX_VALUE_BUFFER_LENGTH+1]; 00452 memset(buf,0,MAX_VALUE_BUFFER_LENGTH+1); 00453 memcpy(buf,(char *)coap_data_ptr,coap_data_ptr_length); 00454 return string(buf); 00455 } 00456 } 00457 return string(""); 00458 }
Generated on Tue Jul 12 2022 15:15:35 by
1.7.2