b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | /******************************************************************************* |
| 2 | * |
| 3 | * Copyright (c) 2013, 2014 Intel Corporation and others. |
| 4 | * All rights reserved. This program and the accompanying materials |
| 5 | * are made available under the terms of the Eclipse Public License v1.0 |
| 6 | * and Eclipse Distribution License v1.0 which accompany this distribution. |
| 7 | * |
| 8 | * The Eclipse Public License is available at |
| 9 | * http://www.eclipse.org/legal/epl-v10.html |
| 10 | * The Eclipse Distribution License is available at |
| 11 | * http://www.eclipse.org/org/documents/edl-v10.php. |
| 12 | * |
| 13 | * Contributors: |
| 14 | * David Navarro, Intel Corporation - initial API and implementation |
| 15 | * domedambrosio - Please refer to git log |
| 16 | * Fabien Fleutot - Please refer to git log |
| 17 | * Axel Lorente - Please refer to git log |
| 18 | * Achim Kraus, Bosch Software Innovations GmbH - Please refer to git log |
| 19 | * Pascal Rieux - Please refer to git log |
| 20 | * |
| 21 | *******************************************************************************/ |
| 22 | |
| 23 | /* |
| 24 | Copyright (c) 2013, 2014 Intel Corporation |
| 25 | |
| 26 | Redistribution and use in source and binary forms, with or without modification, |
| 27 | are permitted provided that the following conditions are met: |
| 28 | |
| 29 | * Redistributions of source code must retain the above copyright notice, |
| 30 | this list of conditions and the following disclaimer. |
| 31 | * Redistributions in binary form must reproduce the above copyright notice, |
| 32 | this list of conditions and the following disclaimer in the documentation |
| 33 | and/or other materials provided with the distribution. |
| 34 | * Neither the name of Intel Corporation nor the names of its contributors |
| 35 | may be used to endorse or promote products derived from this software |
| 36 | without specific prior written permission. |
| 37 | |
| 38 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 39 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 40 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| 41 | IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
| 42 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| 43 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 44 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 45 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| 46 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| 47 | THE POSSIBILITY OF SUCH DAMAGE. |
| 48 | |
| 49 | David Navarro <david.navarro@intel.com> |
| 50 | |
| 51 | */ |
| 52 | |
| 53 | /* |
| 54 | * Implements an object for testing purpose |
| 55 | * |
| 56 | * Multiple |
| 57 | * Object | ID | Instances | Mandatoty | |
| 58 | * Test | 1024 | Yes | No | |
| 59 | * |
| 60 | * Ressources: |
| 61 | * Supported Multiple |
| 62 | * Name | ID | Operations | Instances | Mandatory | Type | Range | Units | Description | |
| 63 | * test | 1 | R/W | No | Yes | Integer | 0-255 | | | |
| 64 | * exec | 2 | E | No | Yes | | | | | |
| 65 | * dec | 3 | R/W | No | Yes | Float | | | | |
| 66 | * |
| 67 | */ |
| 68 | |
| 69 | #include "liblwm2m.h" |
| 70 | |
| 71 | #include <stdio.h> |
| 72 | #include <stdlib.h> |
| 73 | #include <string.h> |
| 74 | #include <ctype.h> |
| 75 | |
| 76 | static void prv_output_buffer(uint8_t * buffer, |
| 77 | int length) |
| 78 | { |
| 79 | int i; |
| 80 | uint8_t array[16]; |
| 81 | |
| 82 | i = 0; |
| 83 | while (i < length) |
| 84 | { |
| 85 | int j; |
| 86 | fprintf(stderr, " "); |
| 87 | |
| 88 | memcpy(array, buffer+i, 16); |
| 89 | |
| 90 | for (j = 0 ; j < 16 && i+j < length; j++) |
| 91 | { |
| 92 | fprintf(stderr, "%02X ", array[j]); |
| 93 | } |
| 94 | while (j < 16) |
| 95 | { |
| 96 | fprintf(stderr, " "); |
| 97 | j++; |
| 98 | } |
| 99 | fprintf(stderr, " "); |
| 100 | for (j = 0 ; j < 16 && i+j < length; j++) |
| 101 | { |
| 102 | if (isprint(array[j])) |
| 103 | fprintf(stderr, "%c ", array[j]); |
| 104 | else |
| 105 | fprintf(stderr, ". "); |
| 106 | } |
| 107 | fprintf(stderr, "\n"); |
| 108 | |
| 109 | i += 16; |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | /* |
| 114 | * Multiple instance objects can use userdata to store data that will be shared between the different instances. |
| 115 | * The lwm2m_object_t object structure - which represent every object of the liblwm2m as seen in the single instance |
| 116 | * object - contain a chained list called instanceList with the object specific structure prv_instance_t: |
| 117 | */ |
| 118 | typedef struct _prv_instance_ |
| 119 | { |
| 120 | /* |
| 121 | * The first two are mandatories and represent the pointer to the next instance and the ID of this one. The rest |
| 122 | * is the instance scope user data (uint8_t test in this case) |
| 123 | */ |
| 124 | struct _prv_instance_ * next; // matches lwm2m_list_t::next |
| 125 | uint16_t shortID; // matches lwm2m_list_t::id |
| 126 | uint8_t test; |
| 127 | double dec; |
| 128 | } prv_instance_t; |
| 129 | |
| 130 | static uint8_t prv_read(uint16_t instanceId, |
| 131 | int * numDataP, |
| 132 | lwm2m_tlv_t ** dataArrayP, |
| 133 | lwm2m_object_t * objectP) |
| 134 | { |
| 135 | prv_instance_t * targetP; |
| 136 | int i; |
| 137 | |
| 138 | targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId); |
| 139 | if (NULL == targetP) return COAP_404_NOT_FOUND; |
| 140 | |
| 141 | if (*numDataP == 0) |
| 142 | { |
| 143 | *dataArrayP = lwm2m_tlv_new(2); |
| 144 | if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR; |
| 145 | *numDataP = 2; |
| 146 | (*dataArrayP)[0].id = 1; |
| 147 | (*dataArrayP)[1].id = 3; |
| 148 | } |
| 149 | |
| 150 | for (i = 0 ; i < *numDataP ; i++) |
| 151 | { |
| 152 | switch ((*dataArrayP)[i].id) |
| 153 | { |
| 154 | case 1: |
| 155 | (*dataArrayP)[i].type = LWM2M_TYPE_RESOURCE; |
| 156 | lwm2m_tlv_encode_int(targetP->test, *dataArrayP + i); |
| 157 | break; |
| 158 | case 2: |
| 159 | return COAP_405_METHOD_NOT_ALLOWED; |
| 160 | case 3: |
| 161 | (*dataArrayP)[i].type = LWM2M_TYPE_RESOURCE; |
| 162 | lwm2m_tlv_encode_float(targetP->dec, *dataArrayP + i); |
| 163 | break; |
| 164 | default: |
| 165 | return COAP_404_NOT_FOUND; |
| 166 | } |
| 167 | if ((*dataArrayP)[i].length == 0) return COAP_500_INTERNAL_SERVER_ERROR; |
| 168 | } |
| 169 | |
| 170 | return COAP_205_CONTENT; |
| 171 | } |
| 172 | |
| 173 | static uint8_t prv_write(uint16_t instanceId, |
| 174 | int numData, |
| 175 | lwm2m_tlv_t * dataArray, |
| 176 | lwm2m_object_t * objectP) |
| 177 | { |
| 178 | prv_instance_t * targetP; |
| 179 | int i; |
| 180 | |
| 181 | targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId); |
| 182 | if (NULL == targetP) return COAP_404_NOT_FOUND; |
| 183 | |
| 184 | for (i = 0 ; i < numData ; i++) |
| 185 | { |
| 186 | switch (dataArray[i].id) |
| 187 | { |
| 188 | case 1: |
| 189 | { |
| 190 | int64_t value; |
| 191 | |
| 192 | if (1 != lwm2m_tlv_decode_int(dataArray + i, &value) || value < 0 || value > 0xFF) |
| 193 | { |
| 194 | return COAP_400_BAD_REQUEST; |
| 195 | } |
| 196 | targetP->test = (uint8_t)value; |
| 197 | } |
| 198 | break; |
| 199 | case 2: |
| 200 | return COAP_405_METHOD_NOT_ALLOWED; |
| 201 | case 3: |
| 202 | if (1 != lwm2m_tlv_decode_float(dataArray + i, &(targetP->dec))) |
| 203 | { |
| 204 | return COAP_400_BAD_REQUEST; |
| 205 | } |
| 206 | break; |
| 207 | default: |
| 208 | return COAP_404_NOT_FOUND; |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | return COAP_204_CHANGED; |
| 213 | } |
| 214 | |
| 215 | static uint8_t prv_delete(uint16_t id, |
| 216 | lwm2m_object_t * objectP) |
| 217 | { |
| 218 | prv_instance_t * targetP; |
| 219 | |
| 220 | objectP->instanceList = lwm2m_list_remove(objectP->instanceList, id, (lwm2m_list_t **)&targetP); |
| 221 | if (NULL == targetP) return COAP_404_NOT_FOUND; |
| 222 | |
| 223 | lwm2m_free(targetP); |
| 224 | |
| 225 | return COAP_202_DELETED; |
| 226 | } |
| 227 | |
| 228 | static uint8_t prv_create(uint16_t instanceId, |
| 229 | int numData, |
| 230 | lwm2m_tlv_t * dataArray, |
| 231 | lwm2m_object_t * objectP) |
| 232 | { |
| 233 | prv_instance_t * targetP; |
| 234 | uint8_t result; |
| 235 | |
| 236 | |
| 237 | targetP = (prv_instance_t *)lwm2m_malloc(sizeof(prv_instance_t)); |
| 238 | if (NULL == targetP) return COAP_500_INTERNAL_SERVER_ERROR; |
| 239 | memset(targetP, 0, sizeof(prv_instance_t)); |
| 240 | |
| 241 | targetP->shortID = instanceId; |
| 242 | objectP->instanceList = LWM2M_LIST_ADD(objectP->instanceList, targetP); |
| 243 | |
| 244 | result = prv_write(instanceId, numData, dataArray, objectP); |
| 245 | |
| 246 | if (result != COAP_204_CHANGED) |
| 247 | { |
| 248 | (void)prv_delete(instanceId, objectP); |
| 249 | } |
| 250 | else |
| 251 | { |
| 252 | result = COAP_201_CREATED; |
| 253 | } |
| 254 | |
| 255 | return result; |
| 256 | } |
| 257 | |
| 258 | static uint8_t prv_exec(uint16_t instanceId, |
| 259 | uint16_t resourceId, |
| 260 | uint8_t * buffer, |
| 261 | int length, |
| 262 | lwm2m_object_t * objectP) |
| 263 | { |
| 264 | |
| 265 | if (NULL == lwm2m_list_find(objectP->instanceList, instanceId)) return COAP_404_NOT_FOUND; |
| 266 | |
| 267 | switch (resourceId) |
| 268 | { |
| 269 | case 1: |
| 270 | return COAP_405_METHOD_NOT_ALLOWED; |
| 271 | case 2: |
| 272 | fprintf(stdout, "\r\n-----------------\r\n" |
| 273 | "Execute on %hu/%d/%d\r\n" |
| 274 | " Parameter (%d bytes):\r\n", |
| 275 | objectP->objID, instanceId, resourceId, length); |
| 276 | prv_output_buffer((uint8_t*)buffer, length); |
| 277 | fprintf(stdout, "-----------------\r\n\r\n"); |
| 278 | return COAP_204_CHANGED; |
| 279 | case 3: |
| 280 | return COAP_405_METHOD_NOT_ALLOWED; |
| 281 | default: |
| 282 | return COAP_404_NOT_FOUND; |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | static void prv_test_close(lwm2m_object_t * object) |
| 287 | { |
| 288 | LWM2M_LIST_FREE(object->instanceList); |
| 289 | if (object->userData != NULL) |
| 290 | { |
| 291 | lwm2m_free(object->userData); |
| 292 | object->userData = NULL; |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | lwm2m_object_t * get_test_object(void) |
| 297 | { |
| 298 | lwm2m_object_t * testObj; |
| 299 | |
| 300 | testObj = (lwm2m_object_t *)lwm2m_malloc(sizeof(lwm2m_object_t)); |
| 301 | |
| 302 | if (NULL != testObj) |
| 303 | { |
| 304 | int i; |
| 305 | prv_instance_t * targetP; |
| 306 | |
| 307 | memset(testObj, 0, sizeof(lwm2m_object_t)); |
| 308 | |
| 309 | testObj->objID = 1024; |
| 310 | for (i=0 ; i < 3 ; i++) |
| 311 | { |
| 312 | targetP = (prv_instance_t *)lwm2m_malloc(sizeof(prv_instance_t)); |
| 313 | if (NULL == targetP) return NULL; |
| 314 | memset(targetP, 0, sizeof(prv_instance_t)); |
| 315 | targetP->shortID = 10 + i; |
| 316 | targetP->test = 20 + i; |
| 317 | targetP->dec = -30 + i + (double)i/100.0; |
| 318 | testObj->instanceList = LWM2M_LIST_ADD(testObj->instanceList, targetP); |
| 319 | } |
| 320 | /* |
| 321 | * From a single instance object, two more functions are available. |
| 322 | * - The first one (createFunc) create a new instance and filled it with the provided informations. If an ID is |
| 323 | * provided a check is done for verifying his disponibility, or a new one is generated. |
| 324 | * - The other one (deleteFunc) delete an instance by removing it from the instance list (and freeing the memory |
| 325 | * allocated to it) |
| 326 | */ |
| 327 | testObj->readFunc = prv_read; |
| 328 | testObj->writeFunc = prv_write; |
| 329 | testObj->executeFunc = prv_exec; |
| 330 | testObj->createFunc = prv_create; |
| 331 | testObj->deleteFunc = prv_delete; |
| 332 | testObj->closeFunc = prv_test_close; |
| 333 | } |
| 334 | |
| 335 | return testObj; |
| 336 | } |