Contiki 3.x
oma-tlv.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, Yanzi Networks AB.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /**
32  * \addtogroup oma-lwm2m
33  * @{
34  *
35  */
36 
37 /**
38  * \file
39  * Implementation of the Contiki OMA LWM2M TLV
40  * \author
41  * Joakim Eriksson <joakime@sics.se>
42  * Niclas Finne <nfi@sics.se>
43  */
44 
45 #include <string.h>
46 #include <stdint.h>
47 #include "oma-tlv.h"
48 
49 #define DEBUG 0
50 #if DEBUG
51 #include <stdio.h>
52 #define PRINTF(...) printf(__VA_ARGS__)
53 #else
54 #define PRINTF(...)
55 #endif
56 
57 /*---------------------------------------------------------------------------*/
58 static inline uint8_t
59 get_len_type(const oma_tlv_t *tlv)
60 {
61  if(tlv->length < 8) {
62  return 0;
63  } else if(tlv->length < 256) {
64  return 1;
65  } else if(tlv->length < 0x10000) {
66  return 2;
67  } else {
68  return 3;
69  }
70 }
71 /*---------------------------------------------------------------------------*/
72 size_t
73 oma_tlv_read(oma_tlv_t *tlv, const uint8_t *buffer, size_t len)
74 {
75  uint8_t len_type;
76  uint8_t len_pos = 1;
77  size_t tlv_len;
78 
79  tlv->type = (buffer[0] >> 6) & 3;
80  len_type = (buffer[0] >> 3) & 3;
81  len_pos = 1 + (((buffer[0] & (1 << 5)) != 0) ? 2 : 1);
82 
83  tlv->id = buffer[1];
84  /* if len_pos is larger than two it means that there is more ID to read */
85  if(len_pos > 2) {
86  tlv->id = (tlv->id << 8) + buffer[2];
87  }
88 
89  if(len_type == 0) {
90  tlv_len = buffer[0] & 7;
91  } else {
92  /* read the length */
93  tlv_len = 0;
94  while(len_type > 0) {
95  tlv_len = tlv_len << 8 | buffer[len_pos++];
96  len_type--;
97  }
98  }
99  /* and read out the data??? */
100  tlv->length = tlv_len;
101  tlv->value = &buffer[len_pos];
102 
103  return len_pos + tlv_len;
104 }
105 /*---------------------------------------------------------------------------*/
106 size_t
107 oma_tlv_get_size(const oma_tlv_t *tlv)
108 {
109  size_t size;
110  /* first hdr + len size */
111  size = 1 + get_len_type(tlv);
112  /* id size */
113  size += (tlv->id > 255) ? 2 : 1;
114 
115  /* and the length */
116  size += tlv->length;
117  return size;
118 }
119 /*---------------------------------------------------------------------------*/
120 size_t
121 oma_tlv_write(const oma_tlv_t *tlv, uint8_t *buffer, size_t len)
122 {
123  int pos;
124  uint8_t len_type;
125 
126  /* len type is the same as number of bytes required for length */
127  len_type = get_len_type(tlv);
128  pos = 1 + len_type;
129  /* ensure that we do not write too much */
130  if(len < tlv->length + pos) {
131  PRINTF("OMA-TLV: Could not write the TLV - buffer overflow.\n");
132  return 0;
133  }
134 
135  /* first type byte in TLV header */
136  buffer[0] = (tlv->type << 6) |
137  (tlv->id > 255 ? (1 << 5) : 0) |
138  (len_type << 3) |
139  (len_type == 0 ? tlv->length : 0);
140 
141  pos = 1;
142  /* The ID */
143  if(tlv->id > 255) {
144  buffer[pos++] = (tlv->id >> 8) & 0xff;
145  }
146  buffer[pos++] = tlv->id & 0xff;
147  /* Add length if needed - unrolled loop ? */
148  if(len_type > 2) {
149  buffer[pos++] = (tlv->length >> 16) & 0xff;
150  }
151  if(len_type > 1) {
152  buffer[pos++] = (tlv->length >> 8) & 0xff;
153  }
154  if(len_type > 0) {
155  buffer[pos++] = tlv->length & 0xff;
156  }
157 
158  /* finally add the value */
159  memcpy(&buffer[pos], tlv->value, tlv->length);
160 
161  if(DEBUG) {
162  int i;
163  PRINTF("TLV:");
164  for(i = 0; i < pos + tlv->length; i++) {
165  PRINTF("%02x", buffer[i]);
166  }
167  PRINTF("\n");
168  }
169 
170  return pos + tlv->length;
171 }
172 /*---------------------------------------------------------------------------*/
173 int32_t
174 oma_tlv_get_int32(const oma_tlv_t *tlv)
175 {
176  int i;
177  int32_t value = 0;
178  /* will probably need to handle MSB as a sign bit? */
179  for(i = 0; i < tlv->length; i++) {
180  value = (value << 8) | tlv->value[i];
181  }
182  return value;
183 }
184 /*---------------------------------------------------------------------------*/
185 size_t
186 oma_tlv_write_int32(int16_t id, int32_t value, uint8_t *buffer, size_t len)
187 {
188  oma_tlv_t tlv;
189  size_t tlvlen = 0;
190  uint8_t buf[4];
191  int i;
192  PRINTF("Exporting int32 %d %ld ", id, (long)value);
193 
194  buf[3] = value & 0xff;
195  value = value >> 8;
196  for(i = 1; value > 0 && i < 4; i++) {
197  buf[3 - i] = value & 0xff;
198  value = value >> 8;
199  }
200  tlvlen = i;
201 
202  /* export INT as TLV */
203  PRINTF("len: %zu\n", tlvlen);
204  tlv.type = OMA_TLV_TYPE_RESOURCE;
205  tlv.length = tlvlen;
206  tlv.value = &buf[3 - (tlvlen - 1)];
207  tlv.id = id;
208  return oma_tlv_write(&tlv, buffer, len);
209 }
210 /*---------------------------------------------------------------------------*/
211 /* convert fixpoint 32-bit to a IEEE Float in the byte array*/
212 size_t
213 oma_tlv_write_float32(int16_t id, int32_t value, int bits,
214  uint8_t *buffer, size_t len)
215 {
216  int i;
217  int e = 0;
218  int32_t val = 0;
219  int32_t v;
220  uint8_t b[4];
221  oma_tlv_t tlv;
222 
223  v = value;
224  if(v < 0) {
225  v = -v;
226  }
227 
228  while(v > 1) {
229  val = (val >> 1);
230  if (v & 1) {
231  val = val | (1L << 22);
232  }
233  v = (v >> 1);
234  e++;
235  }
236 
237  PRINTF("Sign: %d, Fraction: %06lx 0b", value < 0, (long)val);
238  for(i = 0; i < 23; i++) {
239  PRINTF("%d", (int)((val >> (22 - i)) & 1));
240  }
241  PRINTF("\nExp:%d\n", e);
242 
243  /* convert to the thing we should have */
244  e = e - bits + 127;
245 
246  /* is this the right byte order? */
247  b[0] = (value < 0 ? 0x80 : 0) | (e >> 1);
248  b[1] = ((e & 1) << 7) | ((val >> 16) & 0x7f);
249  b[2] = (val >> 8) & 0xff;
250  b[3] = val & 0xff;
251 
252  /* construct the TLV */
253  tlv.type = OMA_TLV_TYPE_RESOURCE;
254  tlv.length = 4;
255  tlv.value = b;
256  tlv.id = id;
257 
258  return oma_tlv_write(&tlv, buffer, len);
259 }
260 /*---------------------------------------------------------------------------*/
261 /* convert float to fixpoint */
262 size_t
263 oma_tlv_float32_to_fix(const oma_tlv_t *tlv, int32_t *value, int bits)
264 {
265  /* TLV needs to be 4 bytes */
266  int e, i;
267  int32_t val;
268  int sign = (tlv->value[0] & 0x80) != 0;
269  e = ((tlv->value[0] << 1) & 0xff) | (tlv->value[1] >> 7);
270  val = (((long)tlv->value[1] & 0x7f) << 16) | (tlv->value[2] << 8) | tlv->value[3];
271 
272  PRINTF("Sign: %d, Fraction: %06lx 0b", val < 0, (long)val);
273  for(i = 0; i < 23; i++) {
274  PRINTF("%d", (int)((val >> (22 - i)) & 1));
275  }
276  PRINTF("\nExp:%d => %d\n", e, e - 127);
277 
278  e = e - 127 + bits;
279 
280  /* e corresponds to the number of times we need to roll the number */
281 
282  PRINTF("Actual e=%d\n", e);
283  e = e - 23;
284  PRINTF("E after sub %d\n", e);
285  val = val | 1L << 23;
286  if(e > 0) {
287  val = val << e;
288  } else {
289  val = val >> -e;
290  }
291 
292  *value = sign ? -val : val;
293  return 4;
294 }
295 /*---------------------------------------------------------------------------*/
296 /** @} */
Header file for the Contiki OMA LWM2M TLV