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.
Fork of mbedConnectorInterface by
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 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 }
Generated on Wed Jul 13 2022 02:58:57 by
1.7.2
