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.
observe.c
00001 /******************************************************************************* 00002 * 00003 * Copyright (c) 2013, 2014 Intel Corporation and others. 00004 * All rights reserved. This program and the accompanying materials 00005 * are made available under the terms of the Eclipse Public License v1.0 00006 * and Eclipse Distribution License v1.0 which accompany this distribution. 00007 * 00008 * The Eclipse Public License is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * The Eclipse Distribution License is available at 00011 * http://www.eclipse.org/org/documents/edl-v10.php. 00012 * 00013 * Contributors: 00014 * David Navarro, Intel Corporation - initial API and implementation 00015 * Toby Jaffey - Please refer to git log 00016 * Bosch Software Innovations GmbH - Please refer to git log 00017 * 00018 *******************************************************************************/ 00019 00020 /* 00021 Copyright (c) 2013, 2014 Intel Corporation 00022 00023 Redistribution and use in source and binary forms, with or without modification, 00024 are permitted provided that the following conditions are met: 00025 00026 * Redistributions of source code must retain the above copyright notice, 00027 this list of conditions and the following disclaimer. 00028 * Redistributions in binary form must reproduce the above copyright notice, 00029 this list of conditions and the following disclaimer in the documentation 00030 and/or other materials provided with the distribution. 00031 * Neither the name of Intel Corporation nor the names of its contributors 00032 may be used to endorse or promote products derived from this software 00033 without specific prior written permission. 00034 00035 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00036 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00037 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00038 IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 00039 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00040 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00041 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00042 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00043 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 00044 THE POSSIBILITY OF SUCH DAMAGE. 00045 00046 David Navarro <david.navarro@intel.com> 00047 00048 */ 00049 00050 #include "internals.h" 00051 #include <stdio.h> 00052 00053 00054 #ifdef LWM2M_CLIENT_MODE 00055 static lwm2m_observed_t * prv_findObserved(lwm2m_context_t * contextP, 00056 lwm2m_uri_t * uriP) 00057 { 00058 lwm2m_observed_t * targetP; 00059 00060 targetP = contextP->observedList; 00061 while (targetP != NULL 00062 && (targetP->uri.objectId != uriP->objectId 00063 || targetP->uri.flag != uriP->flag 00064 || (LWM2M_URI_IS_SET_INSTANCE(uriP) && targetP->uri.instanceId != uriP->instanceId) 00065 || (LWM2M_URI_IS_SET_RESOURCE(uriP) && targetP->uri.resourceId != uriP->resourceId))) 00066 { 00067 targetP = targetP->next; 00068 } 00069 00070 return targetP; 00071 } 00072 00073 static void prv_unlinkObserved(lwm2m_context_t * contextP, 00074 lwm2m_observed_t * observedP) 00075 { 00076 if (contextP->observedList == observedP) 00077 { 00078 contextP->observedList = contextP->observedList->next; 00079 } 00080 else 00081 { 00082 lwm2m_observed_t * parentP; 00083 00084 parentP = contextP->observedList; 00085 while (parentP->next != NULL 00086 && parentP->next != observedP) 00087 { 00088 parentP = parentP->next; 00089 } 00090 if (parentP->next != NULL) 00091 { 00092 parentP->next = parentP->next->next; 00093 } 00094 } 00095 } 00096 00097 static lwm2m_watcher_t * prv_findWatcher(lwm2m_observed_t * observedP, 00098 lwm2m_server_t * serverP) 00099 { 00100 lwm2m_watcher_t * targetP; 00101 00102 targetP = observedP->watcherList; 00103 while (targetP != NULL 00104 && targetP->server != serverP) 00105 { 00106 targetP = targetP->next; 00107 } 00108 00109 return targetP; 00110 } 00111 00112 static lwm2m_watcher_t * prv_getWatcher(lwm2m_context_t * contextP, 00113 lwm2m_uri_t * uriP, 00114 lwm2m_server_t * serverP) 00115 { 00116 lwm2m_observed_t * observedP; 00117 bool allocatedObserver; 00118 lwm2m_watcher_t * watcherP; 00119 00120 allocatedObserver = false; 00121 00122 observedP = prv_findObserved(contextP, uriP); 00123 if (observedP == NULL) 00124 { 00125 observedP = (lwm2m_observed_t *)lwm2m_malloc(sizeof(lwm2m_observed_t)); 00126 if (observedP == NULL) return NULL; 00127 allocatedObserver = true; 00128 memset(observedP, 0, sizeof(lwm2m_observed_t)); 00129 memcpy(&(observedP->uri), uriP, sizeof(lwm2m_uri_t)); 00130 observedP->next = contextP->observedList; 00131 contextP->observedList = observedP; 00132 } 00133 00134 watcherP = prv_findWatcher(observedP, serverP); 00135 if (watcherP == NULL) 00136 { 00137 watcherP = (lwm2m_watcher_t *)lwm2m_malloc(sizeof(lwm2m_watcher_t)); 00138 if (watcherP == NULL) 00139 { 00140 if (allocatedObserver == true) 00141 { 00142 lwm2m_free(observedP); 00143 } 00144 return NULL; 00145 } 00146 memset(watcherP, 0, sizeof(lwm2m_watcher_t)); 00147 watcherP->active = false; 00148 watcherP->server = serverP; 00149 watcherP->next = observedP->watcherList; 00150 observedP->watcherList = watcherP; 00151 } 00152 00153 return watcherP; 00154 } 00155 00156 coap_status_t observe_handleRequest(lwm2m_context_t * contextP, 00157 lwm2m_uri_t * uriP, 00158 lwm2m_server_t * serverP, 00159 int size, 00160 lwm2m_data_t * dataP, 00161 coap_packet_t * message, 00162 coap_packet_t * response) 00163 { 00164 lwm2m_watcher_t * watcherP; 00165 uint32_t count; 00166 00167 LOG_ARG("Code: %02X, server status: %s", message->code, STR_STATUS(serverP->status)); 00168 LOG_URI(uriP); 00169 00170 coap_get_header_observe(message, &count); 00171 00172 switch (count) 00173 { 00174 case 0: 00175 if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; 00176 if (message->token_len == 0) return COAP_400_BAD_REQUEST; 00177 00178 watcherP = prv_getWatcher(contextP, uriP, serverP); 00179 if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; 00180 00181 watcherP->tokenLen = message->token_len; 00182 memcpy(watcherP->token, message->token, message->token_len); 00183 watcherP->active = true; 00184 watcherP->lastTime = lwm2m_gettime(); 00185 00186 if (LWM2M_URI_IS_SET_RESOURCE(uriP)) 00187 { 00188 switch (dataP->type) 00189 { 00190 case LWM2M_TYPE_INTEGER: 00191 if (1 != lwm2m_data_decode_int(dataP, &(watcherP->lastValue.asInteger))) return COAP_500_INTERNAL_SERVER_ERROR; 00192 break; 00193 case LWM2M_TYPE_FLOAT: 00194 if (1 != lwm2m_data_decode_float(dataP, &(watcherP->lastValue.asFloat))) return COAP_500_INTERNAL_SERVER_ERROR; 00195 break; 00196 default: 00197 break; 00198 } 00199 } 00200 00201 coap_set_header_observe(response, watcherP->counter++); 00202 00203 return COAP_205_CONTENT; 00204 00205 case 1: 00206 // cancellation 00207 observe_cancel(contextP, LWM2M_MAX_ID, serverP->sessionH); 00208 return COAP_205_CONTENT; 00209 00210 default: 00211 return COAP_400_BAD_REQUEST; 00212 } 00213 } 00214 00215 void observe_cancel(lwm2m_context_t * contextP, 00216 uint16_t mid, 00217 void * fromSessionH) 00218 { 00219 lwm2m_observed_t * observedP; 00220 00221 LOG_ARG("mid: %d", mid); 00222 00223 for (observedP = contextP->observedList; 00224 observedP != NULL; 00225 observedP = observedP->next) 00226 { 00227 lwm2m_watcher_t * targetP = NULL; 00228 00229 if ((LWM2M_MAX_ID == mid || observedP->watcherList->lastMid == mid) 00230 && lwm2m_session_is_equal(observedP->watcherList->server->sessionH, fromSessionH, contextP->userData)) 00231 { 00232 targetP = observedP->watcherList; 00233 observedP->watcherList = observedP->watcherList->next; 00234 } 00235 else 00236 { 00237 lwm2m_watcher_t * parentP; 00238 00239 parentP = observedP->watcherList; 00240 while (parentP->next != NULL 00241 && (parentP->next->lastMid != mid 00242 || lwm2m_session_is_equal(parentP->next->server->sessionH, fromSessionH, contextP->userData))) 00243 { 00244 parentP = parentP->next; 00245 } 00246 if (parentP->next != NULL) 00247 { 00248 targetP = parentP->next; 00249 parentP->next = parentP->next->next; 00250 } 00251 } 00252 if (targetP != NULL) 00253 { 00254 lwm2m_free(targetP); 00255 if (observedP->watcherList == NULL) 00256 { 00257 prv_unlinkObserved(contextP, observedP); 00258 lwm2m_free(observedP); 00259 } 00260 return; 00261 } 00262 } 00263 } 00264 00265 coap_status_t observe_setParameters(lwm2m_context_t * contextP, 00266 lwm2m_uri_t * uriP, 00267 lwm2m_server_t * serverP, 00268 lwm2m_attributes_t * attrP) 00269 { 00270 uint8_t result; 00271 lwm2m_watcher_t * watcherP; 00272 00273 LOG_URI(uriP); 00274 LOG_ARG("toSet: %08X, toClear: %08X, minPeriod: %d, maxPeriod: %d, greaterThan: %f, lessThan: %f, step: %f", 00275 attrP->toSet, attrP->toClear, attrP->minPeriod, attrP->maxPeriod, attrP->greaterThan, attrP->lessThan, attrP->step); 00276 00277 if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; 00278 00279 result = object_checkReadable(contextP, uriP); 00280 if (COAP_205_CONTENT != result) return result; 00281 00282 if (0 != (attrP->toSet & ATTR_FLAG_NUMERIC)) 00283 { 00284 result = object_checkNumeric(contextP, uriP); 00285 if (COAP_205_CONTENT != result) return result; 00286 } 00287 00288 watcherP = prv_getWatcher(contextP, uriP, serverP); 00289 if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; 00290 00291 // Check rule “lt” value + 2*”stp” values < “gt” value 00292 if ((((attrP->toSet | (watcherP->parameters?watcherP->parameters->toSet:0)) & ~attrP->toClear) & ATTR_FLAG_NUMERIC) == ATTR_FLAG_NUMERIC) 00293 { 00294 float gt; 00295 float lt; 00296 float stp; 00297 00298 if (0 != (attrP->toSet & LWM2M_ATTR_FLAG_GREATER_THAN)) 00299 { 00300 gt = attrP->greaterThan; 00301 } 00302 else 00303 { 00304 gt = watcherP->parameters->greaterThan; 00305 } 00306 if (0 != (attrP->toSet & LWM2M_ATTR_FLAG_LESS_THAN)) 00307 { 00308 lt = attrP->lessThan; 00309 } 00310 else 00311 { 00312 lt = watcherP->parameters->lessThan; 00313 } 00314 if (0 != (attrP->toSet & LWM2M_ATTR_FLAG_STEP)) 00315 { 00316 stp = attrP->step; 00317 } 00318 else 00319 { 00320 stp = watcherP->parameters->step; 00321 } 00322 00323 if (lt + (2 * stp) >= gt) return COAP_400_BAD_REQUEST; 00324 } 00325 00326 if (watcherP->parameters == NULL) 00327 { 00328 if (attrP->toSet != 0) 00329 { 00330 watcherP->parameters = (lwm2m_attributes_t *)lwm2m_malloc(sizeof(lwm2m_attributes_t)); 00331 if (watcherP->parameters == NULL) return COAP_500_INTERNAL_SERVER_ERROR; 00332 memcpy(watcherP->parameters, attrP, sizeof(lwm2m_attributes_t)); 00333 } 00334 } 00335 else 00336 { 00337 watcherP->parameters->toSet &= ~attrP->toClear; 00338 if (attrP->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD) 00339 { 00340 watcherP->parameters->minPeriod = attrP->minPeriod; 00341 } 00342 if (attrP->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) 00343 { 00344 watcherP->parameters->maxPeriod = attrP->maxPeriod; 00345 } 00346 if (attrP->toSet & LWM2M_ATTR_FLAG_GREATER_THAN) 00347 { 00348 watcherP->parameters->greaterThan = attrP->greaterThan; 00349 } 00350 if (attrP->toSet & LWM2M_ATTR_FLAG_LESS_THAN) 00351 { 00352 watcherP->parameters->lessThan = attrP->lessThan; 00353 } 00354 if (attrP->toSet & LWM2M_ATTR_FLAG_STEP) 00355 { 00356 watcherP->parameters->step = attrP->step; 00357 } 00358 } 00359 00360 LOG_ARG("Final toSet: %08X, minPeriod: %d, maxPeriod: %d, greaterThan: %f, lessThan: %f, step: %f", 00361 watcherP->parameters->toSet, watcherP->parameters->minPeriod, watcherP->parameters->maxPeriod, watcherP->parameters->greaterThan, watcherP->parameters->lessThan, watcherP->parameters->step); 00362 00363 return COAP_204_CHANGED; 00364 } 00365 00366 lwm2m_observed_t * observe_findByUri(lwm2m_context_t * contextP, 00367 lwm2m_uri_t * uriP) 00368 { 00369 lwm2m_observed_t * targetP; 00370 00371 LOG_URI(uriP); 00372 targetP = contextP->observedList; 00373 while (targetP != NULL) 00374 { 00375 if (targetP->uri.objectId == uriP->objectId) 00376 { 00377 if ((!LWM2M_URI_IS_SET_INSTANCE(uriP) && !LWM2M_URI_IS_SET_INSTANCE(&(targetP->uri))) 00378 || (LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_INSTANCE(&(targetP->uri)) && (uriP->instanceId == targetP->uri.instanceId))) 00379 { 00380 if ((!LWM2M_URI_IS_SET_RESOURCE(uriP) && !LWM2M_URI_IS_SET_RESOURCE(&(targetP->uri))) 00381 || (LWM2M_URI_IS_SET_RESOURCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(&(targetP->uri)) && (uriP->resourceId == targetP->uri.resourceId))) 00382 { 00383 LOG_ARG("Found one with%s observers.", targetP->watcherList ? "" : " no"); 00384 LOG_URI(&(targetP->uri)); 00385 return targetP; 00386 } 00387 } 00388 } 00389 targetP = targetP->next; 00390 } 00391 00392 LOG("Found nothing"); 00393 return NULL; 00394 } 00395 00396 void lwm2m_resource_value_changed(lwm2m_context_t * contextP, 00397 lwm2m_uri_t * uriP) 00398 { 00399 lwm2m_observed_t * targetP; 00400 00401 LOG_URI(uriP); 00402 targetP = contextP->observedList; 00403 while (targetP != NULL) 00404 { 00405 if (targetP->uri.objectId == uriP->objectId) 00406 { 00407 if (!LWM2M_URI_IS_SET_INSTANCE(uriP) 00408 || (targetP->uri.flag & LWM2M_URI_FLAG_INSTANCE_ID) == 0 00409 || uriP->instanceId == targetP->uri.instanceId) 00410 { 00411 if (!LWM2M_URI_IS_SET_RESOURCE(uriP) 00412 || (targetP->uri.flag & LWM2M_URI_FLAG_RESOURCE_ID) == 0 00413 || uriP->resourceId == targetP->uri.resourceId) 00414 { 00415 lwm2m_watcher_t * watcherP; 00416 00417 LOG("Found an observation"); 00418 LOG_URI(&(targetP->uri)); 00419 00420 for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next) 00421 { 00422 if (watcherP->active == true) 00423 { 00424 LOG("Tagging a watcher"); 00425 watcherP->update = true; 00426 } 00427 } 00428 } 00429 } 00430 } 00431 targetP = targetP->next; 00432 } 00433 } 00434 00435 void observe_step(lwm2m_context_t * contextP, 00436 time_t currentTime, 00437 time_t * timeoutP) 00438 { 00439 lwm2m_observed_t * targetP; 00440 00441 LOG("Entering"); 00442 for (targetP = contextP->observedList ; targetP != NULL ; targetP = targetP->next) 00443 { 00444 lwm2m_watcher_t * watcherP; 00445 uint8_t * buffer = NULL; 00446 size_t length = 0; 00447 lwm2m_data_t * dataP = NULL; 00448 int size = 0; 00449 double floatValue = 0; 00450 int64_t integerValue = 0; 00451 bool storeValue = false; 00452 lwm2m_media_type_t format = LWM2M_CONTENT_TEXT; 00453 coap_packet_t message[1]; 00454 time_t interval; 00455 00456 LOG_URI(&(targetP->uri)); 00457 if (LWM2M_URI_IS_SET_RESOURCE(&targetP->uri)) 00458 { 00459 if (COAP_205_CONTENT != object_readData(contextP, &targetP->uri, &size, &dataP)) continue; 00460 switch (dataP->type) 00461 { 00462 case LWM2M_TYPE_INTEGER: 00463 if (1 != lwm2m_data_decode_int(dataP, &integerValue)) continue; 00464 storeValue = true; 00465 break; 00466 case LWM2M_TYPE_FLOAT: 00467 if (1 != lwm2m_data_decode_float(dataP, &floatValue)) continue; 00468 storeValue = true; 00469 break; 00470 default: 00471 break; 00472 } 00473 } 00474 for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next) 00475 { 00476 if (watcherP->active == true) 00477 { 00478 bool notify = false; 00479 00480 if (watcherP->update == true) 00481 { 00482 // value changed, should we notify the server ? 00483 00484 if (watcherP->parameters == NULL || watcherP->parameters->toSet == 0) 00485 { 00486 // no conditions 00487 notify = true; 00488 LOG("Notify with no conditions"); 00489 LOG_URI(&(targetP->uri)); 00490 } 00491 00492 if (notify == false 00493 && watcherP->parameters != NULL 00494 && (watcherP->parameters->toSet & ATTR_FLAG_NUMERIC) != 0) 00495 { 00496 if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_LESS_THAN) != 0) 00497 { 00498 LOG("Checking lower treshold"); 00499 // Did we cross the lower treshold ? 00500 switch (dataP->type) 00501 { 00502 case LWM2M_TYPE_INTEGER: 00503 if ((integerValue <= watcherP->parameters->lessThan 00504 && watcherP->lastValue.asInteger > watcherP->parameters->lessThan) 00505 || (integerValue >= watcherP->parameters->lessThan 00506 && watcherP->lastValue.asInteger < watcherP->parameters->lessThan)) 00507 { 00508 LOG("Notify on lower treshold crossing"); 00509 notify = true; 00510 } 00511 break; 00512 case LWM2M_TYPE_FLOAT: 00513 if ((floatValue <= watcherP->parameters->lessThan 00514 && watcherP->lastValue.asFloat > watcherP->parameters->lessThan) 00515 || (floatValue >= watcherP->parameters->lessThan 00516 && watcherP->lastValue.asFloat < watcherP->parameters->lessThan)) 00517 { 00518 LOG("Notify on lower treshold crossing"); 00519 notify = true; 00520 } 00521 break; 00522 default: 00523 break; 00524 } 00525 } 00526 if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_GREATER_THAN) != 0) 00527 { 00528 LOG("Checking upper treshold"); 00529 // Did we cross the upper treshold ? 00530 switch (dataP->type) 00531 { 00532 case LWM2M_TYPE_INTEGER: 00533 if ((integerValue <= watcherP->parameters->greaterThan 00534 && watcherP->lastValue.asInteger > watcherP->parameters->greaterThan) 00535 || (integerValue >= watcherP->parameters->greaterThan 00536 && watcherP->lastValue.asInteger < watcherP->parameters->greaterThan)) 00537 { 00538 LOG("Notify on lower upper crossing"); 00539 notify = true; 00540 } 00541 break; 00542 case LWM2M_TYPE_FLOAT: 00543 if ((floatValue <= watcherP->parameters->greaterThan 00544 && watcherP->lastValue.asFloat > watcherP->parameters->greaterThan) 00545 || (floatValue >= watcherP->parameters->greaterThan 00546 && watcherP->lastValue.asFloat < watcherP->parameters->greaterThan)) 00547 { 00548 LOG("Notify on lower upper crossing"); 00549 notify = true; 00550 } 00551 break; 00552 default: 00553 break; 00554 } 00555 } 00556 if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_STEP) != 0) 00557 { 00558 LOG("Checking step"); 00559 00560 switch (dataP->type) 00561 { 00562 case LWM2M_TYPE_INTEGER: 00563 { 00564 int64_t diff; 00565 00566 diff = integerValue - watcherP->lastValue.asInteger; 00567 if ((diff < 0 && (0 - diff) >= watcherP->parameters->step) 00568 || (diff >= 0 && diff >= watcherP->parameters->step)) 00569 { 00570 LOG("Notify on step condition"); 00571 notify = true; 00572 } 00573 } 00574 break; 00575 case LWM2M_TYPE_FLOAT: 00576 { 00577 double diff; 00578 00579 diff = floatValue - watcherP->lastValue.asFloat; 00580 if ((diff < 0 && (0 - diff) >= watcherP->parameters->step) 00581 || (diff >= 0 && diff >= watcherP->parameters->step)) 00582 { 00583 LOG("Notify on step condition"); 00584 notify = true; 00585 } 00586 } 00587 break; 00588 default: 00589 break; 00590 } 00591 } 00592 } 00593 00594 if (watcherP->parameters != NULL 00595 && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD) != 0) 00596 { 00597 LOG_ARG("Checking minimal period (%d s)", watcherP->parameters->minPeriod); 00598 00599 if (watcherP->lastTime + watcherP->parameters->minPeriod > currentTime) 00600 { 00601 // Minimum Period did not elapse yet 00602 interval = watcherP->lastTime + watcherP->parameters->minPeriod - currentTime; 00603 if (*timeoutP > interval) *timeoutP = interval; 00604 notify = false; 00605 } 00606 else 00607 { 00608 LOG("Notify on minimal period"); 00609 notify = true; 00610 } 00611 } 00612 } 00613 00614 // Is the Maximum Period reached ? 00615 if (notify == false 00616 && watcherP->parameters != NULL 00617 && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0) 00618 { 00619 LOG_ARG("Checking maximal period (%d s)", watcherP->parameters->minPeriod); 00620 00621 if (watcherP->lastTime + watcherP->parameters->maxPeriod <= currentTime) 00622 { 00623 LOG("Notify on maximal period"); 00624 notify = true; 00625 } 00626 } 00627 00628 if (notify == true) 00629 { 00630 if (buffer == NULL) 00631 { 00632 if (dataP != NULL) 00633 { 00634 int res; 00635 00636 res = lwm2m_data_serialize(&targetP->uri, size, dataP, &format, &buffer); 00637 if (res < 0) 00638 { 00639 break; 00640 } 00641 else 00642 { 00643 length = (size_t)res; 00644 } 00645 00646 } 00647 else 00648 { 00649 if (COAP_205_CONTENT != object_read(contextP, &targetP->uri, &format, &buffer, &length)) 00650 { 00651 buffer = NULL; 00652 break; 00653 } 00654 } 00655 coap_init_message(message, COAP_TYPE_NON, COAP_205_CONTENT, 0); 00656 coap_set_header_content_type(message, format); 00657 coap_set_payload(message, buffer, length); 00658 } 00659 watcherP->lastTime = currentTime; 00660 watcherP->lastMid = contextP->nextMID++; 00661 message->mid = watcherP->lastMid; 00662 coap_set_header_token(message, watcherP->token, watcherP->tokenLen); 00663 coap_set_header_observe(message, watcherP->counter++); 00664 (void)message_send(contextP, message, watcherP->server->sessionH); 00665 watcherP->update = false; 00666 } 00667 00668 // Store this value 00669 if (notify == true && storeValue == true) 00670 { 00671 switch (dataP->type) 00672 { 00673 case LWM2M_TYPE_INTEGER: 00674 watcherP->lastValue.asInteger = integerValue; 00675 break; 00676 case LWM2M_TYPE_FLOAT: 00677 watcherP->lastValue.asFloat = floatValue; 00678 break; 00679 default: 00680 break; 00681 } 00682 } 00683 00684 if (watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0) 00685 { 00686 // update timers 00687 interval = watcherP->lastTime + watcherP->parameters->maxPeriod - currentTime; 00688 if (*timeoutP > interval) *timeoutP = interval; 00689 } 00690 } 00691 } 00692 if (dataP != NULL) lwm2m_data_free(size, dataP); 00693 if (buffer != NULL) lwm2m_free(buffer); 00694 } 00695 } 00696 00697 #endif 00698 00699 #ifdef LWM2M_SERVER_MODE 00700 00701 typedef struct 00702 { 00703 lwm2m_observation_t * observationP; 00704 lwm2m_result_callback_t callbackP; 00705 void * userDataP; 00706 } cancellation_data_t; 00707 00708 static lwm2m_observation_t * prv_findObservationByURI(lwm2m_client_t * clientP, 00709 lwm2m_uri_t * uriP) 00710 { 00711 lwm2m_observation_t * targetP; 00712 00713 targetP = clientP->observationList; 00714 while (targetP != NULL) 00715 { 00716 if (targetP->uri.objectId == uriP->objectId 00717 && targetP->uri.flag == uriP->flag 00718 && targetP->uri.instanceId == uriP->instanceId 00719 && targetP->uri.resourceId == uriP->resourceId) 00720 { 00721 return targetP; 00722 } 00723 00724 targetP = targetP->next; 00725 } 00726 00727 return targetP; 00728 } 00729 00730 void observe_remove(lwm2m_observation_t * observationP) 00731 { 00732 LOG("Entering"); 00733 observationP->clientP->observationList = (lwm2m_observation_t *) LWM2M_LIST_RM(observationP->clientP->observationList, observationP->id, NULL); 00734 lwm2m_free(observationP); 00735 } 00736 00737 static void prv_obsRequestCallback(lwm2m_transaction_t * transacP, 00738 void * message) 00739 { 00740 lwm2m_observation_t * observationP = (lwm2m_observation_t *)transacP->userData; 00741 coap_packet_t * packet = (coap_packet_t *)message; 00742 uint8_t code; 00743 00744 switch (observationP->status) 00745 { 00746 case STATE_DEREG_PENDING: 00747 // Observation was canceled by the user. 00748 observe_remove(observationP); 00749 return; 00750 00751 case STATE_REG_PENDING: 00752 observationP->status = STATE_REGISTERED; 00753 break; 00754 00755 default: 00756 break; 00757 } 00758 00759 if (message == NULL) 00760 { 00761 code = COAP_503_SERVICE_UNAVAILABLE; 00762 } 00763 else if (packet->code == COAP_205_CONTENT 00764 && !IS_OPTION(packet, COAP_OPTION_OBSERVE)) 00765 { 00766 code = COAP_405_METHOD_NOT_ALLOWED; 00767 } 00768 else 00769 { 00770 code = packet->code; 00771 } 00772 00773 if (code != COAP_205_CONTENT) 00774 { 00775 observationP->callback(observationP->clientP->internalID, 00776 &observationP->uri, 00777 code, 00778 LWM2M_CONTENT_TEXT, NULL, 0, 00779 observationP->userData); 00780 observe_remove(observationP); 00781 } 00782 else 00783 { 00784 observationP->callback(observationP->clientP->internalID, 00785 &observationP->uri, 00786 0, 00787 packet->content_type, packet->payload, packet->payload_len, 00788 observationP->userData); 00789 } 00790 } 00791 00792 00793 static void prv_obsCancelRequestCallback(lwm2m_transaction_t * transacP, 00794 void * message) 00795 { 00796 cancellation_data_t * cancelP = (cancellation_data_t *)transacP->userData; 00797 coap_packet_t * packet = (coap_packet_t *)message; 00798 uint8_t code; 00799 00800 if (message == NULL) 00801 { 00802 code = COAP_503_SERVICE_UNAVAILABLE; 00803 } 00804 else 00805 { 00806 code = packet->code; 00807 } 00808 00809 if (code != COAP_205_CONTENT) 00810 { 00811 cancelP->callbackP(cancelP->observationP->clientP->internalID, 00812 &cancelP->observationP->uri, 00813 code, 00814 LWM2M_CONTENT_TEXT, NULL, 0, 00815 cancelP->userDataP); 00816 } 00817 else 00818 { 00819 cancelP->callbackP(cancelP->observationP->clientP->internalID, 00820 &cancelP->observationP->uri, 00821 0, 00822 packet->content_type, packet->payload, packet->payload_len, 00823 cancelP->userDataP); 00824 } 00825 00826 observe_remove(cancelP->observationP); 00827 00828 lwm2m_free(cancelP); 00829 } 00830 00831 00832 int lwm2m_observe(lwm2m_context_t * contextP, 00833 uint16_t clientID, 00834 lwm2m_uri_t * uriP, 00835 lwm2m_result_callback_t callback, 00836 void * userData) 00837 { 00838 lwm2m_client_t * clientP; 00839 lwm2m_transaction_t * transactionP; 00840 lwm2m_observation_t * observationP; 00841 uint8_t token[4]; 00842 00843 LOG_ARG("clientID: %d", clientID); 00844 LOG_URI(uriP); 00845 00846 if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; 00847 00848 clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); 00849 if (clientP == NULL) return COAP_404_NOT_FOUND; 00850 00851 observationP = (lwm2m_observation_t *)lwm2m_malloc(sizeof(lwm2m_observation_t)); 00852 if (observationP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; 00853 memset(observationP, 0, sizeof(lwm2m_observation_t)); 00854 00855 observationP->id = lwm2m_list_newId((lwm2m_list_t *)clientP->observationList); 00856 memcpy(&observationP->uri, uriP, sizeof(lwm2m_uri_t)); 00857 observationP->clientP = clientP; 00858 observationP->status = STATE_REG_PENDING; 00859 observationP->callback = callback; 00860 observationP->userData = userData; 00861 00862 token[0] = clientP->internalID >> 8; 00863 token[1] = clientP->internalID & 0xFF; 00864 token[2] = observationP->id >> 8; 00865 token[3] = observationP->id & 0xFF; 00866 00867 transactionP = transaction_new(clientP->sessionH, COAP_GET, clientP->altPath, uriP, contextP->nextMID++, 4, token); 00868 if (transactionP == NULL) 00869 { 00870 lwm2m_free(observationP); 00871 return COAP_500_INTERNAL_SERVER_ERROR; 00872 } 00873 00874 observationP->clientP->observationList = (lwm2m_observation_t *)LWM2M_LIST_ADD(observationP->clientP->observationList, observationP); 00875 00876 coap_set_header_observe(transactionP->message, 0); 00877 coap_set_header_token(transactionP->message, token, sizeof(token)); 00878 00879 transactionP->callback = prv_obsRequestCallback; 00880 transactionP->userData = (void *)observationP; 00881 00882 contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP); 00883 00884 return transaction_send(contextP, transactionP); 00885 } 00886 00887 int lwm2m_observe_cancel(lwm2m_context_t * contextP, 00888 uint16_t clientID, 00889 lwm2m_uri_t * uriP, 00890 lwm2m_result_callback_t callback, 00891 void * userData) 00892 { 00893 lwm2m_client_t * clientP; 00894 lwm2m_observation_t * observationP; 00895 00896 LOG_ARG("clientID: %d", clientID); 00897 LOG_URI(uriP); 00898 00899 clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); 00900 if (clientP == NULL) return COAP_404_NOT_FOUND; 00901 00902 observationP = prv_findObservationByURI(clientP, uriP); 00903 if (observationP == NULL) return COAP_404_NOT_FOUND; 00904 00905 switch (observationP->status) 00906 { 00907 case STATE_REGISTERED: 00908 { 00909 lwm2m_transaction_t * transactionP; 00910 cancellation_data_t * cancelP; 00911 00912 transactionP = transaction_new(clientP->sessionH, COAP_GET, clientP->altPath, uriP, contextP->nextMID++, 0, NULL); 00913 if (transactionP == NULL) 00914 { 00915 return COAP_500_INTERNAL_SERVER_ERROR; 00916 } 00917 cancelP = (cancellation_data_t *)lwm2m_malloc(sizeof(cancellation_data_t)); 00918 if (cancelP == NULL) 00919 { 00920 lwm2m_free(transactionP); 00921 return COAP_500_INTERNAL_SERVER_ERROR; 00922 } 00923 00924 coap_set_header_observe(transactionP->message, 1); 00925 00926 cancelP->observationP = observationP; 00927 cancelP->callbackP = callback; 00928 cancelP->userDataP = userData; 00929 00930 transactionP->callback = prv_obsCancelRequestCallback; 00931 transactionP->userData = (void *)cancelP; 00932 00933 contextP->transactionList = (lwm2m_transaction_t *)LWM2M_LIST_ADD(contextP->transactionList, transactionP); 00934 00935 return transaction_send(contextP, transactionP); 00936 } 00937 00938 case STATE_REG_PENDING: 00939 observationP->status = STATE_DEREG_PENDING; 00940 break; 00941 00942 default: 00943 // Should not happen 00944 break; 00945 } 00946 00947 return COAP_NO_ERROR; 00948 } 00949 00950 bool observe_handleNotify(lwm2m_context_t * contextP, 00951 void * fromSessionH, 00952 coap_packet_t * message, 00953 coap_packet_t * response) 00954 { 00955 uint8_t * tokenP; 00956 int token_len; 00957 uint16_t clientID; 00958 uint16_t obsID; 00959 lwm2m_client_t * clientP; 00960 lwm2m_observation_t * observationP; 00961 uint32_t count; 00962 00963 LOG("Entering"); 00964 token_len = coap_get_header_token(message, (const uint8_t **)&tokenP); 00965 if (token_len != sizeof(uint32_t)) return false; 00966 00967 if (1 != coap_get_header_observe(message, &count)) return false; 00968 00969 clientID = (tokenP[0] << 8) | tokenP[1]; 00970 obsID = (tokenP[2] << 8) | tokenP[3]; 00971 00972 clientP = (lwm2m_client_t *)lwm2m_list_find((lwm2m_list_t *)contextP->clientList, clientID); 00973 if (clientP == NULL) return false; 00974 00975 observationP = (lwm2m_observation_t *)lwm2m_list_find((lwm2m_list_t *)clientP->observationList, obsID); 00976 if (observationP == NULL) 00977 { 00978 coap_init_message(response, COAP_TYPE_RST, 0, message->mid); 00979 message_send(contextP, response, fromSessionH); 00980 } 00981 else 00982 { 00983 if (message->type == COAP_TYPE_CON ) { 00984 coap_init_message(response, COAP_TYPE_ACK, 0, message->mid); 00985 message_send(contextP, response, fromSessionH); 00986 } 00987 observationP->callback(clientID, 00988 &observationP->uri, 00989 (int)count, 00990 message->content_type, message->payload, message->payload_len, 00991 observationP->userData); 00992 } 00993 return true; 00994 } 00995 #endif
Generated on Sun Jul 17 2022 20:01:04 by
1.7.2