Contiki 2.5
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  * $Id: chameleon-bitopt.c,v 1.9 2010/05/28 06:18:39 nifi Exp $
32  */
33 
34 /**
35  * \file
36  * A Chameleon module that produces bit-optimized headers
37  * \author
38  * Adam Dunkels <adam@sics.se>
39  */
40 
41 #include "net/rime/chameleon.h"
42 
43 #include "net/rime.h"
44 
45 #include <string.h>
46 
47 /* This option enables an optimization where the link addresses are
48  left to the MAC RDC and not encoded in the Chameleon header.
49  Note: this requires that the underlying MAC layer to add link
50  addresses and will not work together with for example nullrdc.
51  */
52 #ifdef CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES
53 #define CHAMELEON_WITH_MAC_LINK_ADDRESSES CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES
54 #else /* !CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES */
55 #define CHAMELEON_WITH_MAC_LINK_ADDRESSES 0
56 #endif /* !CHAMELEON_CONF_WITH_MAC_LINK_ADDRESSES */
57 
58 struct bitopt_hdr {
59  uint8_t channel[2];
60 };
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 uint8_t CC_INLINE
75 get_bits_in_byte(uint8_t *from, int bitpos, int vallen)
76 {
77  uint16_t shifted_val;
78 
79  shifted_val = (from[0] << 8) | from[1];
80 
81  /* PRINTF("get_bits_in_byte: from[0] 0x%02x from[1] 0x%02x shifted_val 0x%04x, return 0x%02x vallen %d\n",
82  from[0], from[1], shifted_val,
83  (((shifted_val << bitpos) >> 8) & bitmask[vallen]) >> (8 - vallen),
84  vallen
85  );*/
86 
87  return (((shifted_val << bitpos) >> 8) & bitmask[vallen]) >> (8 - vallen);
88 }
89 /*---------------------------------------------------------------------------*/
90 void
91 get_bits(uint8_t *to, uint8_t *from, int bitpos, int vallen)
92 {
93  int i, bits;
94 
95 
96  if(vallen < 8) {
97  *to = get_bits_in_byte(from, bitpos, vallen);
98  } else {
99  if(bitpos == 0) {
100  for(i = 0; i < vallen / 8; ++i) {
101  /* PRINTF("get_bits i %d val 0x%02x\n",
102  i, from[i]);*/
103  to[i] = from[i];
104  }
105  bits = vallen & 7;
106  if(bits) {
107  to[i] = get_bits_in_byte(&from[i], 0, bits);
108  }
109  } else {
110  for(i = 0; i < vallen / 8; ++i) {
111  /* PRINTF("get_bits i %d val 0x%02x bitpos %d\n",
112  i, from[i], bitpos);*/
113  to[i] = get_bits_in_byte(&from[i], bitpos, 8);
114  }
115  bits = vallen & 7;
116  if(bits) {
117  to[i] = get_bits_in_byte(&from[i], bitpos, bits);
118  }
119  }
120  }
121 }
122 /*---------------------------------------------------------------------------*/
123 static int
124 header_size(const struct packetbuf_attrlist *a)
125 {
126  int size, len;
127 
128  /* Compute the total size of the final header by summing the size of
129  all attributes that are used on this channel. */
130 
131  size = 0;
132  for(; a->type != PACKETBUF_ATTR_NONE; ++a) {
133 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
134  if(a->type == PACKETBUF_ADDR_SENDER ||
135  a->type == PACKETBUF_ADDR_RECEIVER) {
136  /* Let the link layer handle sender and receiver */
137  continue;
138  }
139 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
140  /* PRINTF("chameleon header_size: header type %s (%d) len %d\n",
141  packetbuf_attr_strings[a->type],
142  a->type,
143  a->len);*/
144  len = a->len;
145  /* if(len < 8) {
146  len = 8;
147  }*/
148  size += len;
149  }
150  return size;
151 }
152 /*---------------------------------------------------------------------------*/
153 void CC_INLINE
154 set_bits_in_byte(uint8_t *target, int bitpos, uint8_t val, int vallen)
155 {
156  unsigned short shifted_val;
157  shifted_val = val << (8 - bitpos + 8 - vallen);
158  /* printf("set_bits_in_byte before target[0] 0x%02x target[1] 0x%02x shifted_val 0x%04x val 0x%02x vallen %d\n",
159  target[0], target[1], shifted_val, val, vallen);*/
160  target[0] |= shifted_val >> 8;
161  target[1] |= shifted_val & 0xff;
162 }
163 /*---------------------------------------------------------------------------*/
164 void
165 set_bits(uint8_t *ptr, int bitpos, uint8_t *val, int vallen)
166 {
167  int i, bits;
168 
169  /* PRINTF("set_bits %p bitpos %d, val %p len %d\n",
170  ptr, bitpos, val, vallen);*/
171 
172  if(vallen < 8) {
173  set_bits_in_byte(ptr, bitpos, *val /*>> (8 - vallen)*/, vallen);
174  } else {
175  if(bitpos == 0) {
176  for(i = 0; i < vallen / 8; ++i) {
177  /* PRINTF("set_bits i %d val %d\n",
178  i, val[i]);*/
179  ptr[i] = val[i];
180  }
181  bits = vallen & 7;
182  if(bits) {
183  set_bits_in_byte(&ptr[i], 0, val[i] >> (8 - bits), bits);
184  }
185  } else {
186  for(i = 0; i < vallen / 8; ++i) {
187  /* PRINTF("set_bits i %d val %d\n",
188  i, val[i]);*/
189  set_bits_in_byte(&ptr[i], bitpos, val[i], 8);
190  }
191  bits = vallen & 7;
192  if(bits) {
193  set_bits_in_byte(&ptr[i], 0, val[i] >> (8 - bits + bitpos), bits);
194  }
195  }
196  }
197 }
198 /*---------------------------------------------------------------------------*/
199 #if 0
200 static void
201 printbin(int n, int digits)
202 {
203  int i;
204  char output[128];
205 
206  for(i = 0; i < digits; ++i) {
207  output[digits - i - 1] = (n & 1) + '0';
208  n >>= 1;
209  }
210  output[i] = 0;
211 
212  printf(output);
213 }
214 
215 static void
216 printhdr(uint8_t *hdr, int len)
217 {
218  int i, j;
219 
220  j = 0;
221  for(i = 0; i < len; ++i) {
222  printbin(hdr[i], 8);
223  printf(", ");
224  ++j;
225  if(j == 10) {
226  printf("\n");
227  j = 0;
228  }
229  }
230 
231  if(j != 0) {
232  printf("\n");
233  }
234 }
235 #endif
236 /*---------------------------------------------------------------------------*/
237 static int
238 pack_header(struct channel *c)
239 {
240  const struct packetbuf_attrlist *a;
241  int hdrbytesize;
242  int byteptr, bitptr, len;
243  uint8_t *hdrptr;
244  struct bitopt_hdr *hdr;
245 
246  /* Compute the total size of the final header by summing the size of
247  all attributes that are used on this channel. */
248 
249  hdrbytesize = c->hdrsize / 8 + ((c->hdrsize & 7) == 0? 0: 1);
250  if(packetbuf_hdralloc(hdrbytesize + sizeof(struct bitopt_hdr)) == 0) {
251  PRINTF("chameleon-bitopt: insufficient space for headers\n");
252  return 0;
253  }
254  hdr = (struct bitopt_hdr *)packetbuf_hdrptr();
255  hdr->channel[0] = c->channelno & 0xff;
256  hdr->channel[1] = (c->channelno >> 8) & 0xff;
257 
258  hdrptr = ((uint8_t *)packetbuf_hdrptr()) + sizeof(struct bitopt_hdr);
259  memset(hdrptr, 0, hdrbytesize);
260 
261  byteptr = bitptr = 0;
262 
263  for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
264 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
265  if(a->type == PACKETBUF_ADDR_SENDER ||
266  a->type == PACKETBUF_ADDR_RECEIVER) {
267  /* Let the link layer handle sender and receiver */
268  PRINTF("%d.%d: pack_header leaving sender/receiver to link layer\n");
269  continue;
270  }
271 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
272  PRINTF("%d.%d: pack_header type %s, len %d, bitptr %d, ",
274  packetbuf_attr_strings[a->type], a->len, bitptr);
275  /* len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);*/
276  len = a->len;
277  byteptr = bitptr / 8;
278  if(PACKETBUF_IS_ADDR(a->type)) {
279  set_bits(&hdrptr[byteptr], bitptr & 7,
280  (uint8_t *)packetbuf_addr(a->type), len);
281  PRINTF("address %d.%d\n",
282  /* rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],*/
283  ((uint8_t *)packetbuf_addr(a->type))[0],
284  ((uint8_t *)packetbuf_addr(a->type))[1]);
285  } else {
286  packetbuf_attr_t val;
287  val = packetbuf_attr(a->type);
288  set_bits(&hdrptr[byteptr], bitptr & 7,
289  (uint8_t *)&val, len);
290  PRINTF("value %d\n",
291  /*rimeaddr_node_addr.u8[0], rimeaddr_node_addr.u8[1],*/
292  val);
293  }
294  /* printhdr(hdrptr, hdrbytesize);*/
295  bitptr += len;
296  }
297  /* printhdr(hdrptr, hdrbytesize);*/
298 
299  return 1; /* Send out packet */
300 }
301 /*---------------------------------------------------------------------------*/
302 static struct channel *
303 unpack_header(void)
304 {
305  const struct packetbuf_attrlist *a;
306  int byteptr, bitptr, len;
307  int hdrbytesize;
308  uint8_t *hdrptr;
309  struct bitopt_hdr *hdr;
310  struct channel *c;
311 
312 
313  /* The packet has a header that tells us what channel the packet is
314  for. */
315  hdr = (struct bitopt_hdr *)packetbuf_dataptr();
316  if(packetbuf_hdrreduce(sizeof(struct bitopt_hdr)) == 0) {
317  PRINTF("chameleon-bitopt: too short packet\n");
318  return NULL;
319  }
320  c = channel_lookup((hdr->channel[1] << 8) + hdr->channel[0]);
321  if(c == NULL) {
322  PRINTF("chameleon-bitopt: input: channel %u not found\n",
323  (hdr->channel[1] << 8) + hdr->channel[0]);
324  return NULL;
325  }
326 
327  hdrptr = packetbuf_dataptr();
328  hdrbytesize = c->hdrsize / 8 + ((c->hdrsize & 7) == 0? 0: 1);
329  if(packetbuf_hdrreduce(hdrbytesize) == 0) {
330  PRINTF("chameleon-bitopt: too short packet\n");
331  return NULL;
332  }
333  byteptr = bitptr = 0;
334  for(a = c->attrlist; a->type != PACKETBUF_ATTR_NONE; ++a) {
335 #if CHAMELEON_WITH_MAC_LINK_ADDRESSES
336  if(a->type == PACKETBUF_ADDR_SENDER ||
337  a->type == PACKETBUF_ADDR_RECEIVER) {
338  /* Let the link layer handle sender and receiver */
339  continue;
340  }
341 #endif /* CHAMELEON_WITH_MAC_LINK_ADDRESSES */
342  PRINTF("%d.%d: unpack_header type %s, len %d, bitptr %d\n",
344  packetbuf_attr_strings[a->type], a->len, bitptr);
345  /* len = (a->len & 0xf8) + ((a->len & 7) ? 8: 0);*/
346  len = a->len;
347  byteptr = bitptr / 8;
348  if(PACKETBUF_IS_ADDR(a->type)) {
349  rimeaddr_t addr;
350  get_bits((uint8_t *)&addr, &hdrptr[byteptr], bitptr & 7, len);
351  PRINTF("%d.%d: unpack_header type %s, addr %d.%d\n",
353  packetbuf_attr_strings[a->type],
354  addr.u8[0], addr.u8[1]);
355  packetbuf_set_addr(a->type, &addr);
356  } else {
357  packetbuf_attr_t val = 0;
358  get_bits((uint8_t *)&val, &hdrptr[byteptr], bitptr & 7, len);
359 
360  packetbuf_set_attr(a->type, val);
361  PRINTF("%d.%d: unpack_header type %s, val %d\n",
363  packetbuf_attr_strings[a->type],
364  val);
365  }
366  /* byteptr += len / 8;*/
367  bitptr += len;
368  }
369  return c;
370 }
371 /*---------------------------------------------------------------------------*/
372 CC_CONST_FUNCTION struct chameleon_module chameleon_bitopt = {
373  unpack_header,
374  pack_header,
375  header_size
376 };
377 /*---------------------------------------------------------------------------*/