observe updates
Fork of mbedConnectorInterface by
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Wed Jul 13 2022 02:11:49 by 1.7.2