coap_status_t observe_handleRequest(lwm2m_context_t * contextP, lwm2m_uri_t * uriP, lwm2m_server_t * serverP, int size, lwm2m_data_t * dataP, coap_packet_t * message, coap_packet_t * response) { lwm2m_watcher_t * watcherP; uint32_t count; LOG("observe_handleRequest()\r\n"); coap_get_header_observe(message, &count); switch (count) { case 0: if (!LWM2M_URI_IS_SET_INSTANCE(uriP) && LWM2M_URI_IS_SET_RESOURCE(uriP)) return COAP_400_BAD_REQUEST; if (message->token_len == 0) return COAP_400_BAD_REQUEST; watcherP = prv_getWatcher(contextP, uriP, serverP); if (watcherP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; watcherP->tokenLen = message->token_len; memcpy(watcherP->token, message->token, message->token_len); watcherP->active = true; watcherP->lastTime = lwm2m_gettime(); if (LWM2M_URI_IS_SET_RESOURCE(uriP)) { switch (dataP->type) { case LWM2M_TYPE_INTEGER: if (1 != lwm2m_data_decode_int(dataP, &(watcherP->lastValue.asInteger))) return COAP_500_INTERNAL_SERVER_ERROR; break; case LWM2M_TYPE_FLOAT: if (1 != lwm2m_data_decode_float(dataP, &(watcherP->lastValue.asFloat))) return COAP_500_INTERNAL_SERVER_ERROR; break; default: break; } } coap_set_header_observe(response, watcherP->counter++); return COAP_205_CONTENT; case 1: // cancellation observe_cancel(contextP, LWM2M_MAX_ID, serverP->sessionH); return COAP_205_CONTENT; default: return COAP_400_BAD_REQUEST; } }
static uint8_t prv_write(uint16_t instanceId, int numData, lwm2m_data_t * dataArray, lwm2m_object_t * objectP) { prv_instance_t * targetP; int i; targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId); if (NULL == targetP) return COAP_404_NOT_FOUND; for (i = 0 ; i < numData ; i++) { switch (dataArray[i].id) { case 1: { int64_t value; if (1 != lwm2m_data_decode_int(dataArray + i, &value) || value < 0 || value > 0xFF) { return COAP_400_BAD_REQUEST; } targetP->test = (uint8_t)value; } break; case 2: return COAP_405_METHOD_NOT_ALLOWED; case 3: if (1 != lwm2m_data_decode_float(dataArray + i, &(targetP->dec))) { return COAP_400_BAD_REQUEST; } break; case 4: { int64_t value; if (1 != lwm2m_data_decode_int(dataArray + i, &value) || value < INT16_MIN || value > INT16_MAX) { return COAP_400_BAD_REQUEST; } targetP->sig = (int16_t)value; } break; default: return COAP_404_NOT_FOUND; } } return COAP_204_CHANGED; }
void observe_step(lwm2m_context_t * contextP, time_t currentTime, time_t * timeoutP) { lwm2m_observed_t * targetP; for (targetP = contextP->observedList ; targetP != NULL ; targetP = targetP->next) { lwm2m_watcher_t * watcherP; uint8_t * buffer = NULL; size_t length = 0; lwm2m_data_t * dataP = NULL; int size = 0; double floatValue = 0; int64_t integerValue = 0; bool storeValue = false; lwm2m_media_type_t format = LWM2M_CONTENT_TEXT; coap_packet_t message[1]; time_t interval; if (LWM2M_URI_IS_SET_RESOURCE(&targetP->uri)) { if (COAP_205_CONTENT != object_readData(contextP, &targetP->uri, &size, &dataP)) continue; switch (dataP->type) { case LWM2M_TYPE_INTEGER: if (1 != lwm2m_data_decode_int(dataP, &integerValue)) continue; storeValue = true; break; case LWM2M_TYPE_FLOAT: if (1 != lwm2m_data_decode_float(dataP, &floatValue)) continue; storeValue = true; break; default: break; } } for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next) { if (watcherP->active == true) { bool notify = false; if (watcherP->update == true) { // value changed, should we notify the server ? if (watcherP->parameters == NULL || watcherP->parameters->toSet == 0) { // no conditions notify = true; LOG("observation_step(/%d/%d/%d) notify[1] = TRUE\n", targetP->uri.objectId, targetP->uri.instanceId, targetP->uri.resourceId); } if (notify == false && watcherP->parameters != NULL && (watcherP->parameters->toSet & ATTR_FLAG_NUMERIC) != 0) { if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_LESS_THAN) != 0) { // Did we cross the lower treshold ? switch (dataP->type) { case LWM2M_TYPE_INTEGER: if ((integerValue <= watcherP->parameters->lessThan && watcherP->lastValue.asInteger > watcherP->parameters->lessThan) || (integerValue >= watcherP->parameters->lessThan && watcherP->lastValue.asInteger < watcherP->parameters->lessThan)) { notify = true; } break; case LWM2M_TYPE_FLOAT: if ((floatValue <= watcherP->parameters->lessThan && watcherP->lastValue.asFloat > watcherP->parameters->lessThan) || (floatValue >= watcherP->parameters->lessThan && watcherP->lastValue.asFloat < watcherP->parameters->lessThan)) { notify = true; } break; default: break; } LOG("observation_step(/%d/%d/%d) notify[2] = %s\n", targetP->uri.objectId, targetP->uri.instanceId, targetP->uri.resourceId, notify ? "TRUE" : "FALSE"); } if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_GREATER_THAN) != 0) { // Did we cross the upper treshold ? switch (dataP->type) { case LWM2M_TYPE_INTEGER: if ((integerValue <= watcherP->parameters->greaterThan && watcherP->lastValue.asInteger > watcherP->parameters->greaterThan) || (integerValue >= watcherP->parameters->greaterThan && watcherP->lastValue.asInteger < watcherP->parameters->greaterThan)) { notify = true; } break; case LWM2M_TYPE_FLOAT: if ((floatValue <= watcherP->parameters->greaterThan && watcherP->lastValue.asFloat > watcherP->parameters->greaterThan) || (floatValue >= watcherP->parameters->greaterThan && watcherP->lastValue.asFloat < watcherP->parameters->greaterThan)) { notify = true; } break; default: break; } LOG("observation_step(/%d/%d/%d) notify[3] = %s\n", targetP->uri.objectId, targetP->uri.instanceId, targetP->uri.resourceId, notify ? "TRUE" : "FALSE"); } if ((watcherP->parameters->toSet & LWM2M_ATTR_FLAG_STEP) != 0) { switch (dataP->type) { case LWM2M_TYPE_INTEGER: { int64_t diff; diff = integerValue - watcherP->lastValue.asInteger; if ((diff < 0 && (0 - diff) >= watcherP->parameters->step) || (diff >= 0 && diff >= watcherP->parameters->step)) { notify = true; } } break; case LWM2M_TYPE_FLOAT: { double diff; diff = floatValue - watcherP->lastValue.asFloat; if ((diff < 0 && (0 - diff) >= watcherP->parameters->step) || (diff >= 0 && diff >= watcherP->parameters->step)) { notify = true; } } break; default: break; } LOG("observation_step(/%d/%d/%d) notify[4] = %s\n", targetP->uri.objectId, targetP->uri.instanceId, targetP->uri.resourceId, notify? "TRUE" : "FALSE"); } } if (watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MIN_PERIOD) != 0) { if (watcherP->lastTime + watcherP->parameters->minPeriod > currentTime) { // Minimum Period did not elapse yet interval = watcherP->lastTime + watcherP->parameters->minPeriod - currentTime; if (*timeoutP > interval) *timeoutP = interval; notify = false; } else { notify = true; } LOG("observation_step(/%d/%d/%d) notify[5] = %s\n", targetP->uri.objectId, targetP->uri.instanceId, targetP->uri.resourceId, notify ? "TRUE" : "FALSE"); } } // Is the Maximum Period reached ? if (notify == false && watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0) { if (watcherP->lastTime + watcherP->parameters->maxPeriod <= currentTime) { notify = true; } LOG("observation_step(/%d/%d/%d) notify[6] = %s\n", targetP->uri.objectId, targetP->uri.instanceId, targetP->uri.resourceId, notify ? "TRUE" : "FALSE"); } if (notify == true) { if (buffer == NULL) { if (dataP != NULL) { length = lwm2m_data_serialize(&targetP->uri, size, dataP, &format, &buffer); if (length == 0) break; } else { if (COAP_205_CONTENT != object_read(contextP, &targetP->uri, &format, &buffer, &length)) { buffer = NULL; break; } } coap_init_message(message, COAP_TYPE_NON, COAP_205_CONTENT, 0); coap_set_header_content_type(message, format); coap_set_payload(message, buffer, length); LOG("Observe Update[/%d/%d/%d]: %.*s\n", targetP->uri.objectId, targetP->uri.instanceId, targetP->uri.resourceId, length, buffer); } watcherP->lastTime = currentTime; watcherP->lastMid = contextP->nextMID++; message->mid = watcherP->lastMid; coap_set_header_token(message, watcherP->token, watcherP->tokenLen); coap_set_header_observe(message, watcherP->counter++); (void)message_send(contextP, message, watcherP->server->sessionH); watcherP->update = false; } // Store this value if (notify == true && storeValue == true) { switch (dataP->type) { case LWM2M_TYPE_INTEGER: watcherP->lastValue.asInteger = integerValue; break; case LWM2M_TYPE_FLOAT: watcherP->lastValue.asFloat = floatValue; break; default: break; } } if (watcherP->parameters != NULL && (watcherP->parameters->toSet & LWM2M_ATTR_FLAG_MAX_PERIOD) != 0) { // update timers interval = watcherP->lastTime + watcherP->parameters->maxPeriod - currentTime; if (*timeoutP > interval) *timeoutP = interval; } } } if (dataP != NULL) lwm2m_data_free(size, dataP); if (buffer != NULL) lwm2m_free(buffer); } }
static int prv_serializeValue(lwm2m_data_t * tlvP, uint8_t * buffer, size_t bufferLen) { int res; int head; res = lwm2m_snprintf((char *)(char *)buffer, bufferLen, JSON_RES_ITEM_TEMPLATE, tlvP->id); if (res <= 0 || res >= bufferLen) return -1; switch (tlvP->dataType) { case LWM2M_TYPE_STRING: res = lwm2m_snprintf((char *)buffer, bufferLen, JSON_ITEM_STRING_BEGIN); if (res <= 0 || res >= bufferLen) return -1; head = res; if (tlvP->length >= bufferLen - head) return -1; memcpy(buffer + head, tlvP->value, tlvP->length); head += tlvP->length; res = lwm2m_snprintf((char *)buffer + head, bufferLen - head, JSON_ITEM_STRING_END); if (res <= 0 || res >= bufferLen - head) return -1; res += head; break; case LWM2M_TYPE_INTEGER: case LWM2M_TYPE_TIME: { int64_t value; if (0 == lwm2m_data_decode_int(tlvP, &value)) return -1; res = lwm2m_snprintf((char *)buffer, bufferLen, JSON_ITEM_INTEGER_TEMPLATE, value); if (res <= 0 || res >= bufferLen) return -1; } break; case LWM2M_TYPE_FLOAT: { double value; if (0 == lwm2m_data_decode_float(tlvP, &value)) return -1; res = lwm2m_snprintf((char *)buffer, bufferLen, JSON_ITEM_FLOAT_TEMPLATE, value); if (res <= 0 || res >= bufferLen) return -1; } break; case LWM2M_TYPE_BOOLEAN: { bool value; if (0 == lwm2m_data_decode_bool(tlvP, &value)) return -1; res = lwm2m_snprintf((char *)buffer, bufferLen, value?JSON_ITEM_BOOL_TRUE:JSON_ITEM_BOOL_FALSE); if (res <= 0 || res >= bufferLen) return -1; } break; case LWM2M_TYPE_OPAQUE: // TODO: base64 encoding res = lwm2m_snprintf((char *)buffer, bufferLen, JSON_ITEM_STRING_BEGIN); if (res <= 0 || res >= bufferLen) return -1; head = res; if (tlvP->length >= bufferLen - head) return -1; memcpy(buffer + head, tlvP->value, tlvP->length); head += tlvP->length; res = lwm2m_snprintf((char *)buffer + head, bufferLen - head, JSON_ITEM_STRING_END); if (res <= 0 || res >= bufferLen - head) return -1; res += head; break; case LWM2M_TYPE_OBJECT_LINK: // TODO: implement return -1; case LWM2M_TYPE_UNDEFINED: if ((tlvP->flags & LWM2M_TLV_FLAG_TEXT_FORMAT) != 0) { res = lwm2m_snprintf((char *)buffer, bufferLen, JSON_ITEM_STRING_BEGIN); if (res <= 0 || res >= bufferLen) return -1; head = res; if (tlvP->length >= bufferLen - head) return -1; memcpy(buffer + head, tlvP->value, tlvP->length); head += tlvP->length; res = lwm2m_snprintf((char *)buffer + head, bufferLen - head, JSON_ITEM_STRING_END); if (res <= 0 || res >= bufferLen - head) return -1; res += head; } else { return -1; } break; default: break; } return res; }
static int prv_serializeValue(lwm2m_data_t * tlvP, uint8_t * buffer, size_t bufferLen) { int res; int head; switch (tlvP->type) { case LWM2M_TYPE_STRING: if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE); head = JSON_ITEM_STRING_BEGIN_SIZE; if (bufferLen - head < tlvP->value.asBuffer.length) return -1; memcpy(buffer + head, tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length); head += tlvP->value.asBuffer.length; if (bufferLen - head < JSON_ITEM_STRING_END_SIZE) return -1; memcpy(buffer + head, JSON_ITEM_STRING_END, JSON_ITEM_STRING_END_SIZE); head += JSON_ITEM_STRING_END_SIZE; break; case LWM2M_TYPE_INTEGER: { int64_t value; if (0 == lwm2m_data_decode_int(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_intToText(value, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (bufferLen - head < JSON_ITEM_NUM_END_SIZE) return -1; memcpy(buffer + head, JSON_ITEM_NUM_END, JSON_ITEM_NUM_END_SIZE); head += JSON_ITEM_NUM_END_SIZE; } break; case LWM2M_TYPE_FLOAT: { double value; if (0 == lwm2m_data_decode_float(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_floatToText(value, buffer + head, bufferLen - head); if (res <= 0) return -1; head += res; if (bufferLen - head < JSON_ITEM_NUM_END_SIZE) return -1; memcpy(buffer + head, JSON_ITEM_NUM_END, JSON_ITEM_NUM_END_SIZE); head += JSON_ITEM_NUM_END_SIZE; } break; case LWM2M_TYPE_BOOLEAN: { bool value; if (0 == lwm2m_data_decode_bool(tlvP, &value)) return -1; if (value == true) { if (bufferLen < JSON_ITEM_BOOL_TRUE_SIZE) return -1; memcpy(buffer, JSON_ITEM_BOOL_TRUE, JSON_ITEM_BOOL_TRUE_SIZE); head = JSON_ITEM_BOOL_TRUE_SIZE; } else { if (bufferLen < JSON_ITEM_BOOL_FALSE_SIZE) return -1; memcpy(buffer, JSON_ITEM_BOOL_FALSE, JSON_ITEM_BOOL_FALSE_SIZE); head = JSON_ITEM_BOOL_FALSE_SIZE; } } break; case LWM2M_TYPE_OPAQUE: if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE); head = JSON_ITEM_STRING_BEGIN_SIZE; res = utils_base64Encode(tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length, buffer+head, bufferLen - head); if (tlvP->value.asBuffer.length != 0 && res == 0) return -1; head += res; if (bufferLen - head < JSON_ITEM_STRING_END_SIZE) return -1; memcpy(buffer + head, JSON_ITEM_STRING_END, JSON_ITEM_STRING_END_SIZE); head += JSON_ITEM_STRING_END_SIZE; break; case LWM2M_TYPE_OBJECT_LINK: // TODO: implement return -1; default: return -1; } return head; }
static int prv_serializeValue(const lwm2m_data_t * tlvP, uint8_t * buffer, size_t bufferLen) { size_t res; size_t head; switch (tlvP->type) { case LWM2M_TYPE_STRING: case LWM2M_TYPE_CORE_LINK: if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE); head = JSON_ITEM_STRING_BEGIN_SIZE; res = json_escapeString(buffer + head, bufferLen - head, tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length); if (!res) return -1; head += res; if (bufferLen - head < 1) return -1; buffer[head++] = JSON_ITEM_STRING_END; break; case LWM2M_TYPE_INTEGER: { int64_t value; if (0 == lwm2m_data_decode_int(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_intToText(value, buffer + head, bufferLen - head); if (!res) return -1; head += res; } break; case LWM2M_TYPE_UNSIGNED_INTEGER: { uint64_t value; if (0 == lwm2m_data_decode_uint(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_uintToText(value, buffer + head, bufferLen - head); if (!res) return -1; head += res; } break; case LWM2M_TYPE_FLOAT: { double value; if (0 == lwm2m_data_decode_float(tlvP, &value)) return -1; if (bufferLen < JSON_ITEM_NUM_SIZE) return -1; memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE); head = JSON_ITEM_NUM_SIZE; res = utils_floatToText(value, buffer + head, bufferLen - head); if (!res) return -1; head += res; } break; case LWM2M_TYPE_BOOLEAN: { bool value; if (0 == lwm2m_data_decode_bool(tlvP, &value)) return -1; if (value) { if (bufferLen < JSON_ITEM_BOOL_SIZE + JSON_TRUE_STRING_SIZE) return -1; memcpy(buffer, JSON_ITEM_BOOL JSON_TRUE_STRING, JSON_ITEM_BOOL_SIZE + JSON_TRUE_STRING_SIZE); head = JSON_ITEM_BOOL_SIZE + JSON_TRUE_STRING_SIZE; } else { if (bufferLen < JSON_ITEM_BOOL_SIZE + JSON_FALSE_STRING_SIZE) return -1; memcpy(buffer, JSON_ITEM_BOOL JSON_FALSE_STRING, JSON_ITEM_BOOL_SIZE + JSON_FALSE_STRING_SIZE); head = JSON_ITEM_BOOL_SIZE + JSON_FALSE_STRING_SIZE; } } break; case LWM2M_TYPE_OPAQUE: if (bufferLen < JSON_ITEM_OPAQUE_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_OPAQUE_BEGIN, JSON_ITEM_OPAQUE_BEGIN_SIZE); head = JSON_ITEM_OPAQUE_BEGIN_SIZE; if (tlvP->value.asBuffer.length > 0) { res = utils_base64Encode(tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length, buffer+head, bufferLen - head); if (!res) return -1; head += res; } if (bufferLen - head < 1) return -1; buffer[head++] = JSON_ITEM_OPAQUE_END; break; case LWM2M_TYPE_OBJECT_LINK: if (bufferLen < JSON_ITEM_OBJECT_LINK_BEGIN_SIZE) return -1; memcpy(buffer, JSON_ITEM_OBJECT_LINK_BEGIN, JSON_ITEM_OBJECT_LINK_BEGIN_SIZE); head = JSON_ITEM_OBJECT_LINK_BEGIN_SIZE; res = utils_objLinkToText(tlvP->value.asObjLink.objectId, tlvP->value.asObjLink.objectInstanceId, buffer + head, bufferLen - head); if (!res) return -1; head += res; if (bufferLen - head < 1) return -1; buffer[head++] = JSON_ITEM_OBJECT_LINK_END; break; default: return -1; } return (int)head; }