Contiki 3.x
chameleon-bitopt.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007, Swedish Institute of Computer Science.
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 Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  */
31 
32 /**
33  * \file
34  * A Chameleon module that produces bit-optimized headers
35  * \author
36  * Adam Dunkels <adam@sics.se>
37  */
38 
39 #include "net/rime/chameleon.h"
40 
41 #include "net/rime/rime.h"
42 
43 #include <string.h>
44 
45 /* This option enables an optimization where the link addresses are
46  left to the MAC RDC and not encoded in the Chameleon header.
47  Note: this requires that the underlying MAC layer to add link
48  addresses and will not work together with for example nullrdc.
49  */
50 #ifdef CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES
51 #define CHAMELEON_WITH_MAC_LINK_ADDRESSES CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES
52 #else /* !CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES */
53 #define CHAMELEON_WITH_MAC_LINK_ADDRESSES 0
54 #endif /* !CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES */
55 
56 struct bitopt_hdr {
57  uint8_t channel[2];
58 };
59 
60 #define BITOPT_HDR_SIZE 2
61 
62 static const uint8_t bitmask[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,
63  0xf8, 0xfc, 0xfe, 0xff };
64 
65 #define DEBUG 0
66 #if DEBUG
67 #include <stdio.h>
68 #define PRINTF(...) printf(__VA_ARGS__)
69 #else
70 #define PRINTF(...)
71 #endif
72 
73 /*---------------------------------------------------------------------------*/
74 /* For get_bits/set_bits functions in this file to work correctly,
75  * the values contained in packetbuf_attr_t variables (uint16_t internally)
76  * must be in little endian byte order.
77  */
78 /* Write little endian 16 bit value */
79 static void CC_INLINE
80 le16_write(void *ptr, uint16_t v)
81 {
82  uint8_t *p = (uint8_t *)ptr;
83  p[0] = v & 0xff;
84  p[1] = v >> 8;
85 }
86 /*---------------------------------------------------------------------------*/
87 /* Read little endian 16 bit value */
88 static uint16_t CC_INLINE
89 le16_read(const void *ptr)
90 {
91  const uint8_t *p = (const uint8_t *)ptr;
92  return ((uint16_t)p[1] << 8) | p[0];
93 }
94 /*---------------------------------------------------------------------------*/
95 static uint8_t CC_INLINE
96 get_bits_in_byte(uint8_t *from, int bitpos, int vallen)
97 {
98  uint16_t shifted_val;
99 
100  shifted_val = (from[0] << 8) | from[1];
101 
102  /* PRINTF("get_bits_in_byte: from[0] 0x%02x from[1] 0x%02x shifted_val 0x%04x, return 0x%02x vallen %d\n",
103  from[0], from[1], shifted_val,
104  (((shifted_val << bitpos) >> 8) & bitmask[vallen]) >> (8 - vallen),
105  vallen
106  );*/
107 
108  return (((shifted_val << bitpos) >> 8) & bitmask[vallen]) >> (8 - vallen);
109 }
110 /*---------------------------------------------------------------------------*/
111 void
112 get_bits(uint8_t *to, uint8_t *from, int bitpos, int vallen)
113 {
114  int i, bits;
115 
116 
117  if(vallen < 8) {
118  *to = get_bits_in_byte(from, bitpos, vallen);
119  } else {
120  if(bitpos == 0) {
121  for(i = 0; i < vallen / 8; ++i) {
122  /* PRINTF("get_bits i %d val 0x%02x\n",
123  i, from[i]);*/
124  to[i] = from[i];
125  }
126  bits = vallen & 7;
127  if(bits) {
128  to[i] = get_bits_in_byte(&from[i], 0, bits);
129  }
130  } else {
131  for(i = 0; i < vallen / 8; ++i) {
132  /* PRINTF("get_bits i %d val 0x%02x bitpos %d\n",
133  i, from[i], bitpos);*/
134  to[i] = get_bits_in_byte(&from[i], bitpos, 8);
135  }
136  bits = vallen & 7;
137  if(bits) {
138  to[i] = get_bits_in_byte(&from[i], bitpos, bits);
139  }
140  }
141  }
142 }
143 /*---------------------------------------------------------------------------*/
144 static int
145 header_size(const struct packetbuf_attrlist *a)
146 {
147  int size, len;
148 
149  /* Compute the total size of the final header by summing the size of
150  all attributes that are used on this channel. */
151 
152  size = 0;
153  for(; a->type != PACKETBUF_ATTR_NONE; ++a) {
154 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
155  if(a->type == PACKETBUF_ADDR_SENDER ||
156  a->type == PACKETBUF_ADDR_RECEIVER) {
157  /* Let the link layer handle sender and receiver */
158  continue;
159  }
160 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
161  /* PRINTF("chameleon header_size: header type %d len %d\n",
162  a->type, a->len);*/
163  len = a->len;
164  /* if(len < 8) {
165  len = 8;
166  }*/
167  size += len;
168  }
169  return size;
170 }
171 /*---------------------------------------------------------------------------*/
172 void CC_INLINE
173 set_bits_in_byte(uint8_t *target, int bitpos, uint8_t val, int vallen)
174 {
175  unsigned short shifted_val;
176  shifted_val = val << (8 - bitpos + 8 - vallen);
177  /* printf("set_bits_in_byte before target[0] 0x%02x target[1] 0x%02x shifted_val 0x%04x val 0x%02x vallen %d\n",
178  target[0], target[1], shifted_val, val, vallen);*/
179  target[0] |= shifted_val >> 8;
180  target[1] |= shifted_val & 0xff;
181 }
182 /*---------------------------------------------------------------------------*/
183 void
184 set_bits(uint8_t *ptr, int bitpos, uint8_t *val, int vallen)
185 {
186  int i, bits;
187 
188  /* PRINTF("set_bits %p bitpos %d, val %p len %d\n",
189  ptr, bitpos, val, vallen);*/
190 
191  if(vallen < 8) {
192  set_bits_in_byte(ptr, bitpos, *val /*>> (8 - vallen)*/, vallen);
193  } else {
194  if(bitpos == 0) {
195  for(i = 0; i < vallen / 8; ++i) {
196  /* PRINTF("set_bits i %d val %d\n",
197  i, val[i]);*/
198  ptr[i] = val[i];
199  }
200  bits = vallen & 7;
201  if(bits) {
202  set_bits_in_byte(&ptr[i], 0, val[i] >> (8 - bits), bits);
203  }
204  } else {
205  for(i = 0; i < vallen / 8; ++i) {
206  /* PRINTF("set_bits i %d val %d\n",
207  i, val[i]);*/
208  set_bits_in_byte(&ptr[i], bitpos, val[i], 8);
209  }
210  bits = vallen & 7;
211  if(bits) {
212  set_bits_in_byte(&ptr[i], 0, val[i] >> (8 - bits + bitpos), bits);
213  }
214  }
215  }
216 }
217 /*---------------------------------------------------------------------------*/
218 #if 0
219 static void
220 printbin(int n, int digits)
221 {
222  int i;
223  char output[128];
224 
225  for(i = 0; i < digits; ++i) {
226  output[digits - i - 1] = (n & 1) + '0';
227  n >>= 1;
228  }
229  output[i] = 0;
230 
231  printf(output);
232 }
233 
234 static void
235 printhdr(uint8_t *hdr, int len)
236 {
237  int i, j;
238 
239  j = 0;
240  for(i = 0; i < len; ++i) {
241  printbin(hdr[i], 8);
242  printf(", ");
243  ++j;
244  if(j == 10) {
245  printf("\n");
246  j = 0;
247  }
248  }
249 
250  if(j != 0) {
251  printf("\n");
252  }
253 }
254 #endif
255 /*---------------------------------------------------------------------------*/
256 static int
257 pack_header(struct channel *c)
258 {
259  const struct packetbuf_attrlist *a;
260  int hdrbytesize;
261  int byteptr, bitptr, len;
262  uint8_t *hdrptr;
263  struct bitopt_hdr *hdr;
264 
265  /* Compute the total size of the final header by summing the size of
266  all attributes that are used on this channel. */
267 
268  hdrbytesize = c->hdrsize / 8 + ((c->hdrsize & 7) == 0? 0: 1);
269  if(packetbuf_hdralloc(hdrbytesize + BITOPT_HDR_SIZE) == 0) {
270  PRINTF("chameleon-bitopt: insufficient space for headers\n");
271  return 0;
272  }
273  hdr = (struct bitopt_hdr *)packetbuf_hdrptr();
274  hdr->channel[0] = c->channelno & 0xff;
275  hdr->channel[1] = (c->channelno >> 8) & 0xff;
276 
277  hdrptr = ((uint8_t *)packetbuf_hdrptr()) + BITOPT_HDR_SIZE;
278  memset(hdrptr, 0, hdrbytesize);
279 
280  byteptr = bitptr = 0;
281 
282  for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
283 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
284  if(a->type == PACKETBUF_ADDR_SENDER ||
285  a->type == PACKETBUF_ADDR_RECEIVER) {
286  /* Let the link layer handle sender and receiver */
287  PRINTF("%d.%d: pack_header leaving sender/receiver to link layer\n");
288  continue;
289  }
290 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
291  PRINTF("%d.%d: pack_header type %d, len %d, bitptr %d, ",
293  a->type, a->len, bitptr);
294  /* len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);*/
295  len = a->len;
296  byteptr = bitptr / 8;
297  if(PACKETBUF_IS_ADDR(a->type)) {
298  set_bits(&hdrptr[byteptr], bitptr & 7,
299  (uint8_t *)packetbuf_addr(a->type), len);
300  PRINTF("address %d.%d\n",
301  /* linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1],*/
302  ((uint8_t *)packetbuf_addr(a->type))[0],
303  ((uint8_t *)packetbuf_addr(a->type))[1]);
304  } else {
305  uint8_t buffer[2];
306  packetbuf_attr_t val = packetbuf_attr(a->type);
307  le16_write(buffer, val);
308  set_bits(&hdrptr[byteptr], bitptr & 7, buffer, len);
309  PRINTF("value %d\n",
310  /*linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1],*/
311  val);
312  }
313  /* printhdr(hdrptr, hdrbytesize);*/
314  bitptr += len;
315  }
316  /* printhdr(hdrptr, hdrbytesize);*/
317 
318  return 1; /* Send out packet */
319 }
320 /*---------------------------------------------------------------------------*/
321 static struct channel *
322 unpack_header(void)
323 {
324  const struct packetbuf_attrlist *a;
325  int byteptr, bitptr, len;
326  int hdrbytesize;
327  uint8_t *hdrptr;
328  struct bitopt_hdr *hdr;
329  struct channel *c;
330 
331 
332  /* The packet has a header that tells us what channel the packet is
333  for. */
334  hdr = (struct bitopt_hdr *)packetbuf_dataptr();
335  if(packetbuf_hdrreduce(BITOPT_HDR_SIZE) == 0) {
336  PRINTF("chameleon-bitopt: too short packet\n");
337  return NULL;
338  }
339  c = channel_lookup((hdr->channel[1] << 8) + hdr->channel[0]);
340  if(c == NULL) {
341  PRINTF("chameleon-bitopt: input: channel %u not found\n",
342  (hdr->channel[1] << 8) + hdr->channel[0]);
343  return NULL;
344  }
345 
346  hdrptr = packetbuf_dataptr();
347  hdrbytesize = c->hdrsize / 8 + ((c->hdrsize & 7) == 0? 0: 1);
348  if(packetbuf_hdrreduce(hdrbytesize) == 0) {
349  PRINTF("chameleon-bitopt: too short packet\n");
350  return NULL;
351  }
352  byteptr = bitptr = 0;
353  for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
354 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
355  if(a->type == PACKETBUF_ADDR_SENDER ||
356  a->type == PACKETBUF_ADDR_RECEIVER) {
357  /* Let the link layer handle sender and receiver */
358  continue;
359  }
360 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
361  PRINTF("%d.%d: unpack_header type %d, len %d, bitptr %d\n",
363  a->type, a->len, bitptr);
364  /* len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);*/
365  len = a->len;
366  byteptr = bitptr / 8;
367  if(PACKETBUF_IS_ADDR(a->type)) {
368  linkaddr_t addr;
369  get_bits((uint8_t *)&addr, &hdrptr[byteptr], bitptr & 7, len);
370  PRINTF("%d.%d: unpack_header type %d, addr %d.%d\n",
372  a->type, addr.u8[0], addr.u8[1]);
373  packetbuf_set_addr(a->type, &addr);
374  } else {
375  packetbuf_attr_t val;
376  uint8_t buffer[2] = {0};
377  get_bits(buffer, &hdrptr[byteptr], bitptr & 7, len);
378  val = le16_read(buffer);
379  packetbuf_set_attr(a->type, val);
380  PRINTF("%d.%d: unpack_header type %d, val %d\n",
382  a->type, val);
383  }
384  /* byteptr += len / 8;*/
385  bitptr += len;
386  }
387  return c;
388 }
389 /*---------------------------------------------------------------------------*/
390 CC_CONST_FUNCTION struct chameleon_module chameleon_bitopt = {
391  unpack_header,
392  pack_header,
393  header_size
394 };
395 /*---------------------------------------------------------------------------*/
void * packetbuf_dataptr(void)
Get a pointer to the data in the packetbuf.
Definition: packetbuf.c:158
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
Header file for Chameleon, Rime's header processing module
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:164
Header file for the Rime stack
#define NULL
The null pointer.
static uint8_t output(const uip_lladdr_t *localdest)
Take an IP packet and format it to be sent on an 802.15.4 network using 6lowpan.
Definition: sicslowpan.c:1275
int packetbuf_hdralloc(int size)
Extend the header of the packetbuf, for outbound packets.
Definition: packetbuf.c:122
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
int packetbuf_hdrreduce(int size)
Reduce the header in the packetbuf, for incoming packets.
Definition: packetbuf.c:139
#define CC_CONST_FUNCTION
Configure if the C compiler have problems with const function pointers.
Definition: cc.h:77